From 2bc950b41a13fad70b31c1b12bd112a76699ac36 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 14:50:46 +0300 Subject: [PATCH 001/689] Add yamlWitnessStrip testing utility --- src/witness/yamlWitnessType.ml | 9 +++++++ tests/util/dune | 4 +++ tests/util/yamlWitnessStrip.ml | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tests/util/dune create mode 100644 tests/util/yamlWitnessStrip.ml diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index a4f80bab02..920cd89eaf 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -105,6 +105,7 @@ struct column: int; function_: string; } + [@@deriving ord] let to_yaml {file_name; file_hash; line; column; function_} = `O [ @@ -132,6 +133,7 @@ struct type_: string; format: string; } + [@@deriving ord] let to_yaml {string; type_; format} = `O [ @@ -154,6 +156,7 @@ struct location: Location.t; loop_invariant: Invariant.t; } + [@@deriving ord] let entry_type = "loop_invariant" @@ -175,6 +178,7 @@ struct type t = { flow_insensitive_invariant: Invariant.t; } + [@@deriving ord] let entry_type = "flow_insensitive_invariant" @@ -196,6 +200,7 @@ struct loop_invariant: Invariant.t; precondition: Invariant.t; } + [@@deriving ord] let entry_type = "precondition_loop_invariant" @@ -221,6 +226,7 @@ struct type_: string; file_hash: string; } + [@@deriving ord] let to_yaml {uuid; type_; file_hash} = `O [ @@ -244,6 +250,7 @@ struct type_: string; format: string; } + [@@deriving ord] let to_yaml {string; type_; format} = `O [ @@ -266,6 +273,7 @@ struct target: Target.t; certification: Certification.t; } + [@@deriving ord] let entry_type = "loop_invariant_certificate" @@ -297,6 +305,7 @@ struct | PreconditionLoopInvariant of PreconditionLoopInvariant.t | LoopInvariantCertificate of LoopInvariantCertificate.t | PreconditionLoopInvariantCertificate of PreconditionLoopInvariantCertificate.t + [@@deriving ord] let entry_type = function | LoopInvariant _ -> LoopInvariant.entry_type diff --git a/tests/util/dune b/tests/util/dune new file mode 100644 index 0000000000..0f5f54d2b5 --- /dev/null +++ b/tests/util/dune @@ -0,0 +1,4 @@ +(executable + (name yamlWitnessStrip) + (libraries goblint_lib goblint.sites.dune batteries.unthreaded) + (preprocess (pps ppx_deriving.std))) diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml new file mode 100644 index 0000000000..0945fb3bc6 --- /dev/null +++ b/tests/util/yamlWitnessStrip.ml @@ -0,0 +1,46 @@ +open Goblint_lib +open YamlWitnessType + +module StrippedEntry = +struct + type t = { + entry_type: EntryType.t; + } + [@@deriving ord] + + let to_yaml {entry_type} = + `O ([ + ("entry_type", `String (EntryType.entry_type entry_type)); + ] @ EntryType.to_yaml' entry_type) +end + +(* Use set for output, so order is deterministic regardless of Goblint. *) +module StrippedEntrySet = Set.Make (StrippedEntry) + +let main () = + let yaml_str = Batteries.input_all stdin in + let yaml = Yaml.of_string_exn yaml_str in + let yaml_entries = yaml |> GobYaml.list |> BatResult.get_ok in + + let entries' = List.fold_left (fun entries' yaml_entry -> + match YamlWitnessType.Entry.of_yaml yaml_entry with + | Ok {entry_type; _} -> + let stripped_entry: StrippedEntry.t = {entry_type} in + StrippedEntrySet.add stripped_entry entries' + | Error (`Msg e) -> + Format.eprintf "couldn't parse entry: %s" e; + entries' + ) StrippedEntrySet.empty yaml_entries + in + let yaml_entries' = + StrippedEntrySet.elements entries' + |> List.map StrippedEntry.to_yaml + in + + let yaml' = `A (List.rev yaml_entries') in + (* to_file/to_string uses a fixed-size buffer... *) + (* estimate how big it should be + extra in case empty *) + let text = Yaml.to_string_exn ~len:(List.length yaml_entries * 2048 + 2048) yaml' in + Batteries.output_string Batteries.stdout text + +let () = main () From 74477a4cea36845a37f98a47708f67b267652a55 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 14:51:14 +0300 Subject: [PATCH 002/689] Add cram witness test to 56-witness/05-prec-problem --- tests/regression/56-witness/05-prec-problem.c | 2 +- tests/regression/56-witness/05-prec-problem.t | 157 ++++++++++++++++++ tests/regression/56-witness/dune | 6 + 3 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 tests/regression/56-witness/05-prec-problem.t create mode 100644 tests/regression/56-witness/dune diff --git a/tests/regression/56-witness/05-prec-problem.c b/tests/regression/56-witness/05-prec-problem.c index 6bbc8b09d3..120c211780 100644 --- a/tests/regression/56-witness/05-prec-problem.c +++ b/tests/regression/56-witness/05-prec-problem.c @@ -1,4 +1,4 @@ -//PARAM: --enable witness.yaml.enabled --enable ana.int.interval +//PARAM: --enable ana.int.interval #include int foo(int* ptr1, int* ptr2){ diff --git a/tests/regression/56-witness/05-prec-problem.t b/tests/regression/56-witness/05-prec-problem.t new file mode 100644 index 0000000000..2387cf00e3 --- /dev/null +++ b/tests/regression/56-witness/05-prec-problem.t @@ -0,0 +1,157 @@ + $ goblint --enable witness.yaml.enabled --enable ana.int.interval 05-prec-problem.c + [Success][Assert] Assertion "y != z" will succeed (05-prec-problem.c:20:5-20:28) + Live lines: 12 + No lines with dead code found by solver. + Total lines (logical LoC): 12 + [Info][Witness] witness generation summary: + total: 15 + +Witness shouldn't contain two unsound precondition_loop_invariant-s with precondition `*ptr1 == 5 && *ptr2 == 5`, +and separately invariants `result == 0` and `result == 1`. +The sound invariant is `result == 1 || result == 0`. + + $ yamlWitnessStrip < witness.yml + - entry_type: precondition_loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 12 + column: 4 + function: foo + loop_invariant: + string: result == 1 || result == 0 + type: assertion + format: C + precondition: + string: '*ptr1 == 5 && *ptr2 == 5' + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 6 + column: 7 + function: foo + loop_invariant: + string: '*ptr2 == 5' + type: assertion + format: C + precondition: + string: '*ptr1 == 5 && *ptr2 == 5' + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 6 + column: 7 + function: foo + loop_invariant: + string: '*ptr1 == 5' + type: assertion + format: C + precondition: + string: '*ptr1 == 5 && *ptr2 == 5' + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 20 + column: 4 + function: main + loop_invariant: + string: z == 1 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 20 + column: 4 + function: main + loop_invariant: + string: y == 0 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 19 + column: 8 + function: main + loop_invariant: + string: y == 0 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 18 + column: 8 + function: main + loop_invariant: + string: five2 == 5 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 17 + column: 8 + function: main + loop_invariant: + string: five == 5 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 12 + column: 4 + function: foo + loop_invariant: + string: result <= 1 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 12 + column: 4 + function: foo + loop_invariant: + string: 0 <= result + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 6 + column: 7 + function: foo + loop_invariant: + string: '*ptr2 == 5 || *ptr2 == 5' + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 05-prec-problem.c + file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + line: 6 + column: 7 + function: foo + loop_invariant: + string: '*ptr1 == 5' + type: assertion + format: C diff --git a/tests/regression/56-witness/dune b/tests/regression/56-witness/dune new file mode 100644 index 0000000000..05fce8ddec --- /dev/null +++ b/tests/regression/56-witness/dune @@ -0,0 +1,6 @@ +(env + (_ + (binaries ../../util/yamlWitnessStrip.exe))) + +(cram + (deps (glob_files *.c) %{bin:yamlWitnessStrip})) From d8b0c1efee3246376cd1355f20dc5a8c1d29e46c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 15:10:49 +0300 Subject: [PATCH 003/689] Strip file hashes from YAML witness cram tests --- tests/regression/56-witness/05-prec-problem.c | 2 +- tests/regression/56-witness/05-prec-problem.t | 24 +++++++++---------- tests/util/yamlWitnessStrip.ml | 24 +++++++++++++++++++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/tests/regression/56-witness/05-prec-problem.c b/tests/regression/56-witness/05-prec-problem.c index 120c211780..ec1a8fc3d4 100644 --- a/tests/regression/56-witness/05-prec-problem.c +++ b/tests/regression/56-witness/05-prec-problem.c @@ -8,7 +8,7 @@ int foo(int* ptr1, int* ptr2){ } else { result = 1; } - // Look at the generated witness.yml to check whether there are contradictory precondition_loop_invariant[s] + // cram test checks for precondition invariant soundness return result; } diff --git a/tests/regression/56-witness/05-prec-problem.t b/tests/regression/56-witness/05-prec-problem.t index 2387cf00e3..33a625696f 100644 --- a/tests/regression/56-witness/05-prec-problem.t +++ b/tests/regression/56-witness/05-prec-problem.t @@ -14,7 +14,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: precondition_loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 12 column: 4 function: foo @@ -29,7 +29,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: precondition_loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 6 column: 7 function: foo @@ -44,7 +44,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: precondition_loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 6 column: 7 function: foo @@ -59,7 +59,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 20 column: 4 function: main @@ -70,7 +70,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 20 column: 4 function: main @@ -81,7 +81,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 19 column: 8 function: main @@ -92,7 +92,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 18 column: 8 function: main @@ -103,7 +103,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 17 column: 8 function: main @@ -114,7 +114,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 12 column: 4 function: foo @@ -125,7 +125,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 12 column: 4 function: foo @@ -136,7 +136,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 6 column: 7 function: foo @@ -147,7 +147,7 @@ The sound invariant is `result == 1 || result == 0`. - entry_type: loop_invariant location: file_name: 05-prec-problem.c - file_hash: cf828ba93b8ed3289734bd38dd37f9e9fd808af7d303b61191df6737aa478928 + file_hash: $STRIPPED_FILE_HASH line: 6 column: 7 function: foo diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 0945fb3bc6..5beb0f6ebe 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -8,6 +8,29 @@ struct } [@@deriving ord] + let strip_file_hashes {entry_type} = + let stripped_file_hash = "$STRIPPED_FILE_HASH" in + let location_strip_file_hash location: Location.t = + {location with file_hash = stripped_file_hash} + in + let target_strip_file_hash target: Target.t = + {target with file_hash = stripped_file_hash} + in + let entry_type: EntryType.t = + match entry_type with + | LoopInvariant x -> + LoopInvariant {x with location = location_strip_file_hash x.location} + | PreconditionLoopInvariant x -> + PreconditionLoopInvariant {x with location = location_strip_file_hash x.location} + | LoopInvariantCertificate x -> + LoopInvariantCertificate {x with target = target_strip_file_hash x.target} + | PreconditionLoopInvariantCertificate x -> + PreconditionLoopInvariantCertificate {x with target = target_strip_file_hash x.target} + | _ -> + entry_type + in + {entry_type} + let to_yaml {entry_type} = `O ([ ("entry_type", `String (EntryType.entry_type entry_type)); @@ -34,6 +57,7 @@ let main () = in let yaml_entries' = StrippedEntrySet.elements entries' + |> List.map StrippedEntry.strip_file_hashes |> List.map StrippedEntry.to_yaml in From 9086c995d95d48be4b3c299632e374b7fcf821a6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 17:16:49 +0300 Subject: [PATCH 004/689] Add YAML witness privatized invariant tests --- tests/regression/13-privatized/01-priv_nr.t | 218 ++++++++++++++++++ tests/regression/13-privatized/dune | 2 + .../regression/36-apron/12-traces-min-rpb1.t | 168 ++++++++++++++ tests/regression/36-apron/dune | 2 + tests/regression/56-witness/dune | 6 +- tests/regression/dune | 9 +- 6 files changed, 399 insertions(+), 6 deletions(-) create mode 100644 tests/regression/13-privatized/01-priv_nr.t create mode 100644 tests/regression/13-privatized/dune create mode 100644 tests/regression/36-apron/12-traces-min-rpb1.t create mode 100644 tests/regression/36-apron/dune diff --git a/tests/regression/13-privatized/01-priv_nr.t b/tests/regression/13-privatized/01-priv_nr.t new file mode 100644 index 0000000000..102c692366 --- /dev/null +++ b/tests/regression/13-privatized/01-priv_nr.t @@ -0,0 +1,218 @@ +`protection` privatization: + + $ goblint --enable witness.yaml.enabled --disable witness.invariant.other --set ana.base.privatization protection 01-priv_nr.c + [Success][Assert] Assertion "glob1 == 5" will succeed (01-priv_nr.c:22:3-22:30) + [Success][Assert] Assertion "t == 5" will succeed (01-priv_nr.c:12:3-12:26) + [Success][Assert] Assertion "glob1 == -10" will succeed (01-priv_nr.c:14:3-14:32) + [Success][Assert] Assertion "glob1 == 6" will succeed (01-priv_nr.c:26:3-26:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total: 19 + [Info][Witness] witness generation summary: + total: 4 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: precondition_loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 25 + column: 2 + function: main + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + precondition: + string: glob1 == 5 + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 11 + column: 2 + function: t_fun + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + precondition: + string: (unsigned long )arg == 0UL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 25 + column: 2 + function: main + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 11 + column: 2 + function: t_fun + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + +`mutex-meet` privatization: + + $ goblint --enable witness.yaml.enabled --disable witness.invariant.other --set ana.base.privatization mutex-meet 01-priv_nr.c + [Success][Assert] Assertion "glob1 == 5" will succeed (01-priv_nr.c:22:3-22:30) + [Success][Assert] Assertion "t == 5" will succeed (01-priv_nr.c:12:3-12:26) + [Success][Assert] Assertion "glob1 == -10" will succeed (01-priv_nr.c:14:3-14:32) + [Success][Assert] Assertion "glob1 == 6" will succeed (01-priv_nr.c:26:3-26:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total: 19 + [Info][Witness] witness generation summary: + total: 4 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: precondition_loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 25 + column: 2 + function: main + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + precondition: + string: glob1 == 5 + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 11 + column: 2 + function: t_fun + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + precondition: + string: (unsigned long )arg == 0UL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 25 + column: 2 + function: main + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 11 + column: 2 + function: t_fun + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + +`write+lock` privatization: + + $ goblint --enable witness.yaml.enabled --disable witness.invariant.other --set ana.base.privatization write+lock 01-priv_nr.c + [Success][Assert] Assertion "glob1 == 5" will succeed (01-priv_nr.c:22:3-22:30) + [Success][Assert] Assertion "t == 5" will succeed (01-priv_nr.c:12:3-12:26) + [Success][Assert] Assertion "glob1 == -10" will succeed (01-priv_nr.c:14:3-14:32) + [Success][Assert] Assertion "glob1 == 6" will succeed (01-priv_nr.c:26:3-26:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total: 19 + [Info][Witness] witness generation summary: + total: 4 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: precondition_loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 25 + column: 2 + function: main + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + precondition: + string: glob1 == 5 + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 11 + column: 2 + function: t_fun + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + precondition: + string: (unsigned long )arg == 0UL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 25 + column: 2 + function: main + loop_invariant: + string: glob1 == 5 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 01-priv_nr.c + file_hash: $STRIPPED_FILE_HASH + line: 11 + column: 2 + function: t_fun + loop_invariant: + string: glob1 == 5 + type: assertion + format: C diff --git a/tests/regression/13-privatized/dune b/tests/regression/13-privatized/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/13-privatized/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t new file mode 100644 index 0000000000..7292c90f48 --- /dev/null +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -0,0 +1,168 @@ + $ goblint --enable witness.yaml.enabled --disable witness.invariant.other --disable ana.base.invariant.enabled --set ana.apron.privatization mutex-meet --set ana.activated[+] apron --enable ana.sv-comp.functions --set ana.apron.domain polyhedra 12-traces-min-rpb1.c + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) + [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 18 + dead: 0 + total: 18 + [Warning][Race] Memory location g@12-traces-min-rpb1.c:7:5-7:10 (race with conf. 110): + write with [mhp:{tid=[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}, + lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (12-traces-min-rpb1.c:14:3-14:8) + read with [mhp:{tid=[main]; created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (12-traces-min-rpb1.c:27:3-27:26) + [Warning][Race] Memory location h@12-traces-min-rpb1.c:8:5-8:10 (race with conf. 110): + write with [mhp:{tid=[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}, lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{tid=[main]; created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (12-traces-min-rpb1.c:27:3-27:26) + [Info][Witness] witness generation summary: + total: 12 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 2 + total: 2 + + $ yamlWitnessStrip < witness.yml + - entry_type: precondition_loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 29 + column: 2 + function: main + loop_invariant: + string: 2147483648LL + (long long )g >= 0LL + type: assertion + format: C + precondition: + string: -1LL + (long long )h == 0LL && -1LL + (long long )g == 0LL + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 29 + column: 2 + function: main + loop_invariant: + string: 2147483647LL - (long long )g >= 0LL + type: assertion + format: C + precondition: + string: -1LL + (long long )h == 0LL && -1LL + (long long )g == 0LL + type: assertion + format: C + - entry_type: precondition_loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 29 + column: 2 + function: main + loop_invariant: + string: (0LL - (long long )g) + (long long )h == 0LL + type: assertion + format: C + precondition: + string: -1LL + (long long )h == 0LL && -1LL + (long long )g == 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 29 + column: 2 + function: main + loop_invariant: + string: 2147483648LL + (long long )g >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 29 + column: 2 + function: main + loop_invariant: + string: 2147483647LL - (long long )g >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 29 + column: 2 + function: main + loop_invariant: + string: (0LL - (long long )g) + (long long )h == 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 19 + column: 2 + function: t_fun + loop_invariant: + string: 2147483648LL + (long long )g >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 19 + column: 2 + function: t_fun + loop_invariant: + string: 2147483647LL - (long long )g >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 19 + column: 2 + function: t_fun + loop_invariant: + string: (0LL - (long long )g) + (long long )h == 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 14 + column: 2 + function: t_fun + loop_invariant: + string: 2147483648LL + (long long )g >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 14 + column: 2 + function: t_fun + loop_invariant: + string: 2147483647LL - (long long )g >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 12-traces-min-rpb1.c + file_hash: $STRIPPED_FILE_HASH + line: 14 + column: 2 + function: t_fun + loop_invariant: + string: (0LL - (long long )g) + (long long )h == 0LL + type: assertion + format: C diff --git a/tests/regression/36-apron/dune b/tests/regression/36-apron/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/36-apron/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) diff --git a/tests/regression/56-witness/dune b/tests/regression/56-witness/dune index 05fce8ddec..23c0dd3290 100644 --- a/tests/regression/56-witness/dune +++ b/tests/regression/56-witness/dune @@ -1,6 +1,2 @@ -(env - (_ - (binaries ../../util/yamlWitnessStrip.exe))) - (cram - (deps (glob_files *.c) %{bin:yamlWitnessStrip})) + (deps (glob_files *.c))) diff --git a/tests/regression/dune b/tests/regression/dune index fdb1d941c2..ff8d68f8c4 100644 --- a/tests/regression/dune +++ b/tests/regression/dune @@ -1,3 +1,10 @@ +(env + (_ + (binaries ../util/yamlWitnessStrip.exe))) + (cram (applies_to :whole_subtree) - (deps %{bin:goblint} (package goblint))) ; need entire package for includes/ + (deps + %{bin:goblint} + (package goblint) ; need entire package for includes/ + %{bin:yamlWitnessStrip})) From 950cf9b1e3679ad2bb53baa4b270038445c20500 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 17:21:26 +0300 Subject: [PATCH 005/689] Fix variable counting with ana.apron.invariant.one-var --- src/analyses/apron/apronAnalysis.apron.ml | 2 +- src/cdomains/apron/apronDomain.apron.ml | 9 ++ .../regression/36-apron/12-traces-min-rpb1.t | 113 +----------------- 3 files changed, 11 insertions(+), 113 deletions(-) diff --git a/src/analyses/apron/apronAnalysis.apron.ml b/src/analyses/apron/apronAnalysis.apron.ml index eab32b3b5b..4de1ced337 100644 --- a/src/analyses/apron/apronAnalysis.apron.ml +++ b/src/analyses/apron/apronAnalysis.apron.ml @@ -542,7 +542,7 @@ struct |> List.enum |> Enum.filter_map (fun (lincons1: Lincons1.t) -> (* filter one-vars *) - if one_var || Apron.Linexpr0.get_size lincons1.lincons0.linexpr0 >= 2 then + if one_var || Lincons1.num_vars lincons1 >= 2 then CilOfApron.cil_exp_of_lincons1 lincons1 |> Option.map e_inv |> Option.filter (fun exp -> not (InvariantCil.exp_contains_tmp exp) && InvariantCil.exp_is_in_scope scope exp) diff --git a/src/cdomains/apron/apronDomain.apron.ml b/src/cdomains/apron/apronDomain.apron.ml index 5f01aef297..37d369c970 100644 --- a/src/cdomains/apron/apronDomain.apron.ml +++ b/src/cdomains/apron/apronDomain.apron.ml @@ -158,6 +158,15 @@ struct let show = Format.asprintf "%a" print let compare x y = String.compare (show x) (show y) (* HACK *) + + let num_vars x = + (* Apron.Linexpr0.get_size returns some internal nonsense, so we count ourselves. *) + let size = ref 0 in + Lincons1.iter (fun coeff var -> + if not (Apron.Coeff.is_zero coeff) then + incr size + ) x; + !size end module Lincons1Set = diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 7292c90f48..f20caf1f5c 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -14,7 +14,7 @@ write with [mhp:{tid=[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}, lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (12-traces-min-rpb1.c:15:3-15:8) read with [mhp:{tid=[main]; created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (12-traces-min-rpb1.c:27:3-27:26) [Info][Witness] witness generation summary: - total: 12 + total: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -22,73 +22,6 @@ total: 2 $ yamlWitnessStrip < witness.yml - - entry_type: precondition_loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 29 - column: 2 - function: main - loop_invariant: - string: 2147483648LL + (long long )g >= 0LL - type: assertion - format: C - precondition: - string: -1LL + (long long )h == 0LL && -1LL + (long long )g == 0LL - type: assertion - format: C - - entry_type: precondition_loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 29 - column: 2 - function: main - loop_invariant: - string: 2147483647LL - (long long )g >= 0LL - type: assertion - format: C - precondition: - string: -1LL + (long long )h == 0LL && -1LL + (long long )g == 0LL - type: assertion - format: C - - entry_type: precondition_loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 29 - column: 2 - function: main - loop_invariant: - string: (0LL - (long long )g) + (long long )h == 0LL - type: assertion - format: C - precondition: - string: -1LL + (long long )h == 0LL && -1LL + (long long )g == 0LL - type: assertion - format: C - - entry_type: loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 29 - column: 2 - function: main - loop_invariant: - string: 2147483648LL + (long long )g >= 0LL - type: assertion - format: C - - entry_type: loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 29 - column: 2 - function: main - loop_invariant: - string: 2147483647LL - (long long )g >= 0LL - type: assertion - format: C - entry_type: loop_invariant location: file_name: 12-traces-min-rpb1.c @@ -100,28 +33,6 @@ string: (0LL - (long long )g) + (long long )h == 0LL type: assertion format: C - - entry_type: loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 19 - column: 2 - function: t_fun - loop_invariant: - string: 2147483648LL + (long long )g >= 0LL - type: assertion - format: C - - entry_type: loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 19 - column: 2 - function: t_fun - loop_invariant: - string: 2147483647LL - (long long )g >= 0LL - type: assertion - format: C - entry_type: loop_invariant location: file_name: 12-traces-min-rpb1.c @@ -133,28 +44,6 @@ string: (0LL - (long long )g) + (long long )h == 0LL type: assertion format: C - - entry_type: loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 14 - column: 2 - function: t_fun - loop_invariant: - string: 2147483648LL + (long long )g >= 0LL - type: assertion - format: C - - entry_type: loop_invariant - location: - file_name: 12-traces-min-rpb1.c - file_hash: $STRIPPED_FILE_HASH - line: 14 - column: 2 - function: t_fun - loop_invariant: - string: 2147483647LL - (long long )g >= 0LL - type: assertion - format: C - entry_type: loop_invariant location: file_name: 12-traces-min-rpb1.c From 6023cbd5fa20199e224299b9eb676b2ef0117285 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 17:32:00 +0300 Subject: [PATCH 006/689] Add ana.apron.invariant.diff-box test --- tests/regression/36-apron/52-queuesize.t | 280 +++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 tests/regression/36-apron/52-queuesize.t diff --git a/tests/regression/36-apron/52-queuesize.t b/tests/regression/36-apron/52-queuesize.t new file mode 100644 index 0000000000..d984535e64 --- /dev/null +++ b/tests/regression/36-apron/52-queuesize.t @@ -0,0 +1,280 @@ +`ana.apron.invariant.diff-box` test case from https://github.com/goblint/analyzer/pull/762. + +Without diff-box: + + $ goblint --enable witness.yaml.enabled --disable witness.invariant.other --disable ana.base.invariant.enabled --set ana.apron.privatization mutex-meet --set ana.activated[+] apron --enable ana.sv-comp.functions --set ana.apron.domain polyhedra --enable ana.apron.invariant.one-var --disable ana.apron.invariant.diff-box 52-queuesize.c + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:67:5-67:31) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:68:5-68:38) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:69:5-69:31) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:70:5-70:38) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:71:5-71:45) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:15:3-15:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:16:3-16:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:17:3-17:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:18:3-18:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:19:3-19:43) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:26:3-26:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:27:3-27:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:28:3-28:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:29:3-29:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:30:3-30:43) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:36:3-36:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:37:3-37:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:38:3-38:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:39:3-39:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:40:3-40:43) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:47:3-47:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:48:3-48:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:49:3-49:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:50:3-50:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:51:3-51:43) + [Warning][Deadcode] Function 'worker' has dead code: + on line 58 (52-queuesize.c:58-58) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 53 + dead: 1 + total: 54 + [Warning][Deadcode][CWE-571] condition '1' is always true (52-queuesize.c:56:10-56:11) + [Warning][Deadcode][CWE-571] condition '1' is always true (52-queuesize.c:78:12-78:13) + [Info][Witness] witness generation summary: + total: 8 + [Info][Race] Memory locations race summary: + safe: 3 + vulnerable: 0 + unsafe: 0 + total: 3 + + $ yamlWitnessStrip < witness.yml | tee witness-disable-diff-box.yml + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: 2147483647LL - (long long )capacity >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: (long long )capacity - (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: ((0LL - (long long )capacity) + (long long )free) + (long long )used == + 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: 2147483647LL - (long long )capacity >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: (long long )capacity - (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: ((0LL - (long long )capacity) + (long long )free) + (long long )used == + 0LL + type: assertion + format: C + +With diff-box: + + $ goblint --enable witness.yaml.enabled --disable witness.invariant.other --disable ana.base.invariant.enabled --set ana.apron.privatization mutex-meet --set ana.activated[+] apron --enable ana.sv-comp.functions --set ana.apron.domain polyhedra --enable ana.apron.invariant.one-var --enable ana.apron.invariant.diff-box 52-queuesize.c + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:67:5-67:31) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:68:5-68:38) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:69:5-69:31) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:70:5-70:38) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:71:5-71:45) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:15:3-15:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:16:3-16:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:17:3-17:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:18:3-18:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:19:3-19:43) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:26:3-26:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:27:3-27:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:28:3-28:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:29:3-29:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:30:3-30:43) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:36:3-36:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:37:3-37:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:38:3-38:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:39:3-39:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:40:3-40:43) + [Success][Assert] Assertion "free >= 0" will succeed (52-queuesize.c:47:3-47:29) + [Success][Assert] Assertion "free <= capacity" will succeed (52-queuesize.c:48:3-48:36) + [Success][Assert] Assertion "used >= 0" will succeed (52-queuesize.c:49:3-49:29) + [Success][Assert] Assertion "used <= capacity" will succeed (52-queuesize.c:50:3-50:36) + [Success][Assert] Assertion "used + free == capacity" will succeed (52-queuesize.c:51:3-51:43) + [Warning][Deadcode] Function 'worker' has dead code: + on line 58 (52-queuesize.c:58-58) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 53 + dead: 1 + total: 54 + [Warning][Deadcode][CWE-571] condition '1' is always true (52-queuesize.c:56:10-56:11) + [Warning][Deadcode][CWE-571] condition '1' is always true (52-queuesize.c:78:12-78:13) + [Info][Witness] witness generation summary: + total: 6 + [Info][Race] Memory locations race summary: + safe: 3 + vulnerable: 0 + unsafe: 0 + total: 3 + + $ yamlWitnessStrip < witness.yml | tee witness-enable-diff-box.yml + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: (long long )capacity - (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 36 + column: 2 + function: push + loop_invariant: + string: ((0LL - (long long )capacity) + (long long )free) + (long long )used == + 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: (long long )capacity - (long long )free >= 0LL + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: 52-queuesize.c + file_hash: $STRIPPED_FILE_HASH + line: 15 + column: 2 + function: pop + loop_invariant: + string: ((0LL - (long long )capacity) + (long long )free) + (long long )used == + 0LL + type: assertion + format: C + +Compare witnesses: + + $ diff witness-disable-diff-box.yml witness-enable-diff-box.yml + 9,19d8 + < string: 2147483647LL - (long long )capacity >= 0LL + < type: assertion + < format: C + < - entry_type: loop_invariant + < location: + < file_name: 52-queuesize.c + < file_hash: $STRIPPED_FILE_HASH + < line: 36 + < column: 2 + < function: push + < loop_invariant: + 44,54d32 + < type: assertion + < format: C + < - entry_type: loop_invariant + < location: + < file_name: 52-queuesize.c + < file_hash: $STRIPPED_FILE_HASH + < line: 15 + < column: 2 + < function: pop + < loop_invariant: + < string: 2147483647LL - (long long )capacity >= 0LL + [1] From 5959095fa4c322e950a4fcccc6a99b222930693c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 17:43:04 +0300 Subject: [PATCH 007/689] Add test for dead code messages (issue #94) Automatic testing wasn't possible in https://github.com/goblint/analyzer/pull/785#issuecomment-1187671949, but is now with cram. --- tests/regression/issue-94.t/issue-94.c | 14 ++++++++++++++ tests/regression/issue-94.t/run.t | 13 +++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/regression/issue-94.t/issue-94.c create mode 100644 tests/regression/issue-94.t/run.t diff --git a/tests/regression/issue-94.t/issue-94.c b/tests/regression/issue-94.t/issue-94.c new file mode 100644 index 0000000000..7bdc65b0a8 --- /dev/null +++ b/tests/regression/issue-94.t/issue-94.c @@ -0,0 +1,14 @@ +#include + +int main() { + int x; + if (1) + x = 1; + else + x = 2; + if (x) + x = 1; + else + x = 2; + assert(x > 1 && x < 0); +} diff --git a/tests/regression/issue-94.t/run.t b/tests/regression/issue-94.t/run.t new file mode 100644 index 0000000000..04c99d3bf2 --- /dev/null +++ b/tests/regression/issue-94.t/run.t @@ -0,0 +1,13 @@ + $ goblint --enable ana.dead-code.lines --enable ana.dead-code.branches issue-94.c + [Error][Assert] Assertion "tmp" will fail. (issue-94.c:13:3-13:35) + [Warning][Deadcode] Function 'main' has dead code: + on line 8 (issue-94.c:8-8) + on line 12 (issue-94.c:12-12) + on line 14 (issue-94.c:14-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 6 + dead: 3 + total: 9 + [Warning][Deadcode][CWE-571] condition '1' is always true (issue-94.c:5:7-5:8) + [Warning][Deadcode][CWE-571] condition 'x' is always true (issue-94.c:9:7-9:8) + [Warning][Deadcode][CWE-570] condition 'x > 1' (possibly inserted by CIL) is always false (issue-94.c:13:3-13:35) From cd90dfe01fd6e4446e10afab0e71f9e4669548a0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Oct 2022 17:54:25 +0300 Subject: [PATCH 008/689] Add test for synthetic YAML witness invariant locations (PR #758) --- tests/regression/pr-758.t/pr-758.c | 22 +++++++++++++++++++++ tests/regression/pr-758.t/run.t | 31 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/regression/pr-758.t/pr-758.c create mode 100644 tests/regression/pr-758.t/run.t diff --git a/tests/regression/pr-758.t/pr-758.c b/tests/regression/pr-758.t/pr-758.c new file mode 100644 index 0000000000..87aa41889d --- /dev/null +++ b/tests/regression/pr-758.t/pr-758.c @@ -0,0 +1,22 @@ +// Code from https://github.com/goblint/cil/pull/98 + +int main() { + // for loop + int x = 42; + for (x = 0; x < 10; x++) { // there shouldn't be invariants x <= 9, x <= 10 and 0 <= x before this line + // ... + } + + // expression with side effect + int i, k; + i = k = 0; // there shouldn't be invariant k == 0 before this line + + // compound initializers + struct kala { + int kaal; + int hind; + }; + + struct kala a = {2, 3}; // there shouldn't be invariant a.kaal == 2 before this line + return 0; +} diff --git a/tests/regression/pr-758.t/run.t b/tests/regression/pr-758.t/run.t new file mode 100644 index 0000000000..d7a94e0ff7 --- /dev/null +++ b/tests/regression/pr-758.t/run.t @@ -0,0 +1,31 @@ + $ goblint --enable ana.int.interval --enable witness.yaml.enabled pr-758.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 6 + dead: 0 + total: 6 + [Info][Witness] witness generation summary: + total: 2 + + $ yamlWitnessStrip < witness.yml + - entry_type: loop_invariant + location: + file_name: pr-758.c + file_hash: $STRIPPED_FILE_HASH + line: 21 + column: 2 + function: main + loop_invariant: + string: a.hind == 3 + type: assertion + format: C + - entry_type: loop_invariant + location: + file_name: pr-758.c + file_hash: $STRIPPED_FILE_HASH + line: 20 + column: 14 + function: main + loop_invariant: + string: i == 0 + type: assertion + format: C From 8cc3ff2641831e202447e84805b506a6576b4b92 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 11:35:37 +0300 Subject: [PATCH 009/689] Automate 00-sanity/33-hoare-over-paths using cram --- .../00-sanity/33-hoare-over-paths.c | 4 +- .../00-sanity/33-hoare-over-paths.t | 208 ++++++++++++++++++ 2 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 tests/regression/00-sanity/33-hoare-over-paths.t diff --git a/tests/regression/00-sanity/33-hoare-over-paths.c b/tests/regression/00-sanity/33-hoare-over-paths.c index b30586fa59..4a809685ed 100644 --- a/tests/regression/00-sanity/33-hoare-over-paths.c +++ b/tests/regression/00-sanity/33-hoare-over-paths.c @@ -27,8 +27,8 @@ int main() { // NEW explanation: // using SensitiveDomain correctly keeps both paths as path-sensitivity demands - // TODO: manually check final join node in HTML - // cannot be automated because concrete execution cannot check + // cram test checks internal result + // cannot be automated with annotations because concrete execution cannot check // if _must_ lockset _may_ contain m on some path return 0; } diff --git a/tests/regression/00-sanity/33-hoare-over-paths.t b/tests/regression/00-sanity/33-hoare-over-paths.t new file mode 100644 index 0000000000..4d74277cbc --- /dev/null +++ b/tests/regression/00-sanity/33-hoare-over-paths.t @@ -0,0 +1,208 @@ + $ goblint --set ana.path_sens[+] mutex --set result pretty --set outfile pretty.txt 33-hoare-over-paths.c + [Success][Assert] Assertion "1" will succeed (33-hoare-over-paths.c:11:5-11:24) + [Success][Assert] Assertion "1" will succeed (33-hoare-over-paths.c:16:5-16:24) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 0 + total: 7 + + $ cat pretty.txt + Mapping { + 33-hoare-over-paths.c:7:1-34:1(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + })} + 33-hoare-over-paths.c:9:7-9:8(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (Unknown int([-31,31])) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + })} + 33-hoare-over-paths.c:10:5-10:10(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (Not {0}([-31,31])) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + })} + 33-hoare-over-paths.c:11:5-11:24(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + })} + 33-hoare-over-paths.c:15:5-15:27(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + })} + 33-hoare-over-paths.c:16:5-16:24(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{m}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + })} + 33-hoare-over-paths.c:33:3-33:11(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{m}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + }), ([Unit:(), + Unit:(), + Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, + Unit:(), + Unit:(), + top or Set (variables):{}, + booleans:False, + MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Local { + r -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), + Unit:()], mapping { + })} + 33-hoare-over-paths.c:7:1-34:1(main) -> + {([Unit:(), Unit:(), Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{m}, Unit:(), Unit:(), + top or Set (variables):{}, booleans:False, MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Temp { + RETURN -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), Unit:()], mapping { + }), ([Unit:(), + Unit:(), + Unit:(), + Reversed (top or Set (Normal Lvals * booleans)):{}, + Unit:(), + Unit:(), + top or Set (variables):{}, + booleans:False, + MT mode:Singlethreaded, + Thread * lifted created and Unit:([main], bot), + value domain * array partitioning deps * Vars with Weak Update * P:(mapping { + Global { + m -> + mutex + } + Temp { + RETURN -> + (0) + } + }, mapping { + }, {}, {}), + top or std * lifted node:(mapping { + }, Unknown node), + Unit:()], mapping { + })} + OTHERS -> Not available + } From 9f5c0e11020bc2ada09373e592626b8b8bb27234 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 12:40:50 +0300 Subject: [PATCH 010/689] Print regression tests without any automatic checks --- scripts/update_suite.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index 65070303da..3078d1e7ca 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -312,6 +312,9 @@ def parse_tests (lines) when /TERM/ tests[-1] = "term" end + if tests.empty? then + puts "No automatic checks in #{@id}" + end Tests.new(self, tests, tests_line, todo) end From 4705c301f9487e835d335df4bc9c34fbcf970356 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 12:43:38 +0300 Subject: [PATCH 011/689] Fix many regression tests without automatic checks --- scripts/update_suite.rb | 13 ++++++++++- .../00-sanity/18-parse-empty-array.c | 1 + .../00-sanity/29-earlyglobs-insens.c | 1 + tests/regression/01-cpa/38-enum.c | 2 +- tests/regression/01-cpa/55-def_exc-widen.c | 1 + tests/regression/01-cpa/56-def_exc-fp1.c | 2 +- .../01-cpa/57-def_exc-interval-inconsistent.c | 2 +- tests/regression/02-base/34-builtin_va_list.c | 1 + tests/regression/02-base/64-enums-minmax.c | 1 + .../02-base/69-ipmi-struct-blob-fixpoint.c | 2 +- .../02-base/72-ad-widen-duplicate.c | 1 + .../02-base/73-no-eval-on-write-offset.c | 1 + .../02-base/87-casts-dep-on-param.c | 2 +- .../03-practical/21-pfscan_combine_minimal.c | 1 + .../regression/03-practical/23-knot-timeout.c | 2 +- tests/regression/06-symbeq/40-var_eq-widen1.c | 2 +- .../10-synch/23-tid-partitioned-array.c | 1 + .../24-tid-partitioned-array-global.c | 1 + .../regression/10-synch/25-tid-array-malloc.c | 1 + .../10-synch/26-tid-array-malloc-free.c | 1 + .../59-smtprc_threadenter_path_minimal.c | 2 +- tests/regression/18-file/01-ok.c | 10 ++++----- tests/regression/18-file/02-function.c | 10 ++++----- tests/regression/18-file/08-var-reuse.c | 16 +++++++------- tests/regression/18-file/10-inf-loop-ok.c | 10 ++++----- tests/regression/18-file/25-mem-ok.c | 22 +++++++++---------- tests/regression/18-file/26-open-error-ok.c | 10 ++++----- tests/regression/18-file/29-alias-global.c | 14 ++++++------ tests/regression/18-file/36-fun-ptr.c | 10 ++++----- .../20-slr_term/06-trylock_rc_slr.c | 1 + .../29-svcomp/05-isp1362-malloc-fun.c | 2 +- .../regression/29-svcomp/11-arithmetic-bot.c | 1 + tests/regression/29-svcomp/12-interval-bot.c | 2 +- .../regression/29-svcomp/13-comparision-bot.c | 1 + .../14-addition-in-comparision-bot.c | 1 + tests/regression/29-svcomp/19-problematic.c | 1 + tests/regression/29-svcomp/21-issue-casting.c | 1 + .../regression/31-ikind-aware-ints/03-lnot.c | 1 + .../31-ikind-aware-ints/04-ptrdiff.c | 1 + .../regression/31-ikind-aware-ints/05-shift.c | 2 +- .../31-ikind-aware-ints/06-structs.c | 1 + .../31-ikind-aware-ints/15-strange.c | 2 +- .../31-ikind-aware-ints/17-def-enum-refine.c | 2 +- .../35-marshaling/01-disable_hashcons.c | 1 + .../54-unroll_arrays/03-large_index_type.c | 4 ++-- .../54-unroll_arrays/04-access_no_bounds.c | 4 ++-- .../56-witness/50-witness-lifter-fp1.c | 2 +- 47 files changed, 103 insertions(+), 70 deletions(-) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index 3078d1e7ca..bbce8614a2 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -203,6 +203,8 @@ def compare_warnings check.call warnings[idx] != "race" when "nodeadlock" check.call warnings[idx] != "deadlock" + when "nocrash", "fixpoint", "notimeout", "cram" + check.call true end end end @@ -281,6 +283,15 @@ def parse_tests (lines) if obj =~ /#line ([0-9]+).*$/ then i = $1.to_i - 1 end + if obj =~ /NOCRASH/ then + tests[-42] = "nocrash" + elsif obj =~ /FIXPOINT/ then + tests[-42] = "fixpoint" + elsif obj =~ /NOTIMEOUT/ then + tests[-42] = "notimeout" + elsif obj =~ /CRAM/ then + tests[-42] = "cram" + end next if obj =~ /^\s*\/\// || obj =~ /^\s*\/\*([^*]|\*+[^*\/])*\*\/$/ todo << i if obj =~ /TODO|SKIP/ tests_line[i] = obj @@ -313,7 +324,7 @@ def parse_tests (lines) tests[-1] = "term" end if tests.empty? then - puts "No automatic checks in #{@id}" + puts "No automatic checks in #{@id} (maybe NOCRASH/FIXPOINT/NOTIMEOUT/CRAM?)" end Tests.new(self, tests, tests_line, todo) end diff --git a/tests/regression/00-sanity/18-parse-empty-array.c b/tests/regression/00-sanity/18-parse-empty-array.c index a38cbc3712..2205d412da 100644 --- a/tests/regression/00-sanity/18-parse-empty-array.c +++ b/tests/regression/00-sanity/18-parse-empty-array.c @@ -1,4 +1,5 @@ // Test for issue in https://github.com/goblint/cil/issues/19 +// NOCRASH static int a[]; static int a[] = {}; static int b[0] = {}; diff --git a/tests/regression/00-sanity/29-earlyglobs-insens.c b/tests/regression/00-sanity/29-earlyglobs-insens.c index 9d2f186c3e..e671522c51 100644 --- a/tests/regression/00-sanity/29-earlyglobs-insens.c +++ b/tests/regression/00-sanity/29-earlyglobs-insens.c @@ -1,2 +1,3 @@ // PARAM: --set ana.ctx_insens[+] base --enable exp.earlyglobs +// NOCRASH int main() {} diff --git a/tests/regression/01-cpa/38-enum.c b/tests/regression/01-cpa/38-enum.c index 818705843e..ff345b6ba7 100644 --- a/tests/regression/01-cpa/38-enum.c +++ b/tests/regression/01-cpa/38-enum.c @@ -1,7 +1,7 @@ // PARAM: --disable ana.int.interval --disable ana.int.def_exc --enable ana.int.enums void main(){ int n = 1; - for (; n; n++) { // fixed point not reached here + for (; n; n++) { // FIXPOINT: previously fixed point not reached here } return; } diff --git a/tests/regression/01-cpa/55-def_exc-widen.c b/tests/regression/01-cpa/55-def_exc-widen.c index 23b724ae7b..c19f3ab62e 100644 --- a/tests/regression/01-cpa/55-def_exc-widen.c +++ b/tests/regression/01-cpa/55-def_exc-widen.c @@ -1,4 +1,5 @@ //PARAM: --disable ana.int.def_exc_widen_by_join +// NOTIMEOUT int main(int argc , char **argv ) { char buf[512]; diff --git a/tests/regression/01-cpa/56-def_exc-fp1.c b/tests/regression/01-cpa/56-def_exc-fp1.c index 69390b1e35..8e38a04531 100644 --- a/tests/regression/01-cpa/56-def_exc-fp1.c +++ b/tests/regression/01-cpa/56-def_exc-fp1.c @@ -1,6 +1,6 @@ // PARAM: --enable ana.sv-comp.functions // manually minimized from sv-benchmarks/c/seq-mthreaded/pals_lcr.3.ufo.UNBOUNDED.pals.c -// used to not reach fixpoint due to def_exc range +// FIXPOINT: used to not reach fixpoint due to def_exc range _Bool __VERIFIER_nondet_bool(void) ; _Bool mode1 ; diff --git a/tests/regression/01-cpa/57-def_exc-interval-inconsistent.c b/tests/regression/01-cpa/57-def_exc-interval-inconsistent.c index a550ea172f..b0ac9ae5ba 100644 --- a/tests/regression/01-cpa/57-def_exc-interval-inconsistent.c +++ b/tests/regression/01-cpa/57-def_exc-interval-inconsistent.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.int.def_exc --enable ana.int.interval --enable ana.sv-comp.functions --set sem.int.signed_overflow assume_none --set ana.int.refinement never -// used to crash in branch when is_bool returned true, but to_bool returned None on (0,[1,1]) +// NOCRASH: used to crash in branch when is_bool returned true, but to_bool returned None on (0,[1,1]) // manually minimized from sv-benchmarks/c/recursive/MultCommutative-2.c extern int __VERIFIER_nondet_int(void); diff --git a/tests/regression/02-base/34-builtin_va_list.c b/tests/regression/02-base/34-builtin_va_list.c index 2ab9168c68..f16d6fc0fd 100644 --- a/tests/regression/02-base/34-builtin_va_list.c +++ b/tests/regression/02-base/34-builtin_va_list.c @@ -1,3 +1,4 @@ +// NOCRASH #include int sum(int n, ...) { diff --git a/tests/regression/02-base/64-enums-minmax.c b/tests/regression/02-base/64-enums-minmax.c index 9d366aa56f..6c0d827cf0 100644 --- a/tests/regression/02-base/64-enums-minmax.c +++ b/tests/regression/02-base/64-enums-minmax.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.enums +// NOTIMEOUT int main(void) { unsigned char c; int top; diff --git a/tests/regression/02-base/69-ipmi-struct-blob-fixpoint.c b/tests/regression/02-base/69-ipmi-struct-blob-fixpoint.c index 3aa06d1820..8e7e42f0e6 100644 --- a/tests/regression/02-base/69-ipmi-struct-blob-fixpoint.c +++ b/tests/regression/02-base/69-ipmi-struct-blob-fixpoint.c @@ -30,7 +30,7 @@ static int ipmi_open(struct inode *inode, struct file *file) struct ipmi_file_private *priv; priv = kmalloc(sizeof(*priv), GFP_KERNEL); mutex_lock(&ipmi_mutex); - priv->file = file; // should reach fixpoint from priv side effect from here + priv->file = file; // FIXPOINT: should reach fixpoint from priv side effect from here ipmi_create_user(0, &ipmi_hndlrs, priv, &(priv->user)); file->private_data = priv; diff --git a/tests/regression/02-base/72-ad-widen-duplicate.c b/tests/regression/02-base/72-ad-widen-duplicate.c index 436ae70c93..c893d4ae79 100644 --- a/tests/regression/02-base/72-ad-widen-duplicate.c +++ b/tests/regression/02-base/72-ad-widen-duplicate.c @@ -1,4 +1,5 @@ // https://github.com/goblint/analyzer/issues/554 +// FIXPOINT int a; int main() { c(&a); } diff --git a/tests/regression/02-base/73-no-eval-on-write-offset.c b/tests/regression/02-base/73-no-eval-on-write-offset.c index da0e635dfb..780c244e9a 100644 --- a/tests/regression/02-base/73-no-eval-on-write-offset.c +++ b/tests/regression/02-base/73-no-eval-on-write-offset.c @@ -1,4 +1,5 @@ // PARAM: --enable exp.earlyglobs +// NOCRASH char a; int c; diff --git a/tests/regression/02-base/87-casts-dep-on-param.c b/tests/regression/02-base/87-casts-dep-on-param.c index 93a16e4bc3..a265b9db04 100644 --- a/tests/regression/02-base/87-casts-dep-on-param.c +++ b/tests/regression/02-base/87-casts-dep-on-param.c @@ -9,7 +9,7 @@ int g () { int a[10]; f(1, &i); - // check that i is an integer and can be used for array indexing without Goblint crashing + // NOCRASH: check that i is an integer and can be used for array indexing without Goblint crashing int r = a[i]; a[i] = r; diff --git a/tests/regression/03-practical/21-pfscan_combine_minimal.c b/tests/regression/03-practical/21-pfscan_combine_minimal.c index 5054260216..abdef0627b 100644 --- a/tests/regression/03-practical/21-pfscan_combine_minimal.c +++ b/tests/regression/03-practical/21-pfscan_combine_minimal.c @@ -1,3 +1,4 @@ +// FIXPOINT #include struct __anonstruct_PQUEUE_63 { diff --git a/tests/regression/03-practical/23-knot-timeout.c b/tests/regression/03-practical/23-knot-timeout.c index f972363cea..2fafe5d4da 100644 --- a/tests/regression/03-practical/23-knot-timeout.c +++ b/tests/regression/03-practical/23-knot-timeout.c @@ -1,5 +1,5 @@ // PARAM: --disable ana.int.def_exc_widen_by_join -// Used to timeout without ana.int.def_exc_widen_by_join +// NOTIMEOUT: Used to timeout without ana.int.def_exc_widen_by_join #include struct a { diff --git a/tests/regression/06-symbeq/40-var_eq-widen1.c b/tests/regression/06-symbeq/40-var_eq-widen1.c index 72e28c57a0..1cef7fe324 100644 --- a/tests/regression/06-symbeq/40-var_eq-widen1.c +++ b/tests/regression/06-symbeq/40-var_eq-widen1.c @@ -1,6 +1,6 @@ // PARAM: --set ana.activated[+] var_eq // manually minimized from sv-benchmarks/c/ldv-linux-3.16-rc1/205_9a_array_unsafes_linux-3.16-rc1.tar.xz-205_9a-drivers--net--usb--cx82310_eth.ko-entry_point.cil.out.i -// used to call widen incorrectly +// NOCRASH: used to call widen incorrectly typedef _Bool bool; void usb_bulk_msg(int *arg4, int x) { diff --git a/tests/regression/10-synch/23-tid-partitioned-array.c b/tests/regression/10-synch/23-tid-partitioned-array.c index 0f4942ec0e..e0dc849fad 100644 --- a/tests/regression/10-synch/23-tid-partitioned-array.c +++ b/tests/regression/10-synch/23-tid-partitioned-array.c @@ -1,4 +1,5 @@ // PARAM: --set ana.activated[+] thread --set ana.base.arrays.domain partitioned +// NOCRASH #include void *t_fun(void *arg) { diff --git a/tests/regression/10-synch/24-tid-partitioned-array-global.c b/tests/regression/10-synch/24-tid-partitioned-array-global.c index b61daed77f..00685dc1c8 100644 --- a/tests/regression/10-synch/24-tid-partitioned-array-global.c +++ b/tests/regression/10-synch/24-tid-partitioned-array-global.c @@ -1,4 +1,5 @@ // PARAM: --set ana.activated[+] thread --set ana.base.arrays.domain partitioned +// NOCRASH #include pthread_t t_ids[10000]; diff --git a/tests/regression/10-synch/25-tid-array-malloc.c b/tests/regression/10-synch/25-tid-array-malloc.c index 4000577fd3..e59cd02e97 100644 --- a/tests/regression/10-synch/25-tid-array-malloc.c +++ b/tests/regression/10-synch/25-tid-array-malloc.c @@ -1,4 +1,5 @@ // PARAM: --set ana.activated[+] thread +// NOCRASH #include #include diff --git a/tests/regression/10-synch/26-tid-array-malloc-free.c b/tests/regression/10-synch/26-tid-array-malloc-free.c index e8f00d13ae..b070fd0d84 100644 --- a/tests/regression/10-synch/26-tid-array-malloc-free.c +++ b/tests/regression/10-synch/26-tid-array-malloc-free.c @@ -1,4 +1,5 @@ // PARAM: --set ana.activated[+] thread +// NOCRASH #include #include diff --git a/tests/regression/13-privatized/59-smtprc_threadenter_path_minimal.c b/tests/regression/13-privatized/59-smtprc_threadenter_path_minimal.c index 5a9342cfd0..dcbc617e0b 100644 --- a/tests/regression/13-privatized/59-smtprc_threadenter_path_minimal.c +++ b/tests/regression/13-privatized/59-smtprc_threadenter_path_minimal.c @@ -48,7 +48,7 @@ int main(int argc , char **argv ) } pthread_mutex_unlock(& main_thread_count_mutex); - // lock gets here with two paths and crashes + // NOCRASH: lock gets here with two paths and crashes pthread_create(& c_tid, NULL, & thread_start, NULL); return (0); } \ No newline at end of file diff --git a/tests/regression/18-file/01-ok.c b/tests/regression/18-file/01-ok.c index 5c1f21ff1c..db8595022a 100644 --- a/tests/regression/18-file/01-ok.c +++ b/tests/regression/18-file/01-ok.c @@ -1,12 +1,12 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include int main(){ FILE *fp; - fp = fopen("test.txt", "a"); - fprintf(fp, "Testing...\n"); - fclose(fp); -} + fp = fopen("test.txt", "a"); // NOWARN + fprintf(fp, "Testing...\n"); // NOWARN + fclose(fp); // NOWARN +} // NOWARN // All ok! diff --git a/tests/regression/18-file/02-function.c b/tests/regression/18-file/02-function.c index fc3157c264..eb869b2de7 100644 --- a/tests/regression/18-file/02-function.c +++ b/tests/regression/18-file/02-function.c @@ -1,17 +1,17 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include FILE *fp; void f(){ - fp = fopen("test.txt", "a"); + fp = fopen("test.txt", "a"); // NOWARN } int main(){ f(); - fprintf(fp, "Testing...\n"); - fclose(fp); -} + fprintf(fp, "Testing...\n"); // NOWARN + fclose(fp); // NOWARN +} // NOWARN // All ok! diff --git a/tests/regression/18-file/08-var-reuse.c b/tests/regression/18-file/08-var-reuse.c index 1caa238517..001e3592ad 100644 --- a/tests/regression/18-file/08-var-reuse.c +++ b/tests/regression/18-file/08-var-reuse.c @@ -1,15 +1,15 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include int main(){ FILE *fp; - fp = fopen("test.txt", "a"); - fprintf(fp, "Testing...\n"); - fclose(fp); - fp = fopen("test2.txt", "a"); - fprintf(fp, "Testing...\n"); - fclose(fp); -} + fp = fopen("test.txt", "a"); // NOWARN + fprintf(fp, "Testing...\n"); // NOWARN + fclose(fp); // NOWARN + fp = fopen("test2.txt", "a"); // NOWARN + fprintf(fp, "Testing...\n"); // NOWARN + fclose(fp); // NOWARN +} // NOWARN // All ok! diff --git a/tests/regression/18-file/10-inf-loop-ok.c b/tests/regression/18-file/10-inf-loop-ok.c index d88fde272e..51ea8e8845 100644 --- a/tests/regression/18-file/10-inf-loop-ok.c +++ b/tests/regression/18-file/10-inf-loop-ok.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include @@ -6,14 +6,14 @@ FILE *fp; int main(){ int i; - fp = fopen("test.txt", "a"); + fp = fopen("test.txt", "a"); // NOWARN while (i){ - fprintf(fp, "Testing...\n"); + fprintf(fp, "Testing...\n"); // NOWARN i++; } - fclose(fp); -} + fclose(fp); // NOWARN +} // NOWARN // All ok. diff --git a/tests/regression/18-file/25-mem-ok.c b/tests/regression/18-file/25-mem-ok.c index 00ba189b8d..becda78caa 100644 --- a/tests/regression/18-file/25-mem-ok.c +++ b/tests/regression/18-file/25-mem-ok.c @@ -1,13 +1,13 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include int main(){ FILE *fp[3]; // Array -> varinfo with index-offset - fp[1] = fopen("test.txt", "a"); - fprintf(fp[1], "Testing...\n"); - fclose(fp[1]); + fp[1] = fopen("test.txt", "a"); // NOWARN + fprintf(fp[1], "Testing...\n"); // NOWARN + fclose(fp[1]); // NOWARN struct foo { @@ -15,15 +15,15 @@ int main(){ FILE *fp; } bar; // Struct -> varinfo with field-offset - bar.fp = fopen("test.txt", "a"); - fprintf(bar.fp, "Testing...\n"); - fclose(bar.fp); + bar.fp = fopen("test.txt", "a"); // NOWARN + fprintf(bar.fp, "Testing...\n"); // NOWARN + fclose(bar.fp); // NOWARN // Pointer -> Mem exp - *(fp+2) = fopen("test.txt", "a"); - fprintf(*(fp+2), "Testing...\n"); - fclose(*(fp+2)); -} + *(fp+2) = fopen("test.txt", "a"); // NOWARN + fprintf(*(fp+2), "Testing...\n"); // NOWARN + fclose(*(fp+2)); // NOWARN +} // NOWARN // All ok! diff --git a/tests/regression/18-file/26-open-error-ok.c b/tests/regression/18-file/26-open-error-ok.c index 5cf3aaf7bb..45fc907cb7 100644 --- a/tests/regression/18-file/26-open-error-ok.c +++ b/tests/regression/18-file/26-open-error-ok.c @@ -1,15 +1,15 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include int main (){ FILE *fp; - fp = fopen("test.txt", "w"); + fp = fopen("test.txt", "w"); // NOWARN if(fp!=NULL){ - fprintf(fp, "Testing..."); - fclose(fp); + fprintf(fp, "Testing..."); // NOWARN + fclose(fp); // NOWARN } -} +} // NOWARN // All ok! diff --git a/tests/regression/18-file/29-alias-global.c b/tests/regression/18-file/29-alias-global.c index 17b94748c0..4e28393bbc 100644 --- a/tests/regression/18-file/29-alias-global.c +++ b/tests/regression/18-file/29-alias-global.c @@ -1,10 +1,10 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include FILE* fp; FILE* myfopen(char* f){ - fp = fopen(f, "a"); + fp = fopen(f, "a"); // NOWARN return fp; } @@ -13,10 +13,10 @@ int main(){ FILE *fp2; fp1 = myfopen("test1.txt"); fp2 = myfopen("test2.txt"); - fprintf(fp1, "Testing...\n"); - fclose(fp1); - fprintf(fp2, "Testing...\n"); - fclose(fp2); -} + fprintf(fp1, "Testing...\n"); // NOWARN + fclose(fp1); // NOWARN + fprintf(fp2, "Testing...\n"); // NOWARN + fclose(fp2); // NOWARN +} // NOWARN // All ok! diff --git a/tests/regression/18-file/36-fun-ptr.c b/tests/regression/18-file/36-fun-ptr.c index 4f70bf7382..4e50f560fd 100644 --- a/tests/regression/18-file/36-fun-ptr.c +++ b/tests/regression/18-file/36-fun-ptr.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic +// PARAM: --set ana.activated[+] "'file'" --enable ana.file.optimistic --disable warn.info #include @@ -6,9 +6,9 @@ int main(){ FILE *fp; FILE* (*f)(const char *, const char*); f = fopen; - fp = f("test.txt", "a"); - fprintf(fp, "Testing...\n"); - fclose(fp); -} + fp = f("test.txt", "a"); // NOWARN + fprintf(fp, "Testing...\n"); // NOWARN + fclose(fp); // NOWARN +} // NOWARN // All ok! diff --git a/tests/regression/20-slr_term/06-trylock_rc_slr.c b/tests/regression/20-slr_term/06-trylock_rc_slr.c index ab24b142f6..d6e3c3f31e 100644 --- a/tests/regression/20-slr_term/06-trylock_rc_slr.c +++ b/tests/regression/20-slr_term/06-trylock_rc_slr.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval --set solver slr3t +// FIXPOINT #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/tests/regression/29-svcomp/05-isp1362-malloc-fun.c b/tests/regression/29-svcomp/05-isp1362-malloc-fun.c index b8ded7e341..f1c8dece14 100644 --- a/tests/regression/29-svcomp/05-isp1362-malloc-fun.c +++ b/tests/regression/29-svcomp/05-isp1362-malloc-fun.c @@ -1,5 +1,5 @@ // PARAM: --set ana.malloc.wrappers "['ldv_malloc']" - +// NOCRASH #include typedef unsigned long __kernel_ulong_t; diff --git a/tests/regression/29-svcomp/11-arithmetic-bot.c b/tests/regression/29-svcomp/11-arithmetic-bot.c index ce8635b939..d365f14a31 100644 --- a/tests/regression/29-svcomp/11-arithmetic-bot.c +++ b/tests/regression/29-svcomp/11-arithmetic-bot.c @@ -1,5 +1,6 @@ // PARAM: --enable ana.int.interval --enable ana.int.def_exc // from: ldv-linux-3.0/usb_urb-drivers-vhost-vhost_net.ko.cil.out.i +// NOCRASH typedef unsigned long long u64; int main( ) diff --git a/tests/regression/29-svcomp/12-interval-bot.c b/tests/regression/29-svcomp/12-interval-bot.c index 77739efdbd..9d6157875a 100644 --- a/tests/regression/29-svcomp/12-interval-bot.c +++ b/tests/regression/29-svcomp/12-interval-bot.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.int.interval --enable ana.int.def_exc - +// NOCRASH int main(){ unsigned long long a ; diff --git a/tests/regression/29-svcomp/13-comparision-bot.c b/tests/regression/29-svcomp/13-comparision-bot.c index f64fa8a349..843a5fabb4 100644 --- a/tests/regression/29-svcomp/13-comparision-bot.c +++ b/tests/regression/29-svcomp/13-comparision-bot.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval --enable ana.int.def_exc +// NOCRASH #include int main(){ int a = 0; diff --git a/tests/regression/29-svcomp/14-addition-in-comparision-bot.c b/tests/regression/29-svcomp/14-addition-in-comparision-bot.c index f667ca88f6..c729cf6019 100644 --- a/tests/regression/29-svcomp/14-addition-in-comparision-bot.c +++ b/tests/regression/29-svcomp/14-addition-in-comparision-bot.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval +// NOCRASH int main() { unsigned int top; diff --git a/tests/regression/29-svcomp/19-problematic.c b/tests/regression/29-svcomp/19-problematic.c index 63b4fc7af0..99c7c01197 100644 --- a/tests/regression/29-svcomp/19-problematic.c +++ b/tests/regression/29-svcomp/19-problematic.c @@ -1,5 +1,6 @@ // PARAM: --enable ana.sv-comp.functions // Adapted from: https://github.com/sosy-lab/sv-benchmarks/blob/master/c/ldv-regression/test27-2.c +// NOTIMEOUT extern int __VERIFIER_nondet_int(void); struct dummy { diff --git a/tests/regression/29-svcomp/21-issue-casting.c b/tests/regression/29-svcomp/21-issue-casting.c index e02989559c..35d81d4898 100644 --- a/tests/regression/29-svcomp/21-issue-casting.c +++ b/tests/regression/29-svcomp/21-issue-casting.c @@ -1,6 +1,7 @@ // PARAM: --set ana.activated ["'base'","'mallocWrapper'"] --set ana.base.privatization none // minimal analyses to reveal bug // none privatization because mutex deactivated +// NOTIMEOUT static long main(void) { unsigned int cmd; diff --git a/tests/regression/31-ikind-aware-ints/03-lnot.c b/tests/regression/31-ikind-aware-ints/03-lnot.c index 2fb6d79c61..6d96d88dea 100644 --- a/tests/regression/31-ikind-aware-ints/03-lnot.c +++ b/tests/regression/31-ikind-aware-ints/03-lnot.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval +// NOCRASH int main() { unsigned int l = 0; diff --git a/tests/regression/31-ikind-aware-ints/04-ptrdiff.c b/tests/regression/31-ikind-aware-ints/04-ptrdiff.c index 4be48c7793..be658b3cd0 100644 --- a/tests/regression/31-ikind-aware-ints/04-ptrdiff.c +++ b/tests/regression/31-ikind-aware-ints/04-ptrdiff.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.activated[+] var_eq +// NOCRASH int *tmp; int main () diff --git a/tests/regression/31-ikind-aware-ints/05-shift.c b/tests/regression/31-ikind-aware-ints/05-shift.c index a0cf2182d8..87bfba5a0b 100644 --- a/tests/regression/31-ikind-aware-ints/05-shift.c +++ b/tests/regression/31-ikind-aware-ints/05-shift.c @@ -1,6 +1,6 @@ // PARAM: --enable ana.int.interval int main(void) { - // Shifting by a negative number is UB, but we should still not crash on it, but go to top instead + // NOCRASH: Shifting by a negative number is UB, but we should still not crash on it, but go to top instead int v = -1; int r = 17; int u = r >> v; diff --git a/tests/regression/31-ikind-aware-ints/06-structs.c b/tests/regression/31-ikind-aware-ints/06-structs.c index ddf3b51cf0..d3c944c4cd 100644 --- a/tests/regression/31-ikind-aware-ints/06-structs.c +++ b/tests/regression/31-ikind-aware-ints/06-structs.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval +// NOCRASH struct rtl8169_private { unsigned int features ; }; diff --git a/tests/regression/31-ikind-aware-ints/15-strange.c b/tests/regression/31-ikind-aware-ints/15-strange.c index d063b3c6e2..550baf0e1d 100644 --- a/tests/regression/31-ikind-aware-ints/15-strange.c +++ b/tests/regression/31-ikind-aware-ints/15-strange.c @@ -1,7 +1,7 @@ //PARAM: --disable ana.int.interval --disable ana.int.def_exc --enable ana.int.enums int main (int argc, char* argv[]) { - // This used to cause an exception because of incompatible ikinds + // NOCRASH: This used to cause an exception because of incompatible ikinds // See https://github.com/goblint/cil/issues/29 signed char f2 = 7; signed char l_1857 = ((0xFFBD4A17L && f2) | f2); diff --git a/tests/regression/31-ikind-aware-ints/17-def-enum-refine.c b/tests/regression/31-ikind-aware-ints/17-def-enum-refine.c index e34d2d1c79..fd3a75154e 100644 --- a/tests/regression/31-ikind-aware-ints/17-def-enum-refine.c +++ b/tests/regression/31-ikind-aware-ints/17-def-enum-refine.c @@ -4,7 +4,7 @@ int main() { _Bool c; if(c) { x--;} else { x--;} - // The veryfier claimed that the fixed-point was not reached here due to a bug in Enums.leq + // FIXPOINT: The veryfier claimed that the fixed-point was not reached here due to a bug in Enums.leq // The leq wrongly returned false for the Enums {0} and not{}[0,1] return 0; } diff --git a/tests/regression/35-marshaling/01-disable_hashcons.c b/tests/regression/35-marshaling/01-disable_hashcons.c index f6a72bd685..5be9e47819 100644 --- a/tests/regression/35-marshaling/01-disable_hashcons.c +++ b/tests/regression/35-marshaling/01-disable_hashcons.c @@ -1,2 +1,3 @@ // PARAM: --disable ana.opt.hashcons +// NOCRASH int main(void) { return 0; } diff --git a/tests/regression/54-unroll_arrays/03-large_index_type.c b/tests/regression/54-unroll_arrays/03-large_index_type.c index d2e902be83..80851aa4b8 100644 --- a/tests/regression/54-unroll_arrays/03-large_index_type.c +++ b/tests/regression/54-unroll_arrays/03-large_index_type.c @@ -1,9 +1,9 @@ //PARAM: --set ana.base.arrays.domain unroll --set ana.base.arrays.unrolling-factor 5 //from sv-comp test c/aws-c-common/memset_using_uint64_harness.i - +// NOCRASH typedef long unsigned int size_t; -int main() { +int main() { int d[]; size_t num_uint64s; diff --git a/tests/regression/54-unroll_arrays/04-access_no_bounds.c b/tests/regression/54-unroll_arrays/04-access_no_bounds.c index d0a5634b53..fe4886962e 100644 --- a/tests/regression/54-unroll_arrays/04-access_no_bounds.c +++ b/tests/regression/54-unroll_arrays/04-access_no_bounds.c @@ -1,6 +1,6 @@ // PARAM: --set ana.base.arrays.domain unroll --set ana.base.arrays.unrolling-factor 5 //from sv-comp test c/aws-c-common/aws_array_eq_c_str_ignore_case_harness.i - +// NOCRASH typedef long unsigned int size_t; typedef unsigned char uint8_t; @@ -18,7 +18,7 @@ static const uint8_t s_tolower_table[256] = { 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255}; -int main() { +int main() { size_t array_len = 10; void *array = malloc(array_len); diff --git a/tests/regression/56-witness/50-witness-lifter-fp1.c b/tests/regression/56-witness/50-witness-lifter-fp1.c index 8c6e45e648..1db839cd7b 100644 --- a/tests/regression/56-witness/50-witness-lifter-fp1.c +++ b/tests/regression/56-witness/50-witness-lifter-fp1.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.sv-comp.enabled --enable ana.sv-comp.functions --set ana.specification 'CHECK( init(main()), LTL(G ! call(reach_error())) )' --enable ana.int.interval -// previously fixpoint not reached +// FIXPOINT: previously fixpoint not reached // extracted from sv-benchmarks loops-crafted-1/loopv2 int SIZE = 50000001; int __VERIFIER_nondet_int(); From f1ca09d68762c4453cef00f6211d504d370feb18 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 12:53:51 +0300 Subject: [PATCH 012/689] Add cram tests for manual checks --- .../63-access-threadspawn-lval.c | 1 + .../63-access-threadspawn-lval.t | 25 +++++++++++++++++++ .../13-privatized/64-access-invalidate.c | 1 + .../13-privatized/64-access-invalidate.t | 22 ++++++++++++++++ tests/regression/41-stdlib/03-noqsort.t | 8 ++++++ tests/regression/41-stdlib/dune | 2 ++ 6 files changed, 59 insertions(+) create mode 100644 tests/regression/13-privatized/63-access-threadspawn-lval.t create mode 100644 tests/regression/13-privatized/64-access-invalidate.t create mode 100644 tests/regression/41-stdlib/03-noqsort.t create mode 100644 tests/regression/41-stdlib/dune diff --git a/tests/regression/13-privatized/63-access-threadspawn-lval.c b/tests/regression/13-privatized/63-access-threadspawn-lval.c index 7f98b129ab..9ebd29a89d 100644 --- a/tests/regression/13-privatized/63-access-threadspawn-lval.c +++ b/tests/regression/13-privatized/63-access-threadspawn-lval.c @@ -1,3 +1,4 @@ +// CRAM #include pthread_t id1; diff --git a/tests/regression/13-privatized/63-access-threadspawn-lval.t b/tests/regression/13-privatized/63-access-threadspawn-lval.t new file mode 100644 index 0000000000..8639d69fe3 --- /dev/null +++ b/tests/regression/13-privatized/63-access-threadspawn-lval.t @@ -0,0 +1,25 @@ +Should have (safe) write accesses to id1 and id2: + + $ goblint --enable allglobs 63-access-threadspawn-lval.c + [Error][Imprecise][Unsound] Function definition missing for magic2 (63-access-threadspawn-lval.c:21:3-21:12) + [Info][Imprecise] INVALIDATING ALL GLOBALS! (63-access-threadspawn-lval.c:21:3-21:12) + [Info][Imprecise] Invalidating expressions: AddrOf(Var(A, + NoOffset)), AddrOf(Var(id2, NoOffset)), AddrOf(Var(id1, NoOffset)), AddrOf(Var(e, NoOffset)) (63-access-threadspawn-lval.c:21:3-21:12) + [Error][Imprecise][Unsound] Function definition missing for magic1 (63-access-threadspawn-lval.c:13:3-13:11) + [Info][Imprecise] INVALIDATING ALL GLOBALS! (63-access-threadspawn-lval.c:13:3-13:11) + [Info][Imprecise] Invalidating expressions: AddrOf(Var(A, NoOffset)), AddrOf(Var(id2, NoOffset)), AddrOf(Var(id1, NoOffset)) (63-access-threadspawn-lval.c:13:3-13:11) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 13 + dead: 0 + total: 13 + [Success][Race] Memory location id1@63-access-threadspawn-lval.c:4:11-4:14 (safe): + write with [mhp:{tid=[main]}, + multi:false, thread:[main]] (conf. 110) (63-access-threadspawn-lval.c:27:3-27:37) + [Success][Race] Memory location id2@63-access-threadspawn-lval.c:5:11-5:14 (safe): + write with [mhp:{tid=[main]; created={[main, f@63-access-threadspawn-lval.c:27:3-27:37]}}, thread:[main]] (conf. 110) (63-access-threadspawn-lval.c:28:3-28:37) + write with [mhp:{tid=[main]; created={[main, f@63-access-threadspawn-lval.c:27:3-27:37]}}, thread:[main]] (conf. 110) (63-access-threadspawn-lval.c:28:3-28:37) + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total: 2 diff --git a/tests/regression/13-privatized/64-access-invalidate.c b/tests/regression/13-privatized/64-access-invalidate.c index 7a191a9650..1461d413e2 100644 --- a/tests/regression/13-privatized/64-access-invalidate.c +++ b/tests/regression/13-privatized/64-access-invalidate.c @@ -1,3 +1,4 @@ +// CRAM #include pthread_t id; diff --git a/tests/regression/13-privatized/64-access-invalidate.t b/tests/regression/13-privatized/64-access-invalidate.t new file mode 100644 index 0000000000..94613b1bbf --- /dev/null +++ b/tests/regression/13-privatized/64-access-invalidate.t @@ -0,0 +1,22 @@ +Should have (safe) write access to id1 and magic2 invalidate to A: + + $ goblint --enable allglobs 64-access-invalidate.c + [Error][Imprecise][Unsound] Function definition missing for magic2 (64-access-invalidate.c:16:3-16:12) + [Info][Imprecise] INVALIDATING ALL GLOBALS! (64-access-invalidate.c:16:3-16:12) + [Info][Imprecise] Invalidating expressions: AddrOf(Var(A, + NoOffset)), AddrOf(Var(id, NoOffset)), AddrOf(Var(e, NoOffset)) (64-access-invalidate.c:16:3-16:12) + [Error][Imprecise][Unsound] Function definition missing for magic1 (64-access-invalidate.c:12:3-12:11) + [Info][Imprecise] INVALIDATING ALL GLOBALS! (64-access-invalidate.c:12:3-12:11) + [Info][Imprecise] Invalidating expressions: AddrOf(Var(A, NoOffset)), AddrOf(Var(id, NoOffset)) (64-access-invalidate.c:12:3-12:11) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 10 + dead: 0 + total: 10 + [Success][Race] Memory location id@64-access-invalidate.c:4:11-4:13 (safe): + write with [mhp:{tid=[main]}, + multi:false, thread:[main]] (conf. 110) (64-access-invalidate.c:21:3-21:36) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total: 1 diff --git a/tests/regression/41-stdlib/03-noqsort.t b/tests/regression/41-stdlib/03-noqsort.t new file mode 100644 index 0000000000..689906659f --- /dev/null +++ b/tests/regression/41-stdlib/03-noqsort.t @@ -0,0 +1,8 @@ +There should be no CIL warning about multiple definitions: + + $ goblint --set pre.cppflags[+] -DGOBLINT_NO_QSORT 03-noqsort.c + [Warning][Deadcode] Function 'qsort' is uncalled: 1 LLoC (03-noqsort.c:5:1-6:1) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 2 + dead: 1 (1 in uncalled functions) + total: 3 diff --git a/tests/regression/41-stdlib/dune b/tests/regression/41-stdlib/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/41-stdlib/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) From 7b3a3ec96299f3cd4dbe287b8391028cbcfeb652 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 13:40:19 +0300 Subject: [PATCH 013/689] Hide getdate_err from MacOS output --- src/framework/control.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/framework/control.ml b/src/framework/control.ml index 6159f1a936..3a3e86c596 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -215,6 +215,7 @@ struct let is_std = function | {vname = ("__tzname" | "__daylight" | "__timezone"); _} (* unix time.h *) | {vname = ("tzname" | "daylight" | "timezone"); _} (* unix time.h *) + | {vname = "getdate_err"; _} (* unix time.h (only on MacOS?) *) | {vname = ("stdin" | "stdout" | "stderr"); _} -> (* standard stdio.h *) true | _ -> false From 05429139cdeccac0b2cadb12e16c327e5df091f0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 16:34:22 +0300 Subject: [PATCH 014/689] Add test for broken mutex contents hiding on MacOS --- .../03-practical/28-base-mutex-macos.c | 20 +++++++++++++++++++ .../03-practical/28-base-mutex-macos.t | 13 ++++++++++++ tests/regression/03-practical/dune | 2 ++ 3 files changed, 35 insertions(+) create mode 100644 tests/regression/03-practical/28-base-mutex-macos.c create mode 100644 tests/regression/03-practical/28-base-mutex-macos.t create mode 100644 tests/regression/03-practical/dune diff --git a/tests/regression/03-practical/28-base-mutex-macos.c b/tests/regression/03-practical/28-base-mutex-macos.c new file mode 100644 index 0000000000..4f4dc417fc --- /dev/null +++ b/tests/regression/03-practical/28-base-mutex-macos.c @@ -0,0 +1,20 @@ +// Intentionally no #include , because we want to imitate/debug MacOS construction on anything. + +#define __PTHREAD_MUTEX_SIZE__ 56 + +struct _opaque_pthread_mutex_t { + long __sig; + char __opaque[__PTHREAD_MUTEX_SIZE__]; +}; + +typedef struct _opaque_pthread_mutex_t __darwin_pthread_mutex_t; +typedef __darwin_pthread_mutex_t pthread_mutex_t; + +#define _PTHREAD_MUTEX_SIG_init 0x32AAABA7 +#define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}} + +pthread_mutex_t A = PTHREAD_MUTEX_INITIALIZER; + +int main() { + return 0; +} diff --git a/tests/regression/03-practical/28-base-mutex-macos.t b/tests/regression/03-practical/28-base-mutex-macos.t new file mode 100644 index 0000000000..dd7f3f5ca0 --- /dev/null +++ b/tests/regression/03-practical/28-base-mutex-macos.t @@ -0,0 +1,13 @@ + $ goblint --enable witness.yaml.enabled --disable witness.invariant.accessed --set pre.cppflags[+] -DGOBLINT_NO_PTHREAD_ONCE 28-base-mutex-macos.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 2 + dead: 0 + total: 2 + [Info][Witness] witness generation summary: + total: 0 + +There should be no invariants about __sig. +Base analysis should hide mutex contents. + + $ yamlWitnessStrip < witness.yml + [] diff --git a/tests/regression/03-practical/dune b/tests/regression/03-practical/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/03-practical/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) From 7d9de044479fcecfefa20a91cedf37f0aa9b3b1e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Oct 2022 16:47:18 +0300 Subject: [PATCH 015/689] Fix 03-practical/28-base-mutex-macos --- src/analyses/base.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 2fec3d7500..e2855363af 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2151,7 +2151,7 @@ struct | _ -> () ); match lval with (* this section ensure global variables contain bottom values of the proper type before setting them *) - | (Var v, offs) when AD.is_definite lval_val && v.vglob -> + | (Var v, offs) when v.vglob -> (* Optimization: In case of simple integral types, we not need to evaluate the old value. v is not an allocated block, as v directly appears as a variable in the program; so no explicit check is required here (unlike in set) *) @@ -2163,14 +2163,14 @@ struct in begin match current_val with | `Bot -> (* current value is VD `Bot *) - begin match Addr.to_var_offset (AD.choose lval_val) with - | Some (x,offs) -> + begin match AD.to_var_offset lval_val with + | [(x,offs)] -> let t = v.vtype in let iv = VD.bot_value t in (* correct bottom value for top level variable *) - if M.tracing then M.tracel "set" "init bot value: %a\n" VD.pretty iv; + if M.tracing then M.tracel "set" "init bot value (%a): %a\n" d_plaintype t VD.pretty iv; let nv = VD.update_offset (Analyses.ask_of_ctx ctx) iv offs rval_val (Some (Lval lval)) lval t in (* do desired update to value *) set_savetop ~ctx (Analyses.ask_of_ctx ctx) ctx.global ctx.local (AD.from_var v) lval_t nv ~lval_raw:lval ~rval_raw:rval (* set top-level variable to updated value *) - | None -> + | _ -> set_savetop ~ctx (Analyses.ask_of_ctx ctx) ctx.global ctx.local lval_val lval_t rval_val ~lval_raw:lval ~rval_raw:rval end | _ -> From f49fd11c9e54920ac5ff520fad5aeb3b72aa1ffa Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 7 Oct 2022 10:43:37 +0300 Subject: [PATCH 016/689] Add cram tests for CFG --- tests/regression/00-sanity/19-if-0.t | 27 +++ tests/regression/00-sanity/20-if-0-realnode.c | 1 + tests/regression/00-sanity/20-if-0-realnode.t | 25 ++ tests/regression/00-sanity/21-empty-loops.c | 1 + tests/regression/00-sanity/21-empty-loops.t | 215 ++++++++++++++++++ 5 files changed, 269 insertions(+) create mode 100644 tests/regression/00-sanity/19-if-0.t create mode 100644 tests/regression/00-sanity/20-if-0-realnode.t create mode 100644 tests/regression/00-sanity/21-empty-loops.t diff --git a/tests/regression/00-sanity/19-if-0.t b/tests/regression/00-sanity/19-if-0.t new file mode 100644 index 0000000000..8aa27f87f1 --- /dev/null +++ b/tests/regression/00-sanity/19-if-0.t @@ -0,0 +1,27 @@ + $ goblint --enable exp.cfgdot 19-if-0.c + [Success][Assert] Assertion "1" will succeed (19-if-0.c:15:9-15:27) + [Warning][Deadcode] Function 'stuff' is uncalled: 1 LLoC (19-if-0.c:3:1-5:1) + [Warning][Deadcode] Function 'main' has dead code: + on line 11 (19-if-0.c:11-11) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 4 + dead: 2 (1 in uncalled functions) + total: 6 + [Warning][Deadcode][CWE-570] condition '0' is always false (19-if-0.c:9:9-9:10) + + $ cat cfgs/19-if-0.c/main.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 83 -> ret1669 [label = "return 0"] ; + 82 -> 83 [label = "__goblint_check(1)"] ; + 80 -> 83 [label = "stuff()"] ; + 78 -> 82 [label = "Neg(0)"] ; + fun1669 -> 78 [label = "(body)"] ; + 78 -> 80 [label = "Pos(0)"] ; + fun1669 [label="main()",shape=box]; + ret1669 [label="return of main()",shape=box]; + 78 [shape=diamond]; + 80 [fillcolor=orange]; + 82 []; + 83 []; + } diff --git a/tests/regression/00-sanity/20-if-0-realnode.c b/tests/regression/00-sanity/20-if-0-realnode.c index ebde535270..0e7e6f662f 100644 --- a/tests/regression/00-sanity/20-if-0-realnode.c +++ b/tests/regression/00-sanity/20-if-0-realnode.c @@ -1,3 +1,4 @@ +// CRAM #include void stuff() { diff --git a/tests/regression/00-sanity/20-if-0-realnode.t b/tests/regression/00-sanity/20-if-0-realnode.t new file mode 100644 index 0000000000..af48e4402c --- /dev/null +++ b/tests/regression/00-sanity/20-if-0-realnode.t @@ -0,0 +1,25 @@ + $ goblint --enable exp.cfgdot 20-if-0-realnode.c + [Warning][Deadcode] Function 'stuff' is uncalled: 1 LLoC (20-if-0-realnode.c:4:1-6:1) + [Warning][Deadcode] Function 'main' has dead code: + on line 13 (20-if-0-realnode.c:13-13) + on line 18 (20-if-0-realnode.c:18-18) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 2 + dead: 3 (1 in uncalled functions) + total: 5 + [Warning][Deadcode][CWE-570] condition '0' is always false (20-if-0-realnode.c:11:9-11:10) + + $ cat cfgs/20-if-0-realnode.c/main.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 82 -> ret1669 [label = "return 0"] ; + 80 -> 82 [label = "stuff()"] ; + 78 -> 80 [label = "Pos(0)"] ; + 78 -> 78 [label = "Neg(0)"] ; + fun1669 -> 78 [label = "(body)"] ; + fun1669 [label="main()",shape=box]; + ret1669 [label="return of main()",shape=box,fillcolor=orange]; + 78 [shape=diamond]; + 80 [fillcolor=orange]; + 82 [fillcolor=orange]; + } diff --git a/tests/regression/00-sanity/21-empty-loops.c b/tests/regression/00-sanity/21-empty-loops.c index f3f0feb2e5..220e5bf6e9 100644 --- a/tests/regression/00-sanity/21-empty-loops.c +++ b/tests/regression/00-sanity/21-empty-loops.c @@ -1,3 +1,4 @@ +// CRAM int main() { // non-deterministically make all variants live diff --git a/tests/regression/00-sanity/21-empty-loops.t b/tests/regression/00-sanity/21-empty-loops.t new file mode 100644 index 0000000000..8dad2ae3f1 --- /dev/null +++ b/tests/regression/00-sanity/21-empty-loops.t @@ -0,0 +1,215 @@ + $ goblint --enable exp.cfgdot 21-empty-loops.c + [Warning][Deadcode] Function 'suffix' is uncalled: 1 LLoC (21-empty-loops.c:66:1-69:1) + [Warning][Deadcode] Function 'f_empty_goto_loop_suffix' has dead code: + on line 76 (21-empty-loops.c:76-76) + [Warning][Deadcode] Function 'f_empty_while_loop' has dead code: + on line 64 (21-empty-loops.c:64-64) + [Warning][Deadcode] Function 'f_empty_while_loop_prefix' has dead code: + on line 124 (21-empty-loops.c:124-124) + [Warning][Deadcode] Function 'f_empty_while_loop_semicolon' has dead code: + on line 139 (21-empty-loops.c:139-139) + [Warning][Deadcode] Function 'f_empty_while_loop_suffix' has dead code: + on lines 83..84 (21-empty-loops.c:83-84) + [Warning][Deadcode] Function 'f_nonempty_while_loop' has dead code: + on line 104 (21-empty-loops.c:104-104) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 65 + dead: 8 (1 in uncalled functions) + total: 73 + [Warning][Deadcode][CWE-571] condition '1' is always true (21-empty-loops.c:63:10-63:11) + [Warning][Deadcode][CWE-571] condition '1' is always true (21-empty-loops.c:81:10-81:11) + [Warning][Deadcode][CWE-571] condition '1' is always true (21-empty-loops.c:100:10-100:11) + [Warning][Deadcode][CWE-571] condition '1' is always true (21-empty-loops.c:123:10-123:11) + [Warning][Deadcode][CWE-571] condition '1' is always true (21-empty-loops.c:136:10-136:11) + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10966185866 -> ret1667 [label = "return"] ; + 151 -> 10966185866 [label = "Neg(1)"] ; + 151 -> 151 [label = "skip"] ; + fun1667 -> 151 [label = "(body)"] ; + 10966185866 [fillcolor=orange]; + 151 []; + fun1667 [label="f_empty_goto_loop()",shape=box]; + ret1667 [label="return of f_empty_goto_loop()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_while_loop.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 158 -> ret1668 [label = "return"] ; + 155 -> 158 [label = "Neg(1)"] ; + 155 -> 155 [label = "Pos(1)"] ; + fun1668 -> 155 [label = "(body)"] ; + 155 [shape=diamond]; + 158 [fillcolor=orange]; + fun1668 [label="f_empty_while_loop()",shape=box]; + ret1668 [label="return of f_empty_while_loop()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_suffix.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10494758249 -> ret1669 [label = "return"] ; + 160 -> 10494758249 [label = "Neg(1)"] ; + 162 -> 10494758249 [label = "suffix()"] ; + 160 -> 160 [label = "skip"] ; + fun1669 -> 160 [label = "(body)"] ; + 160 []; + 162 [fillcolor=orange]; + fun1669 [label="f_empty_goto_loop_suffix()",shape=box]; + ret1669 [label="return of f_empty_goto_loop_suffix()",shape=box,fillcolor=orange]; + 10494758249 [fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_while_loop_suffix.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 171 -> ret1670 [label = "return"] ; + 170 -> 171 [label = "suffix()"] ; + 166 -> 170 [label = "Neg(1)"] ; + 166 -> 166 [label = "Pos(1)"] ; + fun1670 -> 166 [label = "(body)"] ; + fun1670 [label="f_empty_while_loop_suffix()",shape=box]; + 166 [shape=diamond]; + 170 [fillcolor=orange]; + 171 [fillcolor=orange]; + ret1670 [label="return of f_empty_while_loop_suffix()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_nonempty_goto_loop.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10142820772 -> ret1671 [label = "return"] ; + 174 -> 10142820772 [label = "Neg(1)"] ; + 174 -> 174 [label = "body()"] ; + fun1671 -> 174 [label = "(body)"] ; + 10142820772 [fillcolor=orange]; + fun1671 [label="f_nonempty_goto_loop()",shape=box]; + 174 []; + ret1671 [label="return of f_nonempty_goto_loop()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_nonempty_while_loop.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 184 -> ret1672 [label = "return"] ; + 179 -> 184 [label = "Neg(1)"] ; + 182 -> 179 [label = "body()"] ; + fun1672 -> 179 [label = "(body)"] ; + 179 -> 182 [label = "Pos(1)"] ; + fun1672 [label="f_nonempty_while_loop()",shape=box]; + 179 [shape=diamond]; + 182 []; + 184 [fillcolor=orange]; + ret1672 [label="return of f_nonempty_while_loop()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_prefix.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10451917286 -> ret1673 [label = "return"] ; + 188 -> 10451917286 [label = "Neg(1)"] ; + 188 -> 188 [label = "skip"] ; + 187 -> 188 [label = "prefix()"] ; + fun1673 -> 187 [label = "(body)"] ; + fun1673 [label="f_empty_goto_loop_prefix()",shape=box]; + 187 []; + 188 []; + ret1673 [label="return of f_empty_goto_loop_prefix()",shape=box,fillcolor=orange]; + 10451917286 [fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_while_loop_prefix.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 197 -> ret1674 [label = "return"] ; + 194 -> 197 [label = "Neg(1)"] ; + 194 -> 194 [label = "Pos(1)"] ; + 190 -> 194 [label = "prefix()"] ; + fun1674 -> 190 [label = "(body)"] ; + fun1674 [label="f_empty_while_loop_prefix()",shape=box]; + 190 []; + 194 [shape=diamond]; + 197 [fillcolor=orange]; + ret1674 [label="return of f_empty_while_loop_prefix()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_semicolon.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10404769065 -> ret1675 [label = "return"] ; + 198 -> 10404769065 [label = "Neg(1)"] ; + 198 -> 198 [label = "skip"] ; + fun1675 -> 198 [label = "(body)"] ; + 10404769065 [fillcolor=orange]; + fun1675 [label="f_empty_goto_loop_semicolon()",shape=box]; + 198 []; + ret1675 [label="return of f_empty_goto_loop_semicolon()",shape=box,fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_while_loop_semicolon.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 206 -> ret1676 [label = "return"] ; + 203 -> 206 [label = "Neg(1)"] ; + 203 -> 203 [label = "Pos(1)"] ; + fun1676 -> 203 [label = "(body)"] ; + fun1676 [label="f_empty_while_loop_semicolon()",shape=box]; + ret1676 [label="return of f_empty_while_loop_semicolon()",shape=box,fillcolor=orange]; + 203 [shape=diamond]; + 206 [fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_multiple.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10218149751 -> ret1677 [label = "return"] ; + 207 -> 10218149751 [label = "Neg(1)"] ; + 207 -> 207 [label = "skip"] ; + fun1677 -> 207 [label = "(body)"] ; + fun1677 [label="f_empty_goto_loop_multiple()",shape=box]; + ret1677 [label="return of f_empty_goto_loop_multiple()",shape=box,fillcolor=orange]; + 207 []; + 10218149751 [fillcolor=orange]; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_multiple_semicolon_first.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10606643600 -> ret1678 [label = "return"] ; + 209 -> 10606643600 [label = "Neg(1)"] ; + 209 -> 209 [label = "skip"] ; + fun1678 -> 209 [label = "(body)"] ; + 10606643600 [fillcolor=orange]; + fun1678 [label="f_empty_goto_loop_multiple_semicolon_first()",shape=box]; + ret1678 [label="return of f_empty_goto_loop_multiple_semicolon_first()",shape=box,fillcolor=orange]; + 209 []; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_multiple_semicolon_second.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10984714377 -> ret1679 [label = "return"] ; + 212 -> 10984714377 [label = "Neg(1)"] ; + 212 -> 212 [label = "skip"] ; + fun1679 -> 212 [label = "(body)"] ; + 10984714377 [fillcolor=orange]; + fun1679 [label="f_empty_goto_loop_multiple_semicolon_second()",shape=box]; + ret1679 [label="return of f_empty_goto_loop_multiple_semicolon_second()",shape=box,fillcolor=orange]; + 212 []; + } + + $ cat cfgs/21-empty-loops.c/f_empty_goto_loop_multiple_semicolon_both.dot + digraph cfg { + node [id="\N",URL="javascript:show_info('\N');",style=filled,fillcolor=white]; + 10253493141 -> ret1680 [label = "return"] ; + 215 -> 10253493141 [label = "Neg(1)"] ; + 215 -> 215 [label = "skip"] ; + fun1680 -> 215 [label = "(body)"] ; + 10253493141 [fillcolor=orange]; + fun1680 [label="f_empty_goto_loop_multiple_semicolon_both()",shape=box]; + ret1680 [label="return of f_empty_goto_loop_multiple_semicolon_both()",shape=box,fillcolor=orange]; + 215 []; + } From b38e7a98689a2b1b84efbe829c52e30ae64f18da Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:15:23 +0300 Subject: [PATCH 017/689] Add ppx_deriving_lattice using ppx_easy_deriving --- dune-project | 1 + goblint.opam | 2 + goblint.opam.locked | 22 ++++-- goblint.opam.template | 1 + src/dune | 2 +- src/ppx/lattice/dune | 8 ++ src/ppx/lattice/ppx_deriving_lattice.ml | 97 +++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 src/ppx/lattice/dune create mode 100644 src/ppx/lattice/ppx_deriving_lattice.ml diff --git a/dune-project b/dune-project index 2fbfb271fc..903148201e 100644 --- a/dune-project +++ b/dune-project @@ -32,6 +32,7 @@ ppx_deriving ppx_deriving_hash (ppx_deriving_yojson (>= 3.7.0)) + ppx_easy_deriving (ounit2 :with-test) (qcheck-ounit :with-test) (odoc :with-doc) diff --git a/goblint.opam b/goblint.opam index 678ad53d13..4eac826d63 100644 --- a/goblint.opam +++ b/goblint.opam @@ -29,6 +29,7 @@ depends: [ "ppx_deriving" "ppx_deriving_hash" "ppx_deriving_yojson" {>= "3.7.0"} + "ppx_easy_deriving" "ounit2" {with-test} "qcheck-ounit" {with-test} "odoc" {with-doc} @@ -76,6 +77,7 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" available: os-distribution != "alpine" & arch != "arm64" pin-depends: [ [ "goblint-cil.2.0.1" "git+https://github.com/goblint/cil.git#4df989fe625d91ce07d94afe1d85b3b5c6cdd63e" ] + [ "ppx_easy_deriving.~dev" "git+https://github.com/sim642/ppx_easy_deriving.git#3d599fdfb231e4a1f9bad0e914068210901533a4" ] # 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" ] # TODO: add back after release, only pinned for CI stability diff --git a/goblint.opam.locked b/goblint.opam.locked index acb49a7b14..7fb916100b 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -50,12 +50,14 @@ depends: [ "cpu" {= "2.0.0"} "csexp" {= "1.5.1"} "ctypes" {= "0.20.1"} - "dune" {= "3.6.1"} + "dune" {= "3.8.0"} "dune-build-info" {= "3.6.1"} "dune-configurator" {= "3.6.1"} "dune-private-libs" {= "3.6.1"} "dune-site" {= "3.6.1"} "dyn" {= "3.6.1"} + "either" {= "1.0.0"} + "fileutils" {= "0.6.4"} "fmt" {= "0.9.0"} "fpath" {= "0.7.3"} "goblint-cil" {= "2.0.1"} @@ -67,11 +69,11 @@ depends: [ "mlgmpidl" {= "1.2.14"} "num" {= "1.4"} "ocaml" {= "4.14.0"} - "ocaml-variants" {= "4.14.0+options"} "ocaml-compiler-libs" {= "v0.12.4"} "ocaml-config" {= "2"} "ocaml-option-flambda" {= "1"} "ocaml-syntax-shims" {= "1.0.0"} + "ocaml-variants" {= "4.14.0+options"} "ocamlbuild" {= "0.14.2"} "ocamlfind" {= "1.9.5"} "odoc" {= "2.2.0" & with-doc} @@ -83,7 +85,8 @@ depends: [ "ppx_deriving" {= "5.2.1"} "ppx_deriving_hash" {= "0.1.1"} "ppx_deriving_yojson" {= "3.7.0"} - "ppxlib" {= "0.28.0"} + "ppx_easy_deriving" {= "~dev"} + "ppxlib" {= "0.30.0"} "qcheck-core" {= "0.20"} "qcheck-ounit" {= "0.20" & with-test} "re" {= "1.10.4" & with-doc} @@ -127,16 +130,21 @@ conflicts: [ ] # TODO: manually reordered to avoid opam pin crash: https://github.com/ocaml/opam/issues/4936 pin-depends: [ - [ - "goblint-cil.2.0.1" - "git+https://github.com/goblint/cil.git#4df989fe625d91ce07d94afe1d85b3b5c6cdd63e" - ] [ "apron.v0.9.13" "git+https://github.com/antoinemine/apron.git#1a8e91062c0d7d1e80333d19d5a432332bbbaec8" ] + [ + "goblint-cil.2.0.1" + "git+https://github.com/goblint/cil.git#4df989fe625d91ce07d94afe1d85b3b5c6cdd63e" + ] [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ] + [ + "ppx_easy_deriving.~dev" + "git+ssh://git@github.com/sim642/ppx_easy_deriving.git#master" +] ] + diff --git a/goblint.opam.template b/goblint.opam.template index b7f5a7abff..72855dd72e 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -3,6 +3,7 @@ available: os-distribution != "alpine" & arch != "arm64" pin-depends: [ [ "goblint-cil.2.0.1" "git+https://github.com/goblint/cil.git#4df989fe625d91ce07d94afe1d85b3b5c6cdd63e" ] + [ "ppx_easy_deriving.~dev" "git+https://github.com/sim642/ppx_easy_deriving.git#3d599fdfb231e4a1f9bad0e914068210901533a4" ] # 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" ] # TODO: add back after release, only pinned for CI stability diff --git a/src/dune b/src/dune index 85944375ea..1ab30920e1 100644 --- a/src/dune +++ b/src/dune @@ -59,7 +59,7 @@ (foreign_stubs (language c) (names stubs)) (ocamlopt_flags :standard -no-float-const-prop) (preprocess - (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson ppx_blob)) + (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson ppx_blob ppx_deriving_lattice)) (preprocessor_deps (file util/options.schema.json)) (instrumentation (backend bisect_ppx)) ) diff --git a/src/ppx/lattice/dune b/src/ppx/lattice/dune new file mode 100644 index 0000000000..4c057c6fab --- /dev/null +++ b/src/ppx/lattice/dune @@ -0,0 +1,8 @@ +(include_subdirs no) + +(library + (name ppx_deriving_lattice) + (kind ppx_deriver) + (libraries ppxlib ppx_easy_deriving) + (ppx_runtime_libraries ppx_easy_deriving.runtime) + (preprocess (pps ppxlib.metaquot))) diff --git a/src/ppx/lattice/ppx_deriving_lattice.ml b/src/ppx/lattice/ppx_deriving_lattice.ml new file mode 100644 index 0000000000..e78e88644a --- /dev/null +++ b/src/ppx/lattice/ppx_deriving_lattice.ml @@ -0,0 +1,97 @@ +open Ppxlib +open Ppx_easy_deriving + +module LeqArg: Product.Reduce.Conjunctive.S = +struct + let name = "leq" +end + +module LeqDeriver = Deriver.Make (Product.Reduce2.Make (Product.Reduce.Conjunctive.Make (LeqArg))) +let leq_deriving = LeqDeriver.register () + + +module JoinArg: Product.Map2.S = +struct + let name = "join" +end + +module JoinDeriver = Deriver.Make (Product.Map2.Make (JoinArg)) +let join_deriving = JoinDeriver.register () + + +module MeetArg: Product.Map2.S = +struct + let name = "meet" +end + +module MeetDeriver = Deriver.Make (Product.Map2.Make (MeetArg)) +let meet_deriving = MeetDeriver.register () + + +module WidenArg: Product.Map2.S = +struct + let name = "widen" +end + +module WidenDeriver = Deriver.Make (Product.Map2.Make (WidenArg)) +let widen_deriving = WidenDeriver.register () + + +module NarrowArg: Product.Map2.S = +struct + let name = "narrow" +end + +module NarrowDeriver = Deriver.Make (Product.Map2.Make (NarrowArg)) +let narrow_deriving = NarrowDeriver.register () + + +module BotArg: Product.Create.S = +struct + let name = "bot" + let typ ~loc _ = [%type: unit] +end + +module BotDeriver = Deriver.Make (Product.Create.Make (BotArg)) +let bot_deriving = BotDeriver.register () + + +module IsBotArg: Product.Reduce.Conjunctive.S = +struct + let name = "is_bot" +end + +module IsBotDeriver = Deriver.Make (Product.Reduce1.Make (Product.Reduce.Conjunctive.Make (IsBotArg))) +let is_bot_deriving = IsBotDeriver.register () + + +module TopArg: Product.Create.S = +struct + let name = "top" + let typ ~loc _ = [%type: unit] +end + +module TopDeriver = Deriver.Make (Product.Create.Make (TopArg)) +let top_deriving = TopDeriver.register () + + +module IsTopArg: Product.Reduce.Conjunctive.S = +struct + let name = "is_top" +end + +module IsTopDeriver = Deriver.Make (Product.Reduce1.Make (Product.Reduce.Conjunctive.Make (IsTopArg))) +let is_top_deriving = IsTopDeriver.register () + + +let _ = Ppxlib.Deriving.add_alias "lattice" [ + leq_deriving; + join_deriving; + meet_deriving; + widen_deriving; + narrow_deriving; + bot_deriving; + is_bot_deriving; + top_deriving; + is_top_deriving; + ] From a4ef64ec4a44058c6f46131ac9e5f266124d6780 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 12 May 2021 11:44:48 +0300 Subject: [PATCH 018/689] Use lattice deriver for Lattice.ProdConf --- src/domains/lattice.ml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/domains/lattice.ml b/src/domains/lattice.ml index 4cdaa8fb9f..0147939413 100644 --- a/src/domains/lattice.ml +++ b/src/domains/lattice.ml @@ -409,27 +409,17 @@ end module ProdConf (C: Printable.ProdConfiguration) (Base1: S) (Base2: S) = struct - include Printable.ProdConf (C) (Base1) (Base2) - - let bot () = (Base1.bot (), Base2.bot ()) - let is_bot (x1,x2) = Base1.is_bot x1 && Base2.is_bot x2 - let top () = (Base1.top (), Base2.top ()) - let is_top (x1,x2) = Base1.is_top x1 && Base2.is_top x2 - - let leq (x1,x2) (y1,y2) = Base1.leq x1 y1 && Base2.leq x2 y2 + open struct (* open to avoid leaking P and causing conflicts *) + module P = Printable.ProdConf (C) (Base1) (Base2) + end + type t = Base1.t * Base2.t [@@deriving lattice] + include (P: module type of P with type t := t) let pretty_diff () ((x1,x2:t),(y1,y2:t)): Pretty.doc = if Base1.leq x1 y1 then Base2.pretty_diff () (x2,y2) else Base1.pretty_diff () (x1,y1) - - let op_scheme op1 op2 (x1,x2) (y1,y2): t = (op1 x1 y1, op2 x2 y2) - let join = op_scheme Base1.join Base2.join - let meet = op_scheme Base1.meet Base2.meet - let narrow = op_scheme Base1.narrow Base2.narrow - let widen = op_scheme Base1.widen Base2.widen - end From 35fe676dd6af8424ecca1a0f25181ac71adf8400 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 12 May 2021 11:46:10 +0300 Subject: [PATCH 019/689] Use lattice deriver for Lattice.Prod3 --- src/domains/lattice.ml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/domains/lattice.ml b/src/domains/lattice.ml index 0147939413..2ed13ad385 100644 --- a/src/domains/lattice.ml +++ b/src/domains/lattice.ml @@ -428,14 +428,11 @@ module ProdSimple = ProdConf (struct let expand_fst = false let expand_snd = fal module Prod3 (Base1: S) (Base2: S) (Base3: S) = struct - include Printable.Prod3 (Base1) (Base2) (Base3) - - let bot () = (Base1.bot (), Base2.bot (), Base3.bot ()) - let is_bot (x1,x2,x3) = Base1.is_bot x1 && Base2.is_bot x2 && Base3.is_bot x3 - let top () = (Base1.top (), Base2.top (), Base3.top ()) - let is_top (x1,x2,x3) = Base1.is_top x1 && Base2.is_top x2 && Base3.is_top x3 - - let leq (x1,x2,x3) (y1,y2,y3) = Base1.leq x1 y1 && Base2.leq x2 y2 && Base3.leq x3 y3 + open struct (* open to avoid leaking P and causing conflicts *) + module P = Printable.Prod3 (Base1) (Base2) (Base3) + end + type t = Base1.t * Base2.t * Base3.t [@@deriving lattice] + include (P: module type of P with type t := t) let pretty_diff () ((x1,x2,x3:t),(y1,y2,y3:t)): Pretty.doc = if not (Base1.leq x1 y1) then @@ -444,12 +441,6 @@ struct Base2.pretty_diff () (x2,y2) else Base3.pretty_diff () (x3,y3) - - let op_scheme op1 op2 op3 (x1,x2,x3) (y1,y2,y3): t = (op1 x1 y1, op2 x2 y2, op3 x3 y3) - let join = op_scheme Base1.join Base2.join Base3.join - let meet = op_scheme Base1.meet Base2.meet Base3.meet - let widen = op_scheme Base1.widen Base2.widen Base3.widen - let narrow = op_scheme Base1.narrow Base2.narrow Base3.narrow end module Prod4 (Base1: S) (Base2: S) (Base3: S) (Base4: S) = From 7989ea4d4a1bd8cf9bd721888cddba12b782bed0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:27:08 +0300 Subject: [PATCH 020/689] Remove unused Prod4 --- src/domains/lattice.ml | 27 --------------------------- src/domains/printable.ml | 29 ----------------------------- 2 files changed, 56 deletions(-) diff --git a/src/domains/lattice.ml b/src/domains/lattice.ml index 2ed13ad385..01cbf9b9cf 100644 --- a/src/domains/lattice.ml +++ b/src/domains/lattice.ml @@ -443,33 +443,6 @@ struct Base3.pretty_diff () (x3,y3) end -module Prod4 (Base1: S) (Base2: S) (Base3: S) (Base4: S) = -struct - include Printable.Prod4 (Base1) (Base2) (Base3) (Base4) - - let bot () = (Base1.bot (), Base2.bot (), Base3.bot (), Base4.bot ()) - let is_bot (x1,x2,x3,x4) = Base1.is_bot x1 && Base2.is_bot x2 && Base3.is_bot x3 && Base4.is_bot x4 - let top () = (Base1.top (), Base2.top (), Base3.top (), Base4.top ()) - let is_top (x1,x2,x3,x4) = Base1.is_top x1 && Base2.is_top x2 && Base3.is_top x3 && Base4.is_top x4 - let leq (x1,x2,x3,x4) (y1,y2,y3,y4) = Base1.leq x1 y1 && Base2.leq x2 y2 && Base3.leq x3 y3 && Base4.leq x4 y4 - - let pretty_diff () ((x1,x2,x3,x4:t),(y1,y2,y3,y4:t)): Pretty.doc = - if not (Base1.leq x1 y1) then - Base1.pretty_diff () (x1,y1) - else if not (Base2.leq x2 y2) then - Base2.pretty_diff () (x2,y2) - else if not (Base3.leq x3 y3) then - Base3.pretty_diff () (x3,y3) - else - Base4.pretty_diff () (x4,y4) - - let op_scheme op1 op2 op3 op4 (x1,x2,x3,x4) (y1,y2,y3,y4): t = (op1 x1 y1, op2 x2 y2, op3 x3 y3, op4 x4 y4) - let join = op_scheme Base1.join Base2.join Base3.join Base4.join - let meet = op_scheme Base1.meet Base2.meet Base3.meet Base4.meet - let widen = op_scheme Base1.widen Base2.widen Base3.widen Base4.widen - let narrow = op_scheme Base1.narrow Base2.narrow Base3.narrow Base4.narrow -end - module LiftBot (Base : S) = struct include Printable.LiftBot (Base) diff --git a/src/domains/printable.ml b/src/domains/printable.ml index 59d22957b4..495d294e6e 100644 --- a/src/domains/printable.ml +++ b/src/domains/printable.ml @@ -430,35 +430,6 @@ struct let arbitrary () = QCheck.triple (Base1.arbitrary ()) (Base2.arbitrary ()) (Base3.arbitrary ()) end -module Prod4 (Base1: S) (Base2: S) (Base3: S) (Base4: S) = struct - type t = Base1.t * Base2.t * Base3.t * Base4.t [@@deriving eq, ord, hash] - include Std - - let show (x,y,z,w) = "(" ^ Base1.show x ^ ", " ^ Base2.show y ^ ", " ^ Base3.show z ^ ", " ^ Base4.show w ^ ")" - - let pretty () (x,y,z,w) = - text "(" ++ - Base1.pretty () x - ++ text ", " ++ - Base2.pretty () y - ++ text ", " ++ - Base3.pretty () z - ++ text ", " ++ - Base4.pretty () w - ++ text ")" - - let printXml f (x,y,z,w) = - BatPrintf.fprintf f "\n\n\n%s\n\n%a\n%s\n\n%a\n%s\n\n%a\n%s\n\n%a\n\n" (XmlUtil.escape (Base1.name ())) Base1.printXml x (XmlUtil.escape (Base2.name ())) Base2.printXml y (XmlUtil.escape (Base3.name ())) Base3.printXml z (XmlUtil.escape (Base4.name ())) Base4.printXml w - - let to_yojson (x, y, z, w) = - `Assoc [ (Base1.name (), Base1.to_yojson x); (Base2.name (), Base2.to_yojson y); (Base3.name (), Base3.to_yojson z); (Base4.name (), Base4.to_yojson w) ] - - let name () = Base1.name () ^ " * " ^ Base2.name () ^ " * " ^ Base3.name () ^ " * " ^ Base4.name () - - let relift (x,y,z,w) = (Base1.relift x, Base2.relift y, Base3.relift z, Base4.relift w) - let arbitrary () = QCheck.quad (Base1.arbitrary ()) (Base2.arbitrary ()) (Base3.arbitrary ()) (Base4.arbitrary ()) -end - module Liszt (Base: S) = struct type t = Base.t list [@@deriving eq, ord, hash, to_yojson] From a7d42a44cc0cc3843a74a3b789889641b95a7e2b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:35:55 +0300 Subject: [PATCH 021/689] Use lattice deriver for BaseDomain.BaseComponents --- src/cdomains/baseDomain.ml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/cdomains/baseDomain.ml b/src/cdomains/baseDomain.ml index 6950c16889..e3a775020f 100644 --- a/src/cdomains/baseDomain.ml +++ b/src/cdomains/baseDomain.ml @@ -45,7 +45,7 @@ type 'a basecomponents_t = { deps: PartDeps.t; weak: WeakUpdates.t; priv: 'a; -} [@@deriving eq, ord, hash] +} [@@deriving eq, ord, hash, lattice] module BaseComponents (PrivD: Lattice.S): @@ -54,7 +54,7 @@ sig val op_scheme: (CPA.t -> CPA.t -> CPA.t) -> (PartDeps.t -> PartDeps.t -> PartDeps.t) -> (WeakUpdates.t -> WeakUpdates.t -> WeakUpdates.t) -> (PrivD.t -> PrivD.t -> PrivD.t) -> t -> t -> t end = struct - type t = PrivD.t basecomponents_t [@@deriving eq, ord, hash] + type t = PrivD.t basecomponents_t [@@deriving eq, ord, hash, lattice] include Printable.Std open Pretty @@ -97,14 +97,6 @@ struct let tr = QCheck.quad (CPA.arbitrary ()) (PartDeps.arbitrary ()) (WeakUpdates.arbitrary ()) (PrivD.arbitrary ()) in QCheck.map ~rev:to_tuple of_tuple tr - let bot () = { cpa = CPA.bot (); deps = PartDeps.bot (); weak = WeakUpdates.bot (); priv = PrivD.bot ()} - let is_bot {cpa; deps; weak; priv} = CPA.is_bot cpa && PartDeps.is_bot deps && WeakUpdates.is_bot weak && PrivD.is_bot priv - let top () = {cpa = CPA.top (); deps = PartDeps.top (); weak = WeakUpdates.top () ; priv = PrivD.bot ()} - let is_top {cpa; deps; weak; priv} = CPA.is_top cpa && PartDeps.is_top deps && WeakUpdates.is_top weak && PrivD.is_top priv - - let leq {cpa=x1; deps=x2; weak=x3; priv=x4 } {cpa=y1; deps=y2; weak=y3; priv=y4} = - CPA.leq x1 y1 && PartDeps.leq x2 y2 && WeakUpdates.leq x3 y3 && PrivD.leq x4 y4 - let pretty_diff () (({cpa=x1; deps=x2; weak=x3; priv=x4}:t),({cpa=y1; deps=y2; weak=y3; priv=y4}:t)): Pretty.doc = if not (CPA.leq x1 y1) then CPA.pretty_diff () (x1,y1) @@ -117,10 +109,6 @@ struct let op_scheme op1 op2 op3 op4 {cpa=x1; deps=x2; weak=x3; priv=x4} {cpa=y1; deps=y2; weak=y3; priv=y4}: t = {cpa = op1 x1 y1; deps = op2 x2 y2; weak = op3 x3 y3; priv = op4 x4 y4 } - let join = op_scheme CPA.join PartDeps.join WeakUpdates.join PrivD.join - let meet = op_scheme CPA.meet PartDeps.meet WeakUpdates.meet PrivD.meet - let widen = op_scheme CPA.widen PartDeps.widen WeakUpdates.widen PrivD.widen - let narrow = op_scheme CPA.narrow PartDeps.narrow WeakUpdates.narrow PrivD.narrow let relift {cpa; deps; weak; priv} = {cpa = CPA.relift cpa; deps = PartDeps.relift deps; weak = WeakUpdates.relift weak; priv = PrivD.relift priv} From 9a34f8c3a6e353053cdac5edfc7b35a978ea43f0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:37:45 +0300 Subject: [PATCH 022/689] Use lattice deriver for RelationDomain.RelComponents --- src/cdomains/apron/relationDomain.apron.ml | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/cdomains/apron/relationDomain.apron.ml b/src/cdomains/apron/relationDomain.apron.ml index c5b6a0a89b..c8942c2c6b 100644 --- a/src/cdomains/apron/relationDomain.apron.ml +++ b/src/cdomains/apron/relationDomain.apron.ml @@ -151,7 +151,7 @@ end type ('a, 'b) relcomponents_t = { rel: 'a; priv: 'b; -} [@@deriving eq, ord, hash, to_yojson] +} [@@deriving eq, ord, hash, to_yojson, lattice] module RelComponents (D3: S3) (PrivD: Lattice.S): sig @@ -160,7 +160,7 @@ sig end = struct module RD = D3 - type t = (RD.t, PrivD.t) relcomponents_t [@@deriving eq, ord, hash, to_yojson] + type t = (RD.t, PrivD.t) relcomponents_t [@@deriving eq, ord, hash, to_yojson, lattice] include Printable.Std open Pretty @@ -191,26 +191,11 @@ struct let tr = QCheck.pair (RD.arbitrary ()) (PrivD.arbitrary ()) in QCheck.map ~rev:to_tuple of_tuple tr - let bot () = {rel = RD.bot (); priv = PrivD.bot ()} - let is_bot {rel; priv} = RD.is_bot rel && PrivD.is_bot priv - let top () = {rel = RD.top (); priv = PrivD.bot ()} - let is_top {rel; priv} = RD.is_top rel && PrivD.is_top priv - - let leq {rel=x1; priv=x3 } {rel=y1; priv=y3} = - RD.leq x1 y1 && PrivD.leq x3 y3 - let pretty_diff () (({rel=x1; priv=x3}:t),({rel=y1; priv=y3}:t)): Pretty.doc = if not (RD.leq x1 y1) then RD.pretty_diff () (x1,y1) else PrivD.pretty_diff () (x3,y3) - - let op_scheme op1 op3 {rel=x1; priv=x3} {rel=y1; priv=y3}: t = - {rel = op1 x1 y1; priv = op3 x3 y3 } - let join = op_scheme RD.join PrivD.join - let meet = op_scheme RD.meet PrivD.meet - let widen = op_scheme RD.widen PrivD.widen - let narrow = op_scheme RD.narrow PrivD.narrow end From b0c207f141bc5336754ee1a479a7d7a2520cd7b3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:39:42 +0300 Subject: [PATCH 023/689] Use lattice deriver for PthreadDomain.D --- src/cdomains/pthreadDomain.ml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/cdomains/pthreadDomain.ml b/src/cdomains/pthreadDomain.ml index 8cef57bdbd..145da447f6 100644 --- a/src/cdomains/pthreadDomain.ml +++ b/src/cdomains/pthreadDomain.ml @@ -25,8 +25,7 @@ end module D = struct include Printable.StdLeaf - type domain = { tid : Tid.t; pred : Pred.t; ctx : Ctx.t } [@@deriving to_yojson] - type t = domain + type t = { tid : Tid.t; pred : Pred.t; ctx : Ctx.t } [@@deriving to_yojson, lattice] (** printing *) let show x = @@ -36,7 +35,7 @@ module D = struct (Pred.show x.pred) (Ctx.show x.ctx) - include Printable.SimpleShow(struct type t = domain let show = show end) + include Printable.SimpleShow(struct type nonrec t = t let show = show end) let name () = "pthread state" @@ -59,22 +58,11 @@ module D = struct (** let hash = Hashtbl.hash *) let hash x = Hashtbl.hash (Tid.hash x.tid, Pred.hash x.pred, Ctx.hash x.ctx) let make tid pred ctx = { tid; pred; ctx } - let bot () = { tid = Tid.bot (); pred = Pred.bot (); ctx = Ctx.bot () } - let is_bot x = Tid.is_bot x.tid && Pred.is_bot x.pred && Ctx.is_bot x.ctx let any_is_bot x = Tid.is_bot x.tid || Pred.is_bot x.pred - let top () = { tid = Tid.top (); pred = Pred.top (); ctx = Ctx.top () } - let is_top x = Tid.is_top x.tid && Pred.is_top x.pred && Ctx.is_top x.ctx - - let leq x y = Tid.leq x.tid y.tid && Pred.leq x.pred y.pred && Ctx.leq x.ctx y.ctx let op_scheme op1 op2 op3 x y : t = { tid = op1 x.tid y.tid; pred = op2 x.pred y.pred; ctx = op3 x.ctx y.ctx } - let join = op_scheme Tid.join Pred.join Ctx.join - let widen = join - let meet = op_scheme Tid.meet Pred.meet Ctx.meet - let narrow = meet - let pretty_diff () (x,y) = if not (Tid.leq x.tid y.tid) then Tid.pretty_diff () (x.tid,y.tid) From a96262ef23ac2c8a7611327eb27ee65377fcfd5a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:41:00 +0300 Subject: [PATCH 024/689] Use more derivers for PthreadDomain.D --- src/cdomains/pthreadDomain.ml | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/cdomains/pthreadDomain.ml b/src/cdomains/pthreadDomain.ml index 145da447f6..7bed37a267 100644 --- a/src/cdomains/pthreadDomain.ml +++ b/src/cdomains/pthreadDomain.ml @@ -25,7 +25,7 @@ end module D = struct include Printable.StdLeaf - type t = { tid : Tid.t; pred : Pred.t; ctx : Ctx.t } [@@deriving to_yojson, lattice] + type t = { tid : Tid.t; pred : Pred.t; ctx : Ctx.t } [@@deriving eq, ord, hash, to_yojson, lattice] (** printing *) let show x = @@ -35,34 +35,16 @@ module D = struct (Pred.show x.pred) (Ctx.show x.ctx) - include Printable.SimpleShow(struct type nonrec t = t let show = show end) + include Printable.SimpleShow (struct + type nonrec t = t + let show = show + end) let name () = "pthread state" - (** let equal = Util.equals *) - let equal x y = - Tid.equal x.tid y.tid && Pred.equal x.pred y.pred && Ctx.equal x.ctx y.ctx - - - (** compare all fields with correspoding compare operators *) - let compare x y = - List.fold_left - (fun acc v -> if acc = 0 && v <> 0 then v else acc) - 0 - [ Tid.compare x.tid y.tid - ; Pred.compare x.pred y.pred - ; Ctx.compare x.ctx y.ctx - ] - - - (** let hash = Hashtbl.hash *) - let hash x = Hashtbl.hash (Tid.hash x.tid, Pred.hash x.pred, Ctx.hash x.ctx) let make tid pred ctx = { tid; pred; ctx } let any_is_bot x = Tid.is_bot x.tid || Pred.is_bot x.pred - let op_scheme op1 op2 op3 x y : t = - { tid = op1 x.tid y.tid; pred = op2 x.pred y.pred; ctx = op3 x.ctx y.ctx } - let pretty_diff () (x,y) = if not (Tid.leq x.tid y.tid) then Tid.pretty_diff () (x.tid,y.tid) From 17aa06c5e80e75d869d0b74797534c16060f6d61 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 12:46:24 +0300 Subject: [PATCH 025/689] Derive hash for IntDomain and FloatDomain --- src/cdomains/floatDomain.ml | 6 +----- src/cdomains/intDomain.ml | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/cdomains/floatDomain.ml b/src/cdomains/floatDomain.ml index 4eb024adf9..23e967ca65 100644 --- a/src/cdomains/floatDomain.ml +++ b/src/cdomains/floatDomain.ml @@ -939,7 +939,7 @@ module FloatDomTupleImpl = struct module F1 = FloatIntervalImplLifted open Batteries - type t = F1.t option [@@deriving to_yojson, eq, ord] + type t = F1.t option [@@deriving eq, ord, hash] let name () = "floatdomtuple" @@ -986,10 +986,6 @@ module FloatDomTupleImpl = struct Option.map_default identity "" (mapp { fp= (fun (type a) (module F : FloatDomain with type t = a) x -> F.name () ^ ":" ^ F.show x); } x) - let hash x = - Option.map_default identity 0 - (mapp { fp= (fun (type a) (module F : FloatDomain with type t = a) -> F.hash); } x) - let of_const fkind = create { fi= (fun (type a) (module F : FloatDomain with type t = a) -> F.of_const fkind); } diff --git a/src/cdomains/intDomain.ml b/src/cdomains/intDomain.ml index 589239810f..d70d5b8ac1 100644 --- a/src/cdomains/intDomain.ml +++ b/src/cdomains/intDomain.ml @@ -3313,7 +3313,7 @@ module IntDomTupleImpl = struct module I5 = IntervalSetFunctor (BI) type t = I1.t option * I2.t option * I3.t option * I4.t option * I5.t option - [@@deriving to_yojson, eq, ord] + [@@deriving eq, ord, hash] let name () = "intdomtuple" @@ -3623,7 +3623,6 @@ module IntDomTupleImpl = struct (* others *) let show = String.concat "; " % to_list % mapp { fp = fun (type a) (module I:SOverflow with type t = a) x -> I.name () ^ ":" ^ (I.show x) } let to_yojson = [%to_yojson: Yojson.Safe.t list] % to_list % mapp { fp = fun (type a) (module I:SOverflow with type t = a) x -> I.to_yojson x } - let hash = List.fold_left (lxor) 0 % to_list % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.hash } (* `map/opt_map` are used by `project` *) let opt_map b f = From 5ed8049a1f308ff8d14675d0baeccc2eb30390df Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 13:20:47 +0300 Subject: [PATCH 026/689] Add ppx_deriving_printable using ppx_easy_deriving --- src/dune | 2 +- src/ppx/printable/dune | 8 ++++++++ src/ppx/printable/ppx_deriving_printable.ml | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/ppx/printable/dune create mode 100644 src/ppx/printable/ppx_deriving_printable.ml diff --git a/src/dune b/src/dune index 1ab30920e1..e7b4733abd 100644 --- a/src/dune +++ b/src/dune @@ -59,7 +59,7 @@ (foreign_stubs (language c) (names stubs)) (ocamlopt_flags :standard -no-float-const-prop) (preprocess - (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson ppx_blob ppx_deriving_lattice)) + (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson ppx_blob ppx_deriving_printable ppx_deriving_lattice)) (preprocessor_deps (file util/options.schema.json)) (instrumentation (backend bisect_ppx)) ) diff --git a/src/ppx/printable/dune b/src/ppx/printable/dune new file mode 100644 index 0000000000..2b620d2319 --- /dev/null +++ b/src/ppx/printable/dune @@ -0,0 +1,8 @@ +(include_subdirs no) + +(library + (name ppx_deriving_printable) + (kind ppx_deriver) + (libraries ppxlib ppx_easy_deriving) + (ppx_runtime_libraries ppx_easy_deriving.runtime) + (preprocess (pps ppxlib.metaquot))) diff --git a/src/ppx/printable/ppx_deriving_printable.ml b/src/ppx/printable/ppx_deriving_printable.ml new file mode 100644 index 0000000000..ad57b93e45 --- /dev/null +++ b/src/ppx/printable/ppx_deriving_printable.ml @@ -0,0 +1,15 @@ +open Ppx_easy_deriving + +module ReliftArg: Product.Map1.S = +struct + let name = "relift" +end + +module ReliftDeriver = Deriver.Make (Product.Map1.Make (ReliftArg)) +let relift_deriving = ReliftDeriver.register () + + +(* TODO: needs https://github.com/ocaml-ppx/ppxlib/pull/124 to include eq, ord, hash *) +(* let _ = Ppxlib.Deriving.add_alias "printable" [ + relift_deriving; + ] *) From 816a6f56f6c5302997d7bc0984c027b7cd126ece Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 13:21:24 +0300 Subject: [PATCH 027/689] Use relift deriver with lattice deriver --- src/cdomains/apron/relationDomain.apron.ml | 6 ++---- src/cdomains/baseDomain.ml | 7 ++----- src/cdomains/pthreadDomain.ml | 2 +- src/domains/printable.ml | 7 ++----- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/cdomains/apron/relationDomain.apron.ml b/src/cdomains/apron/relationDomain.apron.ml index c8942c2c6b..fdaced26ca 100644 --- a/src/cdomains/apron/relationDomain.apron.ml +++ b/src/cdomains/apron/relationDomain.apron.ml @@ -151,7 +151,7 @@ end type ('a, 'b) relcomponents_t = { rel: 'a; priv: 'b; -} [@@deriving eq, ord, hash, to_yojson, lattice] +} [@@deriving eq, ord, hash, to_yojson, relift, lattice] module RelComponents (D3: S3) (PrivD: Lattice.S): sig @@ -160,13 +160,11 @@ sig end = struct module RD = D3 - type t = (RD.t, PrivD.t) relcomponents_t [@@deriving eq, ord, hash, to_yojson, lattice] + type t = (RD.t, PrivD.t) relcomponents_t [@@deriving eq, ord, hash, to_yojson, relift, lattice] include Printable.Std open Pretty - let relift {rel; priv} = {rel = RD.relift rel; priv = PrivD.relift priv} - let show r = let first = RD.show r.rel in let third = PrivD.show r.priv in diff --git a/src/cdomains/baseDomain.ml b/src/cdomains/baseDomain.ml index e3a775020f..1c1a3c6a66 100644 --- a/src/cdomains/baseDomain.ml +++ b/src/cdomains/baseDomain.ml @@ -45,7 +45,7 @@ type 'a basecomponents_t = { deps: PartDeps.t; weak: WeakUpdates.t; priv: 'a; -} [@@deriving eq, ord, hash, lattice] +} [@@deriving eq, ord, hash, relift, lattice] module BaseComponents (PrivD: Lattice.S): @@ -54,7 +54,7 @@ sig val op_scheme: (CPA.t -> CPA.t -> CPA.t) -> (PartDeps.t -> PartDeps.t -> PartDeps.t) -> (WeakUpdates.t -> WeakUpdates.t -> WeakUpdates.t) -> (PrivD.t -> PrivD.t -> PrivD.t) -> t -> t -> t end = struct - type t = PrivD.t basecomponents_t [@@deriving eq, ord, hash, lattice] + type t = PrivD.t basecomponents_t [@@deriving eq, ord, hash, relift, lattice] include Printable.Std open Pretty @@ -109,9 +109,6 @@ struct let op_scheme op1 op2 op3 op4 {cpa=x1; deps=x2; weak=x3; priv=x4} {cpa=y1; deps=y2; weak=y3; priv=y4}: t = {cpa = op1 x1 y1; deps = op2 x2 y2; weak = op3 x3 y3; priv = op4 x4 y4 } - - let relift {cpa; deps; weak; priv} = - {cpa = CPA.relift cpa; deps = PartDeps.relift deps; weak = WeakUpdates.relift weak; priv = PrivD.relift priv} end module type ExpEvaluator = diff --git a/src/cdomains/pthreadDomain.ml b/src/cdomains/pthreadDomain.ml index 7bed37a267..a26cd3dfa5 100644 --- a/src/cdomains/pthreadDomain.ml +++ b/src/cdomains/pthreadDomain.ml @@ -25,7 +25,7 @@ end module D = struct include Printable.StdLeaf - type t = { tid : Tid.t; pred : Pred.t; ctx : Ctx.t } [@@deriving eq, ord, hash, to_yojson, lattice] + type t = { tid : Tid.t; pred : Pred.t; ctx : Ctx.t } [@@deriving eq, ord, hash, relift, to_yojson, lattice] (** printing *) let show x = diff --git a/src/domains/printable.ml b/src/domains/printable.ml index 495d294e6e..625af0e0c7 100644 --- a/src/domains/printable.ml +++ b/src/domains/printable.ml @@ -356,7 +356,7 @@ module ProdConf (C: ProdConfiguration) (Base1: S) (Base2: S)= struct include C - type t = Base1.t * Base2.t [@@deriving eq, ord, hash] + type t = Base1.t * Base2.t [@@deriving eq, ord, hash, relift] include Std @@ -387,8 +387,6 @@ struct `Assoc [ (Base1.name (), Base1.to_yojson x); (Base2.name (), Base2.to_yojson y) ] let arbitrary () = QCheck.pair (Base1.arbitrary ()) (Base2.arbitrary ()) - - let relift (x,y) = (Base1.relift x, Base2.relift y) end module Prod = ProdConf (struct let expand_fst = true let expand_snd = true end) @@ -396,7 +394,7 @@ module ProdSimple = ProdConf (struct let expand_fst = false let expand_snd = fal module Prod3 (Base1: S) (Base2: S) (Base3: S) = struct - type t = Base1.t * Base2.t * Base3.t [@@deriving eq, ord, hash] + type t = Base1.t * Base2.t * Base3.t [@@deriving eq, ord, hash, relift] include Std let show (x,y,z) = @@ -426,7 +424,6 @@ struct let name () = Base1.name () ^ " * " ^ Base2.name () ^ " * " ^ Base3.name () - let relift (x,y,z) = (Base1.relift x, Base2.relift y, Base3.relift z) let arbitrary () = QCheck.triple (Base1.arbitrary ()) (Base2.arbitrary ()) (Base3.arbitrary ()) end From 2e2bcc3e2ec63695d67a559b578e71886385e66c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Jun 2023 13:24:13 +0300 Subject: [PATCH 028/689] Use relift deriver more --- src/cdomains/mHP.ml | 5 +---- src/framework/analyses.ml | 3 +-- src/ppx/printable/ppx_deriving_printable.ml | 1 + 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/cdomains/mHP.ml b/src/cdomains/mHP.ml index 8037cfa21d..f0f2fc8c12 100644 --- a/src/cdomains/mHP.ml +++ b/src/cdomains/mHP.ml @@ -11,10 +11,7 @@ type t = { tid: ThreadIdDomain.ThreadLifted.t; created: ConcDomain.ThreadSet.t; must_joined: ConcDomain.ThreadSet.t; -} [@@deriving eq, ord, hash] - -let relift {tid; created; must_joined} = - {tid = ThreadIdDomain.ThreadLifted.relift tid; created = ConcDomain.ThreadSet.relift created; must_joined = ConcDomain.ThreadSet.relift must_joined} +} [@@deriving eq, ord, hash, relift] let current (ask:Queries.ask) = { diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 1a3a4ebeb1..a40a3b0bb5 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -32,8 +32,7 @@ end module Var = struct - type t = Node.t [@@deriving eq, ord, hash] - let relift = Node.relift + type t = Node.t [@@deriving eq, ord, hash, relift] let printXml f n = let l = Node.location n in diff --git a/src/ppx/printable/ppx_deriving_printable.ml b/src/ppx/printable/ppx_deriving_printable.ml index ad57b93e45..b8b80d6730 100644 --- a/src/ppx/printable/ppx_deriving_printable.ml +++ b/src/ppx/printable/ppx_deriving_printable.ml @@ -5,6 +5,7 @@ struct let name = "relift" end +(* TODO: Map1 should also do variants *) module ReliftDeriver = Deriver.Make (Product.Map1.Make (ReliftArg)) let relift_deriving = ReliftDeriver.register () From 57c5c3f2ff6838150c4e99e703026a5ae9c599b7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 25 Sep 2023 11:37:24 +0300 Subject: [PATCH 029/689] Add conditional accesses to LibraryDsl --- src/analyses/libraryDsl.ml | 50 ++++++++++++++++++++++++++----------- src/analyses/libraryDsl.mli | 29 ++++++++++++--------- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/analyses/libraryDsl.ml b/src/analyses/libraryDsl.ml index 49aac8ce9b..431d778b13 100644 --- a/src/analyses/libraryDsl.ml +++ b/src/analyses/libraryDsl.ml @@ -30,8 +30,20 @@ struct | [] -> fail "^::" end +type access = + | Access of LibraryDesc.Access.t + | If of (unit -> bool) * access + +let rec eval_access = function + | Access acc -> Some acc + | If (p, access) -> + if p () then + eval_access access + else + None + type ('k, 'l, 'r) arg_desc = { - accesses: Access.t list; + accesses: access list; match_arg: (Cil.exp, 'k, 'r) Pattern.t; match_var_args: (Cil.exp list, 'l, 'r) Pattern.t; } @@ -51,15 +63,21 @@ let rec accs: type k r. (k, r) args_desc -> Accesses.t = fun args_desc args -> match args_desc, args with | [], [] -> [] | VarArgs arg_desc, args -> - List.map (fun acc -> - (acc, args) + List.filter_map (fun access -> + match eval_access access with + | Some acc -> Some (acc, args) + | None -> None ) arg_desc.accesses | arg_desc :: args_desc, arg :: args -> let accs'' = accs args_desc args in - List.fold_left (fun (accs'': (Access.t * Cil.exp list) list) (acc: Access.t) -> - match List.assoc_opt acc accs'' with - | Some args -> (acc, arg :: args) :: List.remove_assoc acc accs'' - | None -> (acc, [arg]) :: accs'' + List.fold_left (fun (accs'': (Access.t * Cil.exp list) list) (access: access) -> + match eval_access access with + | Some acc -> + begin match List.assoc_opt acc accs'' with + | Some args -> (acc, arg :: args) :: List.remove_assoc acc accs'' + | None -> (acc, [arg]) :: accs'' + end + | None -> accs'' ) accs'' arg_desc.accesses | _, _ -> invalid_arg "accs" @@ -94,11 +112,13 @@ let drop (_name: string) accesses = { empty_drop_desc with accesses; } let drop' accesses = { empty_drop_desc with accesses; } -let r = Access.{ kind = Read; deep = false; } -let r_deep = Access.{ kind = Read; deep = true; } -let w = Access.{ kind = Write; deep = false; } -let w_deep = Access.{ kind = Write; deep = true; } -let f = Access.{ kind = Free; deep = false; } -let f_deep = Access.{ kind = Free; deep = true; } -let s = Access.{ kind = Spawn; deep = false; } -let s_deep = Access.{ kind = Spawn; deep = true; } +let r = Access { kind = Read; deep = false; } +let r_deep = Access { kind = Read; deep = true; } +let w = Access { kind = Write; deep = false; } +let w_deep = Access { kind = Write; deep = true; } +let f = Access { kind = Free; deep = false; } +let f_deep = Access { kind = Free; deep = true; } +let s = Access { kind = Spawn; deep = false; } +let s_deep = Access { kind = Spawn; deep = true; } + +let if_ p access = If (p, access) diff --git a/src/analyses/libraryDsl.mli b/src/analyses/libraryDsl.mli index fd0bc45c26..4ea6d7dae4 100644 --- a/src/analyses/libraryDsl.mli +++ b/src/analyses/libraryDsl.mli @@ -28,46 +28,51 @@ val special': ?attrs:LibraryDesc.attr list -> (LibraryDesc.special, LibraryDesc. (** Create unknown library function descriptor from arguments descriptor, which must {!drop} all arguments. *) val unknown: ?attrs:LibraryDesc.attr list -> (LibraryDesc.special, LibraryDesc.special) args_desc -> LibraryDesc.t +(** Argument access descriptor. *) +type access (** Argument descriptor, which captures the named argument with accesses for continuation function of {!special}. *) -val __: string -> LibraryDesc.Access.t list -> (Cil.exp -> 'r, Cil.exp list -> 'r, 'r) arg_desc +val __: string -> access list -> (Cil.exp -> 'r, Cil.exp list -> 'r, 'r) arg_desc (** Argument descriptor, which captures an unnamed argument with accesses for continuation function of {!special}. *) -val __': LibraryDesc.Access.t list -> (Cil.exp -> 'r, Cil.exp list -> 'r, 'r) arg_desc +val __': access list -> (Cil.exp -> 'r, Cil.exp list -> 'r, 'r) arg_desc (** Argument descriptor, which drops (does not capture) the named argument with accesses. *) -val drop: string -> LibraryDesc.Access.t list -> ('r, 'r, 'r) arg_desc +val drop: string -> access list -> ('r, 'r, 'r) arg_desc (** Argument descriptor, which drops (does not capture) an unnamed argument with accesses. *) -val drop': LibraryDesc.Access.t list -> ('r, 'r, 'r) arg_desc +val drop': access list -> ('r, 'r, 'r) arg_desc (** Shallow {!AccessKind.Read} access. All immediate arguments of function calls are always read, this specifies the reading of pointed-to values. *) -val r: LibraryDesc.Access.t +val r: access (** Deep {!AccessKind.Read} access. All immediate arguments of function calls are always read, this specifies the reading of pointed-to values. Rarely needed. *) -val r_deep: LibraryDesc.Access.t +val r_deep: access (** Shallow {!AccessKind.Write} access. *) -val w: LibraryDesc.Access.t +val w: access (** Deep {!AccessKind.Write} access. Rarely needed. *) -val w_deep: LibraryDesc.Access.t +val w_deep: access (** Shallow {!AccessKind.Free} access. *) -val f: LibraryDesc.Access.t +val f: access (** Deep {!AccessKind.Free} access. Rarely needed. *) -val f_deep: LibraryDesc.Access.t +val f_deep: access (** Shallow {!AccessKind.Spawn} access. *) -val s: LibraryDesc.Access.t +val s: access (** Deep {!AccessKind.Spawn} access. Rarely needed. *) -val s_deep: LibraryDesc.Access.t +val s_deep: access + +(** Conditional access, e.g. on an option. *) +val if_: (unit -> bool) -> access -> access From 9ee9ce7ac842fdbc61fe9b6e6e158f7dff14c4cc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 15:31:46 +0200 Subject: [PATCH 030/689] Add reach_error to library functions --- src/util/library/libraryFunctions.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 53bf804b1d..92355ca89c 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1029,6 +1029,7 @@ let svcomp_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__VERIFIER_nondet_int", unknown []); (* declare invalidate actions to prevent invalidating globals when extern in regression tests *) ("__VERIFIER_nondet_size_t", unknown []); (* cannot give it in sv-comp.c without including stdlib or similar *) ("__VERIFIER_assert", special [__ "exp" []] @@ fun exp -> Assert { exp; check = true; refine = get_bool "sem.assert.refine" }); (* only used if definition missing (e.g. in evalAssert transformed output) or extraspecial *) + ("reach_error", special [] @@ Abort); (* only used if definition missing (e.g. in evalAssert transformed output) or extraspecial *) ] [@@coverage off] From 4752ddf320351654aa13e8beb831736d535a2280 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 15:32:03 +0200 Subject: [PATCH 031/689] Make some YAML witness validation messages more severe --- src/analyses/unassumeAnalysis.ml | 4 ++-- src/witness/yamlWitness.ml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 5895f242c9..9ec69727c0 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -252,13 +252,13 @@ struct | false, (LocationInvariant _ | LoopInvariant _ | PreconditionLoopInvariant _ | InvariantSet _) -> M.info_noloc ~category:Witness "disabled entry of type %s" target_type | _ -> - M.info_noloc ~category:Witness "cannot unassume entry of type %s" target_type + M.warn_noloc ~category:Witness "cannot unassume entry of type %s" target_type in List.iter (fun yaml_entry -> match YamlWitnessType.Entry.of_yaml yaml_entry with | Ok entry -> unassume_entry entry - | Error (`Msg e) -> M.info_noloc ~category:Witness "couldn't parse entry: %s" e + | Error (`Msg e) -> M.error_noloc ~category:Witness "couldn't parse entry: %s" e ) yaml_entries let emit_unassume ctx = diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index d9d39ccee1..2969997906 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -829,7 +829,7 @@ struct None | _ -> incr cnt_unsupported; - M.info_noloc ~category:Witness "cannot validate entry of type %s" target_type; + M.warn_noloc ~category:Witness "cannot validate entry of type %s" target_type; None in @@ -841,7 +841,7 @@ struct Option.to_list yaml_certificate_entry @ yaml_entry :: yaml_entries' | Error (`Msg e) -> incr cnt_error; - M.info_noloc ~category:Witness "couldn't parse entry: %s" e; + M.error_noloc ~category:Witness "couldn't parse entry: %s" e; yaml_entry :: yaml_entries' ) [] yaml_entries in From 2e22af7d31bcaaf6ca04e8337f357d2d9282aade Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 15:51:57 +0200 Subject: [PATCH 032/689] Add ghost_variable and ghost_update to YAML witness types --- src/witness/yamlWitness.ml | 19 ++++++++++ src/witness/yamlWitnessType.ml | 68 +++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 2969997906..213dd26f6f 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -141,6 +141,25 @@ struct }; metadata = metadata (); } + + let ghost_variable ~task ~variable ~type_ ~(initial): Entry.t = { + entry_type = GhostVariable { + variable; + scope = "global"; + type_; + initial; + }; + metadata = metadata ~task (); + } + + let ghost_update ~task ~location ~variable ~(expression): Entry.t = { + entry_type = GhostUpdate { + variable; + expression; + location; + }; + metadata = metadata ~task (); + } end let yaml_entries_to_file yaml_entries file = diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index de9fa151d8..6412c3e7b4 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -413,6 +413,60 @@ struct let entry_type = "precondition_loop_invariant_certificate" end +module GhostVariable = +struct + type t = { + variable: string; + scope: string; + type_: string; + initial: string; + } + + let entry_type = "ghost_variable" + + let to_yaml' {variable; scope; type_; initial} = + [ + ("variable", `String variable); + ("scope", `String scope); + ("type", `String type_); + ("initial", `String initial); + ] + + let of_yaml y = + let open GobYaml in + let+ variable = y |> find "variable" >>= to_string + and+ scope = y |> find "scope" >>= to_string + and+ type_ = y |> find "type" >>= to_string + and+ initial = y |> find "initial" >>= to_string in + {variable; scope; type_; initial} +end + +module GhostUpdate = +struct + type t = { + variable: string; + expression: string; + location: Location.t; + (* TODO: branching? *) + } + + let entry_type = "ghost_update" + + let to_yaml' {variable; expression; location} = + [ + ("variable", `String variable); + ("expression", `String expression); + ("location", Location.to_yaml location); + ] + + let of_yaml y = + let open GobYaml in + let+ variable = y |> find "variable" >>= to_string + and+ expression = y |> find "expression" >>= to_string + and+ location = y |> find "location" >>= Location.of_yaml in + {variable; expression; location} +end + (* TODO: could maybe use GADT, but adds ugly existential layer to entry type pattern matching *) module EntryType = struct @@ -424,6 +478,8 @@ struct | LoopInvariantCertificate of LoopInvariantCertificate.t | PreconditionLoopInvariantCertificate of PreconditionLoopInvariantCertificate.t | InvariantSet of InvariantSet.t + | GhostVariable of GhostVariable.t + | GhostUpdate of GhostUpdate.t let entry_type = function | LocationInvariant _ -> LocationInvariant.entry_type @@ -433,6 +489,8 @@ struct | LoopInvariantCertificate _ -> LoopInvariantCertificate.entry_type | PreconditionLoopInvariantCertificate _ -> PreconditionLoopInvariantCertificate.entry_type | InvariantSet _ -> InvariantSet.entry_type + | GhostVariable _ -> GhostVariable.entry_type + | GhostUpdate _ -> GhostUpdate.entry_type let to_yaml' = function | LocationInvariant x -> LocationInvariant.to_yaml' x @@ -442,6 +500,8 @@ struct | LoopInvariantCertificate x -> LoopInvariantCertificate.to_yaml' x | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate.to_yaml' x | InvariantSet x -> InvariantSet.to_yaml' x + | GhostVariable x -> GhostVariable.to_yaml' x + | GhostUpdate x -> GhostUpdate.to_yaml' x let of_yaml y = let open GobYaml in @@ -467,8 +527,14 @@ struct else if entry_type = InvariantSet.entry_type then let+ x = y |> InvariantSet.of_yaml in InvariantSet x + else if entry_type = GhostVariable.entry_type then + let+ x = y |> GhostVariable.of_yaml in + GhostVariable x + else if entry_type = GhostUpdate.entry_type then + let+ x = y |> GhostUpdate.of_yaml in + GhostUpdate x else - Error (`Msg "entry_type") + Error (`Msg ("entry_type " ^ entry_type)) end module Entry = From 688c4dc2914897d72bcf8595286d2a49257ebef6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 17:07:24 +0200 Subject: [PATCH 033/689] Add mutexGhosts analysis --- src/analyses/mutexGhosts.ml | 41 +++++++++++++++++++++++++++++++++++++ src/cdomains/lockDomain.ml | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/analyses/mutexGhosts.ml diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml new file mode 100644 index 0000000000..fd5f9b5f00 --- /dev/null +++ b/src/analyses/mutexGhosts.ml @@ -0,0 +1,41 @@ +(** ([mutexGhosts]). *) + +open Analyses + + +module Spec = +struct + include UnitAnalysis.Spec + let name () = "mutexGhosts" + + module V = + struct + include Node + let is_write_only _ = true + end + + module Locked = + struct + include LockDomain.Mutexes + let name () = "locked" + end + module Unlocked = + struct + include LockDomain.Mutexes + let name () = "unlocked" + end + module G = Lattice.Prod (Locked) (Unlocked) + + let event ctx e octx = + begin match e with + | Events.Lock (l, _) -> + ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot ()) + | Events.Unlock l -> + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l) + | _ -> () + end; + ctx.local +end + +let _ = + MCP.register_analysis ~dep:["mutexEvents"] (module Spec : MCPSpec) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 107c1c0692..a7b3c93571 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -8,7 +8,7 @@ module IdxDom = ValueDomain.IndexDomain open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) -module Simple = Lattice.Reverse (Mutexes) +module Simple = SetDomain.Reverse (Mutexes) module Priorities = IntDomain.Lifted module Lockset = From 45be1644d407c182fd2919b1403eb09ca3af2413 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 17:30:09 +0200 Subject: [PATCH 034/689] Add YamlEntryGlobal query --- src/analyses/mCP.ml | 4 ++++ src/domains/queries.ml | 9 +++++++++ src/framework/constraints.ml | 24 ++++++++++++++++++++++++ src/witness/yamlWitness.ml | 20 ++++++++++++++++++++ src/witness/yamlWitnessType.ml | 30 ++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+) diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index a3943651c0..8f66f8049d 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -283,6 +283,10 @@ struct (* InvariantGlobal is special: it only goes to corresponding analysis and the argument variant is unlifted for it *) let (n, g): V.t = Obj.obj g in f ~q:(InvariantGlobal (Obj.repr g)) (Result.top ()) (n, spec n, assoc n ctx.local) + | Queries.YamlEntryGlobal (g, task) -> + (* YamlEntryGlobal is special: it only goes to corresponding analysis and the argument variant is unlifted for it *) + let (n, g): V.t = Obj.obj g in + f ~q:(YamlEntryGlobal (Obj.repr g, task)) (Result.top ()) (n, spec n, assoc n ctx.local) | Queries.PartAccess a -> Obj.repr (access ctx a) | Queries.IterSysVars (vq, fi) -> diff --git a/src/domains/queries.ml b/src/domains/queries.ml index f5fc832a9e..cc63e5fc0d 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -63,6 +63,8 @@ type invariant_context = Invariant.context = { } [@@deriving ord, hash] +module YS = SetDomain.ToppedSet (YamlWitnessType.Entry) (struct let topname = "Top" end) + (** GADT for queries with specific result type. *) type _ t = @@ -126,6 +128,7 @@ type _ t = | MustTermAllLoops: MustBool.t t | IsEverMultiThreaded: MayBool.t t | TmpSpecial: Mval.Exp.t -> ML.t t + | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t type 'a result = 'a @@ -195,6 +198,7 @@ struct | MustTermAllLoops -> (module MustBool) | IsEverMultiThreaded -> (module MayBool) | TmpSpecial _ -> (module ML) + | YamlEntryGlobal _ -> (module YS) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -263,6 +267,7 @@ struct | MustTermAllLoops -> MustBool.top () | IsEverMultiThreaded -> MayBool.top () | TmpSpecial _ -> ML.top () + | YamlEntryGlobal _ -> YS.top () end (* The type any_query can't be directly defined in Any as t, @@ -328,6 +333,7 @@ struct | Any IsEverMultiThreaded -> 55 | Any (TmpSpecial _) -> 56 | Any (IsAllocVar _) -> 57 + | Any (YamlEntryGlobal _) -> 58 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -375,6 +381,7 @@ struct | Any (WarnGlobal vi1), Any (WarnGlobal vi2) -> Stdlib.compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) | Any (Invariant i1), Any (Invariant i2) -> compare_invariant_context i1 i2 | Any (InvariantGlobal vi1), Any (InvariantGlobal vi2) -> Stdlib.compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) + | Any (YamlEntryGlobal (vi1, task1)), Any (YamlEntryGlobal (vi2, task2)) -> Stdlib.compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) (* TODO: compare task *) | Any (IterSysVars (vq1, vf1)), Any (IterSysVars (vq2, vf2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) | Any (MutexType m1), Any (MutexType m2) -> Mval.Unit.compare m1 m2 | Any (MustProtectedVars m1), Any (MustProtectedVars m2) -> compare_mustprotectedvars m1 m2 @@ -418,6 +425,7 @@ struct | Any (Invariant i) -> hash_invariant_context i | Any (MutexType m) -> Mval.Unit.hash m | Any (InvariantGlobal vi) -> Hashtbl.hash vi + | Any (YamlEntryGlobal (vi, task)) -> Hashtbl.hash vi (* TODO: hash task *) | Any (MustProtectedVars m) -> hash_mustprotectedvars m | Any (MayBeModifiedSinceSetjmp e) -> JmpBufDomain.BufferEntry.hash e | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start @@ -474,6 +482,7 @@ struct | Any (WarnGlobal vi) -> Pretty.dprintf "WarnGlobal _" | Any (IterSysVars _) -> Pretty.dprintf "IterSysVars _" | Any (InvariantGlobal i) -> Pretty.dprintf "InvariantGlobal _" + | Any (YamlEntryGlobal (i, task)) -> Pretty.dprintf "YamlEntryGlobal _" | Any (MutexType (v,o)) -> Pretty.dprintf "MutexType _" | Any (EvalMutexAttr a) -> Pretty.dprintf "EvalMutexAttr _" | Any MayAccessed -> Pretty.dprintf "MayAccessed" diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 52022b8aee..367386c6f1 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1250,6 +1250,14 @@ struct | `Right g -> Queries.Result.top q end + | YamlEntryGlobal (g, task) -> + let g: V.t = Obj.obj g in + begin match g with + | `Left g -> + S.query (conv ctx) (YamlEntryGlobal (Obj.repr g, task)) + | `Right g -> + Queries.Result.top q + end | IterSysVars (vq, vf) -> (* vars for S *) let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in @@ -1365,6 +1373,14 @@ struct | _ -> Queries.Result.top q end + | YamlEntryGlobal (g, task) -> + let g: V.t = Obj.obj g in + begin match g with + | `Left g -> + S.query (conv ctx) (YamlEntryGlobal (Obj.repr g, task)) + | _ -> + Queries.Result.top q + end | IterSysVars (vq, vf) -> (* vars for S *) let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in @@ -1650,6 +1666,14 @@ struct | `Right v -> Queries.Result.top q end + | YamlEntryGlobal (v, task) -> + let v: V.t = Obj.obj v in + begin match v with + | `Left v -> + S.query (conv ctx) (YamlEntryGlobal (Obj.repr v, task)) + | `Right v -> + Queries.Result.top q + end | _ -> S.query (conv ctx) q let branch ctx = S.branch (conv ctx) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 213dd26f6f..6ea8cc6c78 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -359,6 +359,26 @@ struct entries in + (* Generate flow-insensitive invariants *) + let entries = + if true then ( + GHT.fold (fun g v acc -> + match g with + | `Left g -> (* Spec global *) + begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with + | `Lifted _ as inv -> + Queries.YS.fold List.cons inv acc + | `Top -> + acc + end + | `Right _ -> (* contexts global *) + acc + ) gh entries + ) + else + entries + in + (* Generate precondition invariants. We do this in three steps: 1. Collect contexts for each function diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 6412c3e7b4..823fc993ce 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -9,6 +9,7 @@ struct command_line: string option; (* TODO: description *) } + [@@deriving eq, ord, hash] let to_yaml {name; version; command_line} = `O ([ @@ -39,6 +40,7 @@ struct language: string; specification: string option; } + [@@deriving eq, ord, hash] let to_yaml {input_files; input_file_hashes; data_model; language; specification} = `O ([ @@ -78,6 +80,7 @@ struct producer: Producer.t; task: Task.t option; } + [@@deriving eq, ord, hash] let to_yaml {format_version; uuid; creation_time; producer; task} = `O ([ @@ -111,6 +114,7 @@ struct column: int; function_: string; } + [@@deriving eq, ord, hash] let to_yaml {file_name; file_hash; line; column; function_} = `O [ @@ -138,6 +142,7 @@ struct type_: string; format: string; } + [@@deriving eq, ord, hash] let to_yaml {string; type_; format} = `O [ @@ -160,6 +165,7 @@ struct location: Location.t; loop_invariant: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "loop_invariant" @@ -182,6 +188,7 @@ struct location: Location.t; location_invariant: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "location_invariant" @@ -203,6 +210,7 @@ struct type t = { flow_insensitive_invariant: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "flow_insensitive_invariant" @@ -224,6 +232,7 @@ struct loop_invariant: Invariant.t; precondition: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "precondition_loop_invariant" @@ -251,6 +260,7 @@ struct value: string; format: string; } + [@@deriving eq, ord, hash] let invariant_type = "loop_invariant" @@ -282,6 +292,7 @@ struct type t = | LocationInvariant of LocationInvariant.t | LoopInvariant of LoopInvariant.t + [@@deriving eq, ord, hash] let invariant_type = function | LocationInvariant _ -> LocationInvariant.invariant_type @@ -309,6 +320,7 @@ struct type t = { invariant_type: InvariantType.t; } + [@@deriving eq, ord, hash] let to_yaml {invariant_type} = `O [ @@ -327,6 +339,7 @@ struct type t = { content: Invariant.t list; } + [@@deriving eq, ord, hash] let entry_type = "invariant_set" @@ -346,6 +359,7 @@ struct type_: string; file_hash: string; } + [@@deriving eq, ord, hash] let to_yaml {uuid; type_; file_hash} = `O [ @@ -369,6 +383,7 @@ struct type_: string; format: string; } + [@@deriving eq, ord, hash] let to_yaml {string; type_; format} = `O [ @@ -391,6 +406,7 @@ struct target: Target.t; certification: Certification.t; } + [@@deriving eq, ord, hash] let entry_type = "loop_invariant_certificate" @@ -421,6 +437,7 @@ struct type_: string; initial: string; } + [@@deriving eq, ord, hash] let entry_type = "ghost_variable" @@ -449,6 +466,7 @@ struct location: Location.t; (* TODO: branching? *) } + [@@deriving eq, ord, hash] let entry_type = "ghost_update" @@ -480,6 +498,7 @@ struct | InvariantSet of InvariantSet.t | GhostVariable of GhostVariable.t | GhostUpdate of GhostUpdate.t + [@@deriving eq, ord, hash] let entry_type = function | LocationInvariant _ -> LocationInvariant.entry_type @@ -539,10 +558,21 @@ end module Entry = struct + include Printable.StdLeaf + type t = { entry_type: EntryType.t; metadata: Metadata.t; } + [@@deriving eq, ord, hash] + + let name () = "YAML entry" + + let show _ = "TODO" + include Printable.SimpleShow (struct + type nonrec t = t + let show = show + end) let to_yaml {entry_type; metadata} = `O ([ From 5d3f5fe61d6d444d23deeb4ff91016689a3d8cfe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 17:38:02 +0200 Subject: [PATCH 035/689] Generate YAML witness ghosts for mutexes --- src/analyses/mutexGhosts.ml | 37 ++++++++++++++++++++++++++++++++++ src/witness/yamlWitness.ml | 7 ++++++- src/witness/yamlWitnessType.ml | 2 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index fd5f9b5f00..fe708b8cac 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -35,6 +35,43 @@ struct | _ -> () end; ctx.local + + let query ctx (type a) (q: a Queries.t): a Queries.result = + match q with + | YamlEntryGlobal (g, task) -> + let g: V.t = Obj.obj g in + let (locked, unlocked) = ctx.global g in + let loc = Node.location g in + let location_function = (Node.find_fundec g).svar.vname in + let location = YamlWitness.Entry.location ~location:loc ~location_function in + let entries = + (* TODO: do ghost_variable-s only once *) + Locked.fold (fun l acc -> + let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let type_ = "int" in + let initial = "0" in + let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in + Queries.YS.add entry acc + ) (Locked.union locked unlocked) (Queries.YS.empty ()) + in + let entries = + Locked.fold (fun l acc -> + let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let expression = "1" in + let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + Queries.YS.add entry acc + ) locked entries + in + let entries = + Unlocked.fold (fun l acc -> + let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let expression = "0" in + let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + Queries.YS.add entry acc + ) unlocked entries + in + entries + | _ -> Queries.Result.top q end let _ = diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 6ea8cc6c78..e04a4c9744 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -367,7 +367,12 @@ struct | `Left g -> (* Spec global *) begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with | `Lifted _ as inv -> - Queries.YS.fold List.cons inv acc + Queries.YS.fold (fun entry acc -> + if BatList.mem_cmp YamlWitnessType.Entry.compare entry acc then (* TODO: be efficient *) + acc + else + entry :: acc + ) inv acc | `Top -> acc end diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 823fc993ce..4bdb730b82 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -562,7 +562,7 @@ struct type t = { entry_type: EntryType.t; - metadata: Metadata.t; + metadata: Metadata.t [@equal fun _ _ -> true] [@compare fun _ _ -> 0] [@hash fun _ -> 1]; } [@@deriving eq, ord, hash] From a80242ae55587538f78e4ff4c3d1b5ee6601a776 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 10:52:05 +0200 Subject: [PATCH 036/689] Make protection privatization more precise with earlyglobs --- src/analyses/basePriv.ml | 4 +-- tests/regression/13-privatized/74-mutex.t | 32 +++++++++++++++++++++++ tests/regression/13-privatized/dune | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/regression/13-privatized/74-mutex.t create mode 100644 tests/regression/13-privatized/dune diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 125429231e..f08e7d710e 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -687,8 +687,8 @@ struct if not invariant then ( if not (Param.handle_atomic && ask.f MustBeAtomic) then sideg (V.unprotected x) v; (* Delay publishing unprotected write in the atomic section. *) - if !earlyglobs then (* earlyglobs workaround for 13/60 *) - sideg (V.protected x) v + if !earlyglobs && not (ThreadFlag.is_currently_multi ask) then (* earlyglobs workaround for 13/60 *) + sideg (V.protected x) v (* Also side to protected because with earlyglobs enter_multithreaded does not side everything to protected *) (* Unlock after invariant will still side effect refined value (if protected) from CPA, because cannot distinguish from non-invariant write since W is implicit. *) ); if Param.handle_atomic && ask.f MustBeAtomic then diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t new file mode 100644 index 0000000000..21c89cd524 --- /dev/null +++ b/tests/regression/13-privatized/74-mutex.t @@ -0,0 +1,32 @@ + $ goblint --enable ana.sv-comp.functions 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +Should also work with earlyglobs. +Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. + + $ goblint --enable ana.sv-comp.functions --enable exp.earlyglobs 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 diff --git a/tests/regression/13-privatized/dune b/tests/regression/13-privatized/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/13-privatized/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) From 086e60d9dc2c81c718e78f1b444ec63467d7bdf9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 11:51:12 +0200 Subject: [PATCH 037/689] Add ask argument to BasePriv invariant_global-s --- src/analyses/base.ml | 2 +- src/analyses/basePriv.ml | 14 +++++++------- src/analyses/basePriv.mli | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 9aca9e2079..7c6b2bf73f 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1243,7 +1243,7 @@ struct (* TODO: account for single-threaded values without earlyglobs. *) match g with | `Left g' -> (* priv *) - Priv.invariant_global (priv_getg ctx.global) g' + Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' | `Right _ -> (* thread return *) Invariant.none ) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index f08e7d710e..ea46e25689 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -42,7 +42,7 @@ sig val thread_join: ?force:bool -> Q.ask -> (V.t -> G.t) -> Cil.exp -> BaseComponents (D).t -> BaseComponents (D).t val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> BaseComponents (D).t -> BaseComponents (D).t - val invariant_global: (V.t -> G.t) -> V.t -> Invariant.t + val invariant_global: Q.ask -> (V.t -> G.t) -> V.t -> Invariant.t val invariant_vars: Q.ask -> (V.t -> G.t) -> BaseComponents (D).t -> varinfo list val init: unit -> unit @@ -131,7 +131,7 @@ struct let thread_join ?(force=false) ask get e st = st let thread_return ask get set tid st = st - let invariant_global getg g = + let invariant_global ask getg g = ValueDomain.invariant_global getg g let invariant_vars ask getg st = [] @@ -211,7 +211,7 @@ struct let thread_join ?(force=false) ask get e st = st let thread_return ask get set tid st = st - let invariant_global getg = function + let invariant_global ask getg = function | `Right g' -> (* global *) ValueDomain.invariant_global (read_unprotected_global getg) g' | _ -> (* mutex *) @@ -621,7 +621,7 @@ struct let get_mutex_inits' = CPA.find x get_mutex_inits in VD.join get_mutex_global_x' get_mutex_inits' - let invariant_global getg = function + let invariant_global ask getg = function | `Middle g -> (* global *) ValueDomain.invariant_global (read_unprotected_global getg) g | `Left _ @@ -777,7 +777,7 @@ struct vf (V.protected g); | _ -> () - let invariant_global getg g = + let invariant_global ask getg g = match g with | `Left g' -> (* unprotected *) ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g' @@ -841,7 +841,7 @@ struct open Locksets - let invariant_global getg = function + let invariant_global ask getg = function | `Right g' -> (* global *) ValueDomain.invariant_global (fun x -> GWeak.fold (fun s' tm acc -> @@ -1633,7 +1633,7 @@ struct let threadenter ask st = time "threadenter" (Priv.threadenter ask) st let threadspawn ask get set st = time "threadspawn" (Priv.threadspawn ask get set) st let iter_sys_vars getg vq vf = time "iter_sys_vars" (Priv.iter_sys_vars getg vq) vf - let invariant_global getg v = time "invariant_global" (Priv.invariant_global getg) v + let invariant_global ask getg v = time "invariant_global" (Priv.invariant_global ask getg) v let invariant_vars ask getg st = time "invariant_vars" (Priv.invariant_vars ask getg) st let thread_join ?(force=false) ask get e st = time "thread_join" (Priv.thread_join ~force ask get e) st diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index 6906e6e4e1..e176a450fa 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -31,7 +31,7 @@ sig val thread_join: ?force:bool -> Queries.ask -> (V.t -> G.t) -> Cil.exp -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t val thread_return: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t - val invariant_global: (V.t -> G.t) -> V.t -> Invariant.t + val invariant_global: Queries.ask -> (V.t -> G.t) -> V.t -> Invariant.t (** Provides [Queries.InvariantGlobal] result for base. Should account for all unprotected/weak values of global variables. *) From b2d09da76450c1f57909247904bb828f5cf407df Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:07:56 +0200 Subject: [PATCH 038/689] Add MustProtectingLocks query --- src/analyses/mutexAnalysis.ml | 3 +++ src/domains/queries.ml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 138f65ab47..1d134425f1 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -233,6 +233,9 @@ struct true else *) Mutexes.leq mutex_lockset protecting + | Queries.MustProtectingLocks g -> + let protecting = protecting ~write:true Strong g in + Mutexes.fold Queries.AD.add protecting (Queries.AD.empty ()) | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index cc63e5fc0d..3fd8c1fc87 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -117,6 +117,7 @@ type _ t = | MustJoinedThreads: ConcDomain.MustThreadSet.t t | ThreadsJoinedCleanly: MustBool.t t | MustProtectedVars: mustprotectedvars -> VS.t t + | MustProtectingLocks: CilType.Varinfo.t -> AD.t t | Invariant: invariant_context -> Invariant.t t | InvariantGlobal: Obj.t -> Invariant.t t (** Argument must be of corresponding [Spec.V.t]. *) | WarnGlobal: Obj.t -> Unit.t t (** Argument must be of corresponding [Spec.V.t]. *) @@ -187,6 +188,7 @@ struct | MustJoinedThreads -> (module ConcDomain.MustThreadSet) | ThreadsJoinedCleanly -> (module MustBool) | MustProtectedVars _ -> (module VS) + | MustProtectingLocks _ -> (module AD) | Invariant _ -> (module Invariant) | InvariantGlobal _ -> (module Invariant) | WarnGlobal _ -> (module Unit) @@ -256,6 +258,7 @@ struct | MustJoinedThreads -> ConcDomain.MustThreadSet.top () | ThreadsJoinedCleanly -> MustBool.top () | MustProtectedVars _ -> VS.top () + | MustProtectingLocks _ -> AD.top () | Invariant _ -> Invariant.top () | InvariantGlobal _ -> Invariant.top () | WarnGlobal _ -> Unit.top () @@ -334,6 +337,7 @@ struct | Any (TmpSpecial _) -> 56 | Any (IsAllocVar _) -> 57 | Any (YamlEntryGlobal _) -> 58 + | Any (MustProtectingLocks _) -> 59 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -385,6 +389,7 @@ struct | Any (IterSysVars (vq1, vf1)), Any (IterSysVars (vq2, vf2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) | Any (MutexType m1), Any (MutexType m2) -> Mval.Unit.compare m1 m2 | Any (MustProtectedVars m1), Any (MustProtectedVars m2) -> compare_mustprotectedvars m1 m2 + | Any (MustProtectingLocks g1), Any (MustProtectingLocks g2) -> CilType.Varinfo.compare g1 g2 | Any (MayBeModifiedSinceSetjmp e1), Any (MayBeModifiedSinceSetjmp e2) -> JmpBufDomain.BufferEntry.compare e1 e2 | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 @@ -427,6 +432,7 @@ struct | Any (InvariantGlobal vi) -> Hashtbl.hash vi | Any (YamlEntryGlobal (vi, task)) -> Hashtbl.hash vi (* TODO: hash task *) | Any (MustProtectedVars m) -> hash_mustprotectedvars m + | Any (MustProtectingLocks g) -> CilType.Varinfo.hash g | Any (MayBeModifiedSinceSetjmp e) -> JmpBufDomain.BufferEntry.hash e | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv @@ -478,6 +484,7 @@ struct | Any MustJoinedThreads -> Pretty.dprintf "MustJoinedThreads" | Any ThreadsJoinedCleanly -> Pretty.dprintf "ThreadsJoinedCleanly" | Any (MustProtectedVars m) -> Pretty.dprintf "MustProtectedVars _" + | Any (MustProtectingLocks g) -> Pretty.dprintf "MustProtectingLocks _" | Any (Invariant i) -> Pretty.dprintf "Invariant _" | Any (WarnGlobal vi) -> Pretty.dprintf "WarnGlobal _" | Any (IterSysVars _) -> Pretty.dprintf "IterSysVars _" From 526d88aac4ee38d350d8a17b0691766c8dc37e31 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:08:31 +0200 Subject: [PATCH 039/689] Generate protected flow-insensitive invariants with ghosts --- src/analyses/basePriv.ml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index ea46e25689..1863625546 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -777,12 +777,18 @@ struct vf (V.protected g); | _ -> () - let invariant_global ask getg g = + let invariant_global (ask: Q.ask) getg g = match g with | `Left g' -> (* unprotected *) ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g' - | `Right g -> (* protected *) - Invariant.none + | `Right g' -> (* protected *) + let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) + let locks = ask.f (Q.MustProtectingLocks g') in + Q.AD.fold (fun m acc -> + let variable = LockDomain.Addr.show m in (* TODO: valid C name *) + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(acc || of_exp (Lval (Var var, NoOffset))) + ) locks inv let invariant_vars ask getg st = protected_vars ask end From d536db4708977e10d9946c68fb69effb56e69b24 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:10:20 +0200 Subject: [PATCH 040/689] Make mutex ghost variable names distinct from mutex variables --- src/analyses/basePriv.ml | 2 +- src/analyses/mutexGhosts.ml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 1863625546..c34808522b 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -785,7 +785,7 @@ struct let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) let locks = ask.f (Q.MustProtectingLocks g') in Q.AD.fold (fun m acc -> - let variable = LockDomain.Addr.show m in (* TODO: valid C name *) + let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in Invariant.(acc || of_exp (Lval (Var var, NoOffset))) ) locks inv diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index fe708b8cac..1cc3cdca02 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -47,7 +47,7 @@ struct let entries = (* TODO: do ghost_variable-s only once *) Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) let type_ = "int" in let initial = "0" in let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in @@ -56,7 +56,7 @@ struct in let entries = Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) let expression = "1" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc @@ -64,7 +64,7 @@ struct in let entries = Unlocked.fold (fun l acc -> - let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) let expression = "0" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc From 2eafa692f26d25897f67748a89b5c1aa9e1e9da1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:26:34 +0200 Subject: [PATCH 041/689] Document MutexGhosts --- src/analyses/mutexGhosts.ml | 2 +- src/goblint_lib.ml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 1cc3cdca02..b8792a2bf8 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -1,4 +1,4 @@ -(** ([mutexGhosts]). *) +(** Analysis for generating ghost variables corresponding to mutexes ([mutexGhosts]). *) open Analyses diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index e06cc8fa08..c0de408f05 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -106,6 +106,7 @@ module MutexAnalysis = MutexAnalysis module MayLocks = MayLocks module SymbLocks = SymbLocks module Deadlock = Deadlock +module MutexGhosts = MutexGhosts (** {3 Threads} From 470ddbc8490d6daaaee397288e328a3f249ca333 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:36:15 +0200 Subject: [PATCH 042/689] Fix coverage build --- src/analyses/basePriv.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index c34808522b..a24c686a3a 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -787,7 +787,7 @@ struct Q.AD.fold (fun m acc -> let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(acc || of_exp (Lval (Var var, NoOffset))) + Invariant.(acc || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) locks inv let invariant_vars ask getg st = protected_vars ask From 0d5ef634d8c2b0bd3adac807b4b65e726e2d03b0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 13:38:57 +0200 Subject: [PATCH 043/689] Make mutex-meet privatization more precise with earlyglobs --- src/analyses/basePriv.ml | 7 +++-- tests/regression/13-privatized/74-mutex.t | 38 +++++++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index a24c686a3a..6e9384389b 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -329,8 +329,11 @@ struct in if not invariant then ( if M.tracing then M.tracel "priv" "WRITE GLOBAL SIDE %a = %a\n" CilType.Varinfo.pretty x VD.pretty v; - sideg (V.global x) (CPA.singleton x v) - (* Unlock after invariant will still side effect refined value (if protected) from CPA, because cannot distinguish from non-invariant write. *) + let side_cpa = CPA.singleton x v in + sideg (V.global x) side_cpa; + if !earlyglobs && not (ThreadFlag.is_currently_multi ask) then + sideg V.mutex_inits side_cpa (* Also side to inits because with earlyglobs enter_multithreaded does not side everything to inits *) + (* Unlock after invariant will still side effect refined value (if protected) from CPA, because cannot distinguish from non-invariant write. *) ); {st with cpa = cpa'} (* let write_global ask getg sideg cpa x v = diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 21c89cd524..810352de44 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -16,7 +16,41 @@ Should also work with earlyglobs. Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. - $ goblint --enable ana.sv-comp.functions --enable exp.earlyglobs 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable exp.earlyglobs 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +Same with mutex-meet. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +Should also work with earlyglobs. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable exp.earlyglobs 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) From a714dc6d512773c046a1c5dd1f937723623d0c21 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 13:47:17 +0200 Subject: [PATCH 044/689] Generate mutex-meet flow-insensitive invariants with ghosts --- src/analyses/basePriv.ml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 6e9384389b..b28381f9c6 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -294,6 +294,20 @@ module PerMutexMeetPrivBase = struct include PerMutexPrivBase + let invariant_global ask getg = function + | `Left m' as m -> (* mutex *) + let cpa = getg m in + let inv = CPA.fold (fun v _ acc -> + let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in + Invariant.(acc && inv) + ) cpa Invariant.none + in + let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(inv || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + | g -> (* global *) + invariant_global ask getg g + let invariant_vars ask getg (st: _ BaseDomain.basecomponents_t) = (* Mutex-meet local states contain precisely the protected global variables, so we can do fewer queries than {!protected_vars}. *) From 652aeaeaca2c07f03265024ad751ca0a83e41fe5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:02:54 +0200 Subject: [PATCH 045/689] Add ghost variable for multithreaded mode --- src/analyses/base.ml | 11 +++++++++-- src/analyses/mutexGhosts.ml | 28 ++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7c6b2bf73f..7f73fd42af 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1237,13 +1237,20 @@ struct Invariant.none let query_invariant_global ctx g = - if GobConfig.get_bool "ana.base.invariant.enabled" && get_bool "exp.earlyglobs" then ( + if GobConfig.get_bool "ana.base.invariant.enabled" then ( (* Currently these global invariants are only sound with earlyglobs enabled for both single- and multi-threaded programs. Otherwise, the values of globals in single-threaded mode are not accounted for. *) (* TODO: account for single-threaded values without earlyglobs. *) match g with | `Left g' -> (* priv *) - Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' + let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' in + if get_bool "exp.earlyglobs" then + inv + else ( + let variable = "multithreaded" in + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(inv || of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) | `Right _ -> (* thread return *) Invariant.none ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index b8792a2bf8..6a0b8d56e4 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -24,14 +24,21 @@ struct include LockDomain.Mutexes let name () = "unlocked" end - module G = Lattice.Prod (Locked) (Unlocked) + module MultiThread = + struct + include BoolDomain.MayBool + let name () = "multithread" + end + module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot ()) + ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) | Events.Unlock l -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l) + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) + | Events.EnterMultiThreaded -> + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) | _ -> () end; ctx.local @@ -40,7 +47,7 @@ struct match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let (locked, unlocked) = ctx.global g in + let (locked, unlocked, multithread) = ctx.global g in let loc = Node.location g in let location_function = (Node.find_fundec g).svar.vname in let location = YamlWitness.Entry.location ~location:loc ~location_function in @@ -70,6 +77,19 @@ struct Queries.YS.add entry acc ) unlocked entries in + let entries = + if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( + let variable = "multithreaded" in + let type_ = "int" in + let initial = "0" in + let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in + let expression = "1" in + let entry' = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + Queries.YS.add entry (Queries.YS.add entry' entries) + ) + else + entries + in entries | _ -> Queries.Result.top q end From 7c33c72abe086f984afa16439af06518063e5ed8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:07:53 +0200 Subject: [PATCH 046/689] Reorder disjuncts in privatized invariants in implication order This also means that the global variable is (lazily) not accessed when the condition isn't met. --- src/analyses/base.ml | 2 +- src/analyses/basePriv.ml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7f73fd42af..a4e5ab412a 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1249,7 +1249,7 @@ struct else ( let variable = "multithreaded" in let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(inv || of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) | `Right _ -> (* thread return *) Invariant.none diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index b28381f9c6..1950c6219d 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -304,7 +304,7 @@ struct in let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(inv || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) | g -> (* global *) invariant_global ask getg g @@ -804,7 +804,7 @@ struct Q.AD.fold (fun m acc -> let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(acc || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) locks inv let invariant_vars ask getg st = protected_vars ask From 4381e9fafa8108af5baf3d49e6e560fae0e7b7cc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:22:28 +0200 Subject: [PATCH 047/689] Fix MustProtectingLocks query crash with top Happened on 13-privatized/01-priv_nr --- src/analyses/basePriv.ml | 14 +++++++++----- src/analyses/mutexAnalysis.ml | 5 ++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 1950c6219d..a26ed3bac3 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -801,11 +801,15 @@ struct | `Right g' -> (* protected *) let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) let locks = ask.f (Q.MustProtectingLocks g') in - Q.AD.fold (fun m acc -> - let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) locks inv + if Q.AD.is_top locks then + Invariant.none + else ( + Q.AD.fold (fun m acc -> + let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) locks inv + ) let invariant_vars ask getg st = protected_vars ask end diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 1d134425f1..7e877d7dad 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -235,7 +235,10 @@ struct Mutexes.leq mutex_lockset protecting | Queries.MustProtectingLocks g -> let protecting = protecting ~write:true Strong g in - Mutexes.fold Queries.AD.add protecting (Queries.AD.empty ()) + if Mutexes.is_top protecting then + Queries.AD.top () + else + Mutexes.fold Queries.AD.add protecting (Queries.AD.empty ()) | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) From 60a51b986900e2efa77924fb6fb83c689e6917f2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:27:01 +0200 Subject: [PATCH 048/689] Fix protection privatization protected invariant with no protecting mutexes Happened on 13-privatized/02-priv_rc. --- src/analyses/basePriv.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index a26ed3bac3..891e8d2183 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -799,11 +799,11 @@ struct | `Left g' -> (* unprotected *) ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g' | `Right g' -> (* protected *) - let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) let locks = ask.f (Q.MustProtectingLocks g') in - if Q.AD.is_top locks then + if Q.AD.is_top locks || Q.AD.is_empty locks then Invariant.none else ( + let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in From fd84cd95f93b82b0f062e82f5683b011a52fc09e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:31:19 +0200 Subject: [PATCH 049/689] Fix mutex-meet privatization protected invariant with no protecting mutexes Happened on 13-privatized/02-priv_rc. --- src/analyses/basePriv.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 891e8d2183..94f0f4092b 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -294,12 +294,15 @@ module PerMutexMeetPrivBase = struct include PerMutexPrivBase - let invariant_global ask getg = function + let invariant_global (ask: Q.ask) getg = function | `Left m' as m -> (* mutex *) let cpa = getg m in let inv = CPA.fold (fun v _ acc -> - let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in - Invariant.(acc && inv) + if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then + let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in + Invariant.(acc && inv) + else + acc ) cpa Invariant.none in let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) From 516e3adc1128fef03ec49ec9bb1b03814914f462 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 15 Mar 2024 12:31:06 +0200 Subject: [PATCH 050/689] Use RichVarinfo for witness ghost variables --- src/analyses/base.ml | 3 +-- src/analyses/basePriv.ml | 6 ++---- src/analyses/mutexGhosts.ml | 8 ++++---- src/goblint_lib.ml | 1 + src/witness/witnessGhost.ml | 21 +++++++++++++++++++++ 5 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 src/witness/witnessGhost.ml diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a4e5ab412a..7ba0d5f706 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1247,8 +1247,7 @@ struct if get_bool "exp.earlyglobs" then inv else ( - let variable = "multithreaded" in - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + let var = WitnessGhost.to_varinfo Multithreaded in Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) | `Right _ -> (* thread return *) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 94f0f4092b..deb603a110 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -305,8 +305,7 @@ struct acc ) cpa Invariant.none in - let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) | g -> (* global *) invariant_global ask getg g @@ -808,8 +807,7 @@ struct else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> - let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + let var = WitnessGhost.to_varinfo (Locked m) in Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) locks inv ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 6a0b8d56e4..aedbeac0d4 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -54,7 +54,7 @@ struct let entries = (* TODO: do ghost_variable-s only once *) Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) + let variable = WitnessGhost.name_varinfo (Locked l) in let type_ = "int" in let initial = "0" in let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in @@ -63,7 +63,7 @@ struct in let entries = Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) + let variable = WitnessGhost.name_varinfo (Locked l) in let expression = "1" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc @@ -71,7 +71,7 @@ struct in let entries = Unlocked.fold (fun l acc -> - let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) + let variable = WitnessGhost.name_varinfo (Locked l) in let expression = "0" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc @@ -79,7 +79,7 @@ struct in let entries = if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let variable = "multithreaded" in + let variable = WitnessGhost.name_varinfo Multithreaded in let type_ = "int" in let initial = "0" in let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index c0de408f05..18a5d72aa7 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -333,6 +333,7 @@ module Graphml = Graphml module YamlWitness = YamlWitness module YamlWitnessType = YamlWitnessType +module WitnessGhost = WitnessGhost module WideningTokens = WideningTokens (** {3 Violation} diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml new file mode 100644 index 0000000000..a9d177a569 --- /dev/null +++ b/src/witness/witnessGhost.ml @@ -0,0 +1,21 @@ +(** Ghost variables for YAML witnesses. *) + +module Var = +struct + type t = + | Locked of LockDomain.Addr.t + | Multithreaded + [@@deriving eq, hash] + + let name_varinfo = function + | Locked l -> LockDomain.Addr.show l ^ "_locked" (* TODO: valid C name *) + | Multithreaded -> "multithreaded" + + (* TODO: define correct types *) +end + +include Var + +module Map = RichVarinfo.Make (Var) + +include Map From a10c973d2712c7b36a28fb176f72fcf99117e958 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 15 Mar 2024 12:54:52 +0200 Subject: [PATCH 051/689] Deduplicate witness ghost entry creation --- src/analyses/mutexGhosts.ml | 26 ++++++-------------------- src/witness/witnessGhost.ml | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index aedbeac0d4..0b11355d57 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -48,43 +48,29 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in let (locked, unlocked, multithread) = ctx.global g in - let loc = Node.location g in - let location_function = (Node.find_fundec g).svar.vname in - let location = YamlWitness.Entry.location ~location:loc ~location_function in let entries = - (* TODO: do ghost_variable-s only once *) + (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> - let variable = WitnessGhost.name_varinfo (Locked l) in - let type_ = "int" in - let initial = "0" in - let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in + let entry = WitnessGhost.variable_entry ~task (Locked l) in Queries.YS.add entry acc ) (Locked.union locked unlocked) (Queries.YS.empty ()) in let entries = Locked.fold (fun l acc -> - let variable = WitnessGhost.name_varinfo (Locked l) in - let expression = "1" in - let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in Queries.YS.add entry acc ) locked entries in let entries = Unlocked.fold (fun l acc -> - let variable = WitnessGhost.name_varinfo (Locked l) in - let expression = "0" in - let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in Queries.YS.add entry acc ) unlocked entries in let entries = if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let variable = WitnessGhost.name_varinfo Multithreaded in - let type_ = "int" in - let initial = "0" in - let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in - let expression = "1" in - let entry' = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + let entry = WitnessGhost.variable_entry ~task Multithreaded in + let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in Queries.YS.add entry (Queries.YS.add entry' entries) ) else diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index a9d177a569..dd4181e467 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -12,6 +12,14 @@ struct | Multithreaded -> "multithreaded" (* TODO: define correct types *) + + let type_ = function + | Locked _ -> GoblintCil.intType + | Multithreaded -> GoblintCil.intType + + let initial = function + | Locked _ -> GoblintCil.zero + | Multithreaded -> GoblintCil.zero end include Var @@ -19,3 +27,17 @@ include Var module Map = RichVarinfo.Make (Var) include Map + +let variable_entry ~task x = + let variable = name_varinfo x in + let type_ = String.trim (CilType.Typ.show (type_ x)) in (* CIL printer puts space at the end of some types *) + let initial = CilType.Exp.show (initial x) in + YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial + +let update_entry ~task ~node x e = + let loc = Node.location node in + let location_function = (Node.find_fundec node).svar.vname in + let location = YamlWitness.Entry.location ~location:loc ~location_function in + let variable = name_varinfo x in + let expression = CilType.Exp.show e in + YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression From 932ac3b312a77d09a683fa651ab114e30aec1b1e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 15 Mar 2024 13:00:59 +0200 Subject: [PATCH 052/689] Allow non-void types for RichVarinfo --- src/analyses/basePriv.ml | 2 +- src/analyses/wrapperFunctionAnalysis.ml | 2 ++ src/common/util/richVarinfo.ml | 9 +++++---- src/common/util/richVarinfo.mli | 3 ++- src/witness/witnessGhost.ml | 6 ++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index deb603a110..cafa84eb79 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -951,7 +951,7 @@ struct (* sync: M -> (2^M -> (G -> D)) *) include AbstractLockCenteredBase (ThreadMap) (LockCenteredBase.CPA) - let global_init_thread = RichVarinfo.single ~name:"global_init" + let global_init_thread = RichVarinfo.single ~name:"global_init" ~typ:GoblintCil.voidType let current_thread (ask: Q.ask): Thread.t = if !AnalysisState.global_initialization then ThreadIdDomain.Thread.threadinit (global_init_thread ()) ~multiple:false diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index 9510304e56..f3cf05c94d 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -144,6 +144,8 @@ module MallocWrapper : MCPSpec = struct Format.dprintf "@tid:%s" (ThreadLifted.show t) in Format.asprintf "(alloc@sid:%s%t%t)" (Node.show_id node) tid uniq_count + + let typ _ = GoblintCil.voidType end module NodeVarinfoMap = RichVarinfo.BiVarinfoMap.Make(ThreadNode) diff --git a/src/common/util/richVarinfo.ml b/src/common/util/richVarinfo.ml index d1918c40a6..6a27339eed 100644 --- a/src/common/util/richVarinfo.ml +++ b/src/common/util/richVarinfo.ml @@ -1,9 +1,9 @@ open GoblintCil -let create_var name = Cilfacade.create_var @@ makeGlobalVar name voidType +let create_var name typ = Cilfacade.create_var @@ makeGlobalVar name typ -let single ~name = - let vi = lazy (create_var name) in +let single ~name ~typ = + let vi = lazy (create_var name typ) in fun () -> Lazy.force vi @@ -21,6 +21,7 @@ module type G = sig include Hashtbl.HashedType val name_varinfo: t -> string + val typ: t -> typ end module type H = @@ -47,7 +48,7 @@ struct try XH.find !xh x with Not_found -> - let vi = create_var (X.name_varinfo x) in + let vi = create_var (X.name_varinfo x) (X.typ x) in store_f x vi; vi diff --git a/src/common/util/richVarinfo.mli b/src/common/util/richVarinfo.mli index 4e682734ee..d1c002bf84 100644 --- a/src/common/util/richVarinfo.mli +++ b/src/common/util/richVarinfo.mli @@ -2,7 +2,7 @@ open GoblintCil -val single: name:string -> (unit -> varinfo) +val single: name:string -> typ:typ -> (unit -> varinfo) module type VarinfoMap = sig @@ -18,6 +18,7 @@ module type G = sig include Hashtbl.HashedType val name_varinfo: t -> string + val typ: t -> typ end module type H = diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index dd4181e467..a0d25c5be6 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -11,9 +11,7 @@ struct | Locked l -> LockDomain.Addr.show l ^ "_locked" (* TODO: valid C name *) | Multithreaded -> "multithreaded" - (* TODO: define correct types *) - - let type_ = function + let typ = function | Locked _ -> GoblintCil.intType | Multithreaded -> GoblintCil.intType @@ -30,7 +28,7 @@ include Map let variable_entry ~task x = let variable = name_varinfo x in - let type_ = String.trim (CilType.Typ.show (type_ x)) in (* CIL printer puts space at the end of some types *) + let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) let initial = CilType.Exp.show (initial x) in YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial From b0182659a02387cb57a32c67f65a4fa9331b4821 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 2 Apr 2024 12:19:24 +0300 Subject: [PATCH 053/689] Add cram test for privatized witness ghosts --- tests/regression/13-privatized/74-mutex.t | 142 +++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 810352de44..1be888426c 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -7,12 +7,81 @@ dead: 1 total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 9 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 0 total memory locations: 1 + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 4 + function: producer + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 4 + function: producer + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_locked || used == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= used && used <= 1)' + type: assertion + format: C + Should also work with earlyglobs. Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. @@ -33,7 +102,7 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -42,12 +111,81 @@ Same with mutex-meet. dead: 1 total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 9 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 0 total memory locations: 1 + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 4 + function: producer + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 4 + function: producer + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_locked || used == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= used && used <= 1)' + type: assertion + format: C + Should also work with earlyglobs. $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable exp.earlyglobs 74-mutex.c From 7992462268c057f2a26a1f5cfeeab7c0c704e5e4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 2 Apr 2024 13:42:29 +0300 Subject: [PATCH 054/689] Add cram test for witness ghosts with multiple protecting locks --- .../56-witness/64-ghost-multiple-protecting.c | 30 ++ .../56-witness/64-ghost-multiple-protecting.t | 450 ++++++++++++++++++ 2 files changed, 480 insertions(+) create mode 100644 tests/regression/56-witness/64-ghost-multiple-protecting.c create mode 100644 tests/regression/56-witness/64-ghost-multiple-protecting.t diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c new file mode 100644 index 0000000000..0485cd124e --- /dev/null +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -0,0 +1,30 @@ +#include + +int g1, g2; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m1); + pthread_mutex_lock(&m2); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(&m2); + pthread_mutex_unlock(&m1); + + pthread_mutex_lock(&m1); + pthread_mutex_lock(&m2); + g2 = 1; + pthread_mutex_unlock(&m2); + pthread_mutex_lock(&m2); + g2 = 0; + pthread_mutex_unlock(&m2); + pthread_mutex_unlock(&m1); + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + return 0; +} diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t new file mode 100644 index 0000000000..7a413332a2 --- /dev/null +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -0,0 +1,450 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 18 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + +protection doesn't have precise protected invariant for g2. + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 28 + column: 2 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 21 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 18 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 12 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 15 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 8 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 2 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || (0 <= g2 && g2 <= 1)))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C + + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 18 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + +protection-read has precise protected invariant for g2. + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 28 + column: 2 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 21 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 18 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 12 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 15 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 8 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 2 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || g2 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C + + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 18 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 28 + column: 2 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 21 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 18 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 12 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 15 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 8 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 2 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || ((0 <= g2 && g2 <= 1) && g1 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || (g1 == 0 && g2 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C From 01c9b98fc839e3591d2111b279a99765e34af6ff Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 2 Apr 2024 14:55:35 +0300 Subject: [PATCH 055/689] mutex-meet ghost invariants are maybe unsound --- .../56-witness/64-ghost-multiple-protecting.c | 11 +++ .../56-witness/64-ghost-multiple-protecting.t | 68 ++++++++++--------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index 0485cd124e..b19ab18ad5 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -1,4 +1,5 @@ #include +#include int g1, g2; pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; @@ -26,5 +27,15 @@ void *t_fun(void *arg) { int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); + + /* pthread_mutex_lock(&m1); + __goblint_check(g1 == 0); + __goblint_check(g2 == 0); + pthread_mutex_unlock(&m1); + + pthread_mutex_lock(&m2); + __goblint_check(g1 == 0); + __goblint_check(g2 == 0); + pthread_mutex_unlock(&m2); */ return 0; } diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 7a413332a2..b221d65ef1 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -20,7 +20,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 28 + line: 29 column: 2 function: main - entry_type: ghost_update @@ -29,7 +29,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 19 + line: 20 column: 2 function: t_fun - entry_type: ghost_update @@ -38,7 +38,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 16 + line: 17 column: 2 function: t_fun - entry_type: ghost_update @@ -47,7 +47,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 2 function: t_fun - entry_type: ghost_update @@ -56,7 +56,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 21 + line: 22 column: 2 function: t_fun - entry_type: ghost_update @@ -65,7 +65,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 18 + line: 19 column: 2 function: t_fun - entry_type: ghost_update @@ -74,7 +74,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 2 function: t_fun - entry_type: ghost_update @@ -83,7 +83,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 15 + line: 16 column: 2 function: t_fun - entry_type: ghost_update @@ -92,7 +92,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 2 function: t_fun - entry_type: ghost_update @@ -101,7 +101,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 22 + line: 23 column: 2 function: t_fun - entry_type: ghost_update @@ -110,7 +110,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 13 + line: 14 column: 2 function: t_fun - entry_type: ghost_variable @@ -171,7 +171,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 28 + line: 29 column: 2 function: main - entry_type: ghost_update @@ -180,7 +180,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 19 + line: 20 column: 2 function: t_fun - entry_type: ghost_update @@ -189,7 +189,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 16 + line: 17 column: 2 function: t_fun - entry_type: ghost_update @@ -198,7 +198,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 2 function: t_fun - entry_type: ghost_update @@ -207,7 +207,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 21 + line: 22 column: 2 function: t_fun - entry_type: ghost_update @@ -216,7 +216,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 18 + line: 19 column: 2 function: t_fun - entry_type: ghost_update @@ -225,7 +225,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 2 function: t_fun - entry_type: ghost_update @@ -234,7 +234,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 15 + line: 16 column: 2 function: t_fun - entry_type: ghost_update @@ -243,7 +243,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 2 function: t_fun - entry_type: ghost_update @@ -252,7 +252,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 22 + line: 23 column: 2 function: t_fun - entry_type: ghost_update @@ -261,7 +261,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 13 + line: 14 column: 2 function: t_fun - entry_type: ghost_variable @@ -313,6 +313,8 @@ protection-read has precise protected invariant for g2. unsafe: 0 total memory locations: 2 +TODO: Are the mutex-meet invariants sound? + $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded @@ -320,7 +322,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 28 + line: 29 column: 2 function: main - entry_type: ghost_update @@ -329,7 +331,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 19 + line: 20 column: 2 function: t_fun - entry_type: ghost_update @@ -338,7 +340,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 16 + line: 17 column: 2 function: t_fun - entry_type: ghost_update @@ -347,7 +349,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 2 function: t_fun - entry_type: ghost_update @@ -356,7 +358,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 21 + line: 22 column: 2 function: t_fun - entry_type: ghost_update @@ -365,7 +367,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 18 + line: 19 column: 2 function: t_fun - entry_type: ghost_update @@ -374,7 +376,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 2 function: t_fun - entry_type: ghost_update @@ -383,7 +385,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 15 + line: 16 column: 2 function: t_fun - entry_type: ghost_update @@ -392,7 +394,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 2 function: t_fun - entry_type: ghost_update @@ -401,7 +403,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 22 + line: 23 column: 2 function: t_fun - entry_type: ghost_update @@ -410,7 +412,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 13 + line: 14 column: 2 function: t_fun - entry_type: ghost_variable From d3a5a0a3f1f864652788ed6852a019566efead3a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Apr 2024 17:05:34 +0300 Subject: [PATCH 056/689] Add NOWARNs to commented out checks in 56-witness/64-ghost-multiple-protecting --- .../regression/56-witness/64-ghost-multiple-protecting.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index b19ab18ad5..012318ac49 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -29,13 +29,13 @@ int main() { pthread_create(&id, NULL, t_fun, NULL); /* pthread_mutex_lock(&m1); - __goblint_check(g1 == 0); - __goblint_check(g2 == 0); + __goblint_check(g1 == 0); // NOWARN (commented out) + __goblint_check(g2 == 0); // NOWARN (commented out) pthread_mutex_unlock(&m1); pthread_mutex_lock(&m2); - __goblint_check(g1 == 0); - __goblint_check(g2 == 0); + __goblint_check(g1 == 0); // NOWARN (commented out) + __goblint_check(g2 == 0); // NOWARN (commented out) pthread_mutex_unlock(&m2); */ return 0; } From 612c1ccd4fe756af60fde77d837781fe800493ae Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 12:37:18 +0300 Subject: [PATCH 057/689] Remove TODO about mutex-meet unsound witness invariants --- tests/regression/56-witness/64-ghost-multiple-protecting.t | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index b221d65ef1..619438b3e3 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -313,8 +313,6 @@ protection-read has precise protected invariant for g2. unsafe: 0 total memory locations: 2 -TODO: Are the mutex-meet invariants sound? - $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded From e235ba70d1b187a0395f83729ef53f667fc41e6e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 16:25:14 +0300 Subject: [PATCH 058/689] Rewrite mutexGhosts with may locksets per node This makes 56-witness/65-ghost-ambiguous-lock have sensible ghost updates. --- src/analyses/mutexGhosts.ml | 83 +++++---- tests/regression/13-privatized/74-mutex.c | 4 +- tests/regression/13-privatized/74-mutex.t | 20 +-- .../56-witness/64-ghost-multiple-protecting.t | 6 +- .../56-witness/65-ghost-ambiguous-lock.c | 44 +++++ .../56-witness/65-ghost-ambiguous-lock.t | 166 ++++++++++++++++++ 6 files changed, 278 insertions(+), 45 deletions(-) create mode 100644 tests/regression/56-witness/65-ghost-ambiguous-lock.c create mode 100644 tests/regression/56-witness/65-ghost-ambiguous-lock.t diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 0b11355d57..ad40915e7f 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -5,49 +5,72 @@ open Analyses module Spec = struct - include UnitAnalysis.Spec - let name () = "mutexGhosts" - - module V = + (* Copied & modified from MayLocks. *) + module Arg = struct - include Node - let is_write_only _ = true - end + module D = LockDomain.MayLocksetNoRW + module V = + struct + include Node + let is_write_only _ = true + end - module Locked = - struct - include LockDomain.Mutexes - let name () = "locked" - end - module Unlocked = - struct - include LockDomain.Mutexes - let name () = "unlocked" - end - module MultiThread = - struct - include BoolDomain.MayBool - let name () = "multithread" + module Locked = + struct + include D + let name () = "locked" + end + module MultiThread = + struct + include BoolDomain.MayBool + let name () = "multithread" + end + module G = Lattice.Prod (Locked) (MultiThread) + + let add ctx (l,r) = + D.add l ctx.local + + let remove ctx l = + match D.Addr.to_mval l with + | Some (v,o) -> + (let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in + match mtype with + | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local + | _ -> ctx.local (* we cannot remove them here *)) + | None -> ctx.local (* we cannot remove them here *) end - module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) + + include LocksetAnalysis.MakeMay (Arg) + let name () = "mutexGhosts" + + open Arg + + let sync ctx reason = + if !AnalysisState.postsolving then + ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()); + ctx.local let event ctx e octx = begin match e with - | Events.Lock (l, _) -> - ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) - | Events.Unlock l -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) | Events.EnterMultiThreaded -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) + ctx.sideg ctx.prev_node (Locked.bot (), true) | _ -> () end; - ctx.local + event ctx e octx (* delegate to must lockset analysis *) let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let (locked, unlocked, multithread) = ctx.global g in + let module Cfg = (val !MyCFG.current_cfg) in + let next_lockset = List.fold_left (fun acc (_, next_node) -> + let (locked, _) = ctx.global next_node in + D.join acc locked + ) (D.bot ()) (Cfg.next g) + in + let (lockset, multithread) = ctx.global g in + let unlocked = D.diff lockset next_lockset in + let locked = D.diff next_lockset lockset in let entries = (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> @@ -62,7 +85,7 @@ struct ) locked entries in let entries = - Unlocked.fold (fun l acc -> + Locked.fold (fun l acc -> let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in Queries.YS.add entry acc ) unlocked entries diff --git a/tests/regression/13-privatized/74-mutex.c b/tests/regression/13-privatized/74-mutex.c index 8ed9448b7b..7c57688238 100644 --- a/tests/regression/13-privatized/74-mutex.c +++ b/tests/regression/13-privatized/74-mutex.c @@ -29,8 +29,8 @@ void* producer() int main() { pthread_t tid; - - pthread_mutex_init(&m, 0); + pthread_mutexattr_t mutexattr; pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&m, &mutexattr); pthread_create(&tid, 0, producer, 0); pthread_mutex_lock(&m); diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index d6d7c237e4..6f84aa184f 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,11 +1,11 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -90,9 +90,9 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 @@ -102,14 +102,14 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -193,9 +193,9 @@ Should also work with earlyglobs. [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 17a0a3c600..d51db2285e 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -149,7 +149,7 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -300,7 +300,7 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.c b/tests/regression/56-witness/65-ghost-ambiguous-lock.c new file mode 100644 index 0000000000..b1df0ee2e8 --- /dev/null +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.c @@ -0,0 +1,44 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +#include +#include + +int g1, g2; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m1); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(&m1); + pthread_mutex_lock(&m2); + g2 = 1; + g2 = 0; + pthread_mutex_unlock(&m2); + return NULL; +} + +void fun(pthread_mutex_t *m) { + pthread_mutex_lock(m); + // what g2 can read? + pthread_mutex_unlock(m); +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_t *m; + int r; // rand + m = r ? &m1 : &m2; + + pthread_mutex_lock(m); + // what g1 can read? + pthread_mutex_unlock(m); + + if (r) + fun(&m1); + else + fun(&m2); + return 0; +} diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t new file mode 100644 index 0000000000..ee586bd531 --- /dev/null +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -0,0 +1,166 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 65-ghost-ambiguous-lock.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 23 + dead: 0 + total lines: 23 + [Info][Witness] witness generation summary: + total generation entries: 20 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 37 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 24 + column: 3 + function: fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 37 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 24 + column: 3 + function: fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || g2 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || g1 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C From 726f646eb85ed399955cf11d78c60db56217b9d4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 17:49:52 +0300 Subject: [PATCH 059/689] Add test for mutex ghosts for alloc variables --- .../56-witness/66-ghost-alloc-lock.c | 37 +++++ .../56-witness/66-ghost-alloc-lock.t | 134 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 tests/regression/56-witness/66-ghost-alloc-lock.c create mode 100644 tests/regression/56-witness/66-ghost-alloc-lock.t diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.c b/tests/regression/56-witness/66-ghost-alloc-lock.c new file mode 100644 index 0000000000..75d405f1ab --- /dev/null +++ b/tests/regression/56-witness/66-ghost-alloc-lock.c @@ -0,0 +1,37 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 +#include +#include + +int g1, g2; +pthread_mutex_t *m1; +pthread_mutex_t *m2; + +void *t_fun(void *arg) { + pthread_mutex_lock(m1); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(m1); + pthread_mutex_lock(m2); + g2 = 1; + g2 = 0; + pthread_mutex_unlock(m2); + return NULL; +} + +int main() { + m1 = malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(m1, NULL); + m2 = malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(m2, NULL); + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(m1); + __goblint_check(g1 == 0); + pthread_mutex_unlock(m1); + pthread_mutex_lock(m2); + __goblint_check(g2 == 0); + pthread_mutex_unlock(m2); + return 0; +} diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t new file mode 100644 index 0000000000..84c1589317 --- /dev/null +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -0,0 +1,134 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 66-ghost-alloc-lock.c + [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) + [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 23 + dead: 0 + total lines: 23 + [Info][Witness] witness generation summary: + total generation entries: 16 + [Info][Race] Memory locations race summary: + safe: 4 + vulnerable: 0 + unsafe: 0 + total memory locations: 4 + +TODO: valid C names for alloc mutex ghosts + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 33 + column: 3 + function: main + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 36 + column: 10 + function: main + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 18 + column: 10 + function: t_fun + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 36 + column: 10 + function: main + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 18 + column: 10 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: (alloc@sid:14@tid:[main](#0))_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: (alloc@sid:11@tid:[main](#0))_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((alloc@sid:14@tid:[main](#0))_locked || g2 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((alloc@sid:11@tid:[main](#0))_locked || g1 == 0)' + type: assertion + format: C From 3e9d7c32daffe2f818e5fa5ebf81b5a459fb40bc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 18:05:38 +0300 Subject: [PATCH 060/689] Add valid names to alloc mutex ghosts --- src/witness/witnessGhost.ml | 10 ++++++- .../56-witness/66-ghost-alloc-lock.t | 30 +++++++++---------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index a0d25c5be6..2aca886e78 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -8,7 +8,15 @@ struct [@@deriving eq, hash] let name_varinfo = function - | Locked l -> LockDomain.Addr.show l ^ "_locked" (* TODO: valid C name *) + | Locked (Addr (v, _) as l) -> + let name = + if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then + Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) + else + LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) + in + name ^ "_locked" + | Locked _ -> assert false | Multithreaded -> "multithreaded" let typ = function diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index 84c1589317..bc3236d5a9 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -13,8 +13,6 @@ unsafe: 0 total memory locations: 4 -TODO: valid C names for alloc mutex ghosts - $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded @@ -26,7 +24,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: main - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -35,7 +33,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: main - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -44,7 +42,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: t_fun - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -53,7 +51,7 @@ TODO: valid C names for alloc mutex ghosts column: 10 function: main - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -62,7 +60,7 @@ TODO: valid C names for alloc mutex ghosts column: 10 function: t_fun - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -71,7 +69,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: main - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -80,7 +78,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: t_fun - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -89,7 +87,7 @@ TODO: valid C names for alloc mutex ghosts column: 10 function: main - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -103,32 +101,32 @@ TODO: valid C names for alloc mutex ghosts type: int initial: "0" - entry_type: ghost_variable - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked scope: global type: int initial: "0" - entry_type: ghost_variable - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked scope: global type: int initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (0 <= g2 && g2 <= 1)' + string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (0 <= g1 && g1 <= 1)' + string: '! multithreaded || (alloc_m559918035_locked || g1 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || ((alloc@sid:14@tid:[main](#0))_locked || g2 == 0)' + string: '! multithreaded || (0 <= g2 && g2 <= 1)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || ((alloc@sid:11@tid:[main](#0))_locked || g1 == 0)' + string: '! multithreaded || (0 <= g1 && g1 <= 1)' type: assertion format: C From b19cc2d23ae27f5692c69da724caa703a0e12660 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Apr 2024 14:01:42 +0300 Subject: [PATCH 061/689] Fix mutexGhosts indentation --- src/analyses/mutexGhosts.ml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index ad40915e7f..1c1a05b3b7 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -33,10 +33,11 @@ struct let remove ctx l = match D.Addr.to_mval l with | Some (v,o) -> - (let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in - match mtype with - | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local - | _ -> ctx.local (* we cannot remove them here *)) + let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in + begin match mtype with + | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local + | _ -> ctx.local (* we cannot remove them here *) + end | None -> ctx.local (* we cannot remove them here *) end From 885d0cf4b96d3aec64d90d68cd27e82867001f2a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Apr 2024 14:03:09 +0300 Subject: [PATCH 062/689] Use non-recursive mutex in 56-witness/66-ghost-alloc-lock This fixes unlock ghost update locations. --- .../56-witness/66-ghost-alloc-lock.c | 6 +-- .../56-witness/66-ghost-alloc-lock.t | 40 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.c b/tests/regression/56-witness/66-ghost-alloc-lock.c index 75d405f1ab..2c1028564a 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.c +++ b/tests/regression/56-witness/66-ghost-alloc-lock.c @@ -18,11 +18,11 @@ void *t_fun(void *arg) { return NULL; } -int main() { +int main() { pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); // https://github.com/goblint/analyzer/pull/1414 m1 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m1, NULL); + pthread_mutex_init(m1, &attr); m2 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m2, NULL); + pthread_mutex_init(m2, &attr); pthread_t id; pthread_create(&id, NULL, t_fun, NULL); diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index bc3236d5a9..e4d128b71e 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -24,7 +24,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -33,7 +33,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -42,25 +42,25 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 36 - column: 10 + line: 35 + column: 3 function: main - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 18 - column: 10 + line: 17 + column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -69,7 +69,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -78,22 +78,22 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 36 - column: 10 + line: 32 + column: 3 function: main - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 18 - column: 10 + line: 13 + column: 3 function: t_fun - entry_type: ghost_variable variable: multithreaded @@ -101,23 +101,23 @@ type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked scope: global type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked scope: global type: int initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' + string: '! multithreaded || (alloc_m817990718_locked || g2 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m559918035_locked || g1 == 0)' + string: '! multithreaded || (alloc_m334174073_locked || g1 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant From 21ae83a40215d181e92d31fa81b962c0937b0534 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Apr 2024 17:22:50 +0300 Subject: [PATCH 063/689] Fix mutexGhosts unlocking everything at function return --- src/analyses/mutexGhosts.ml | 21 ++++-- .../56-witness/67-ghost-no-unlock.c | 27 +++++++ .../56-witness/67-ghost-no-unlock.t | 71 +++++++++++++++++++ 3 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 tests/regression/56-witness/67-ghost-no-unlock.c create mode 100644 tests/regression/56-witness/67-ghost-no-unlock.t diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 1c1a05b3b7..934b2a0c0e 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -47,8 +47,11 @@ struct open Arg let sync ctx reason = - if !AnalysisState.postsolving then - ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()); + if !AnalysisState.postsolving then ( + match reason with + | `Return -> ctx.sideg ctx.node (ctx.local, MultiThread.bot ()) + | _ -> ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()) + ); ctx.local let event ctx e octx = @@ -64,12 +67,16 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in let module Cfg = (val !MyCFG.current_cfg) in - let next_lockset = List.fold_left (fun acc (_, next_node) -> - let (locked, _) = ctx.global next_node in - D.join acc locked - ) (D.bot ()) (Cfg.next g) - in let (lockset, multithread) = ctx.global g in + let next_lockset = + match Cfg.next g with + | [] -> lockset (* HACK for return nodes *) + | nexts -> + List.fold_left (fun acc (_, next_node) -> + let (locked, _) = ctx.global next_node in + D.join acc locked + ) (D.bot ()) nexts + in let unlocked = D.diff lockset next_lockset in let locked = D.diff next_lockset lockset in let entries = diff --git a/tests/regression/56-witness/67-ghost-no-unlock.c b/tests/regression/56-witness/67-ghost-no-unlock.c new file mode 100644 index 0000000000..fc10b919d0 --- /dev/null +++ b/tests/regression/56-witness/67-ghost-no-unlock.c @@ -0,0 +1,27 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +#include +#include + +int g1; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m1); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(&m1); + return NULL; +} + +int main() { + + + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m1); + __goblint_check(g1 == 0); + // no unlock + return 0; // there should be no ghost updates for unlock here +} diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t new file mode 100644 index 0000000000..491dd9cf44 --- /dev/null +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -0,0 +1,71 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 67-ghost-no-unlock.c + [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Witness] witness generation summary: + total generation entries: 8 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 12 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || g1 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C From d67c083ba9755e6d1ecc38daaf28d3a266a1ee38 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Apr 2024 14:49:58 +0300 Subject: [PATCH 064/689] Revert "Rewrite mutexGhosts with may locksets per node" This partially reverts commits e235ba70d1b187a0395f83729ef53f667fc41e6e and 21ae83a40215d181e92d31fa81b962c0937b0534. --- src/analyses/mutexGhosts.ml | 91 ++++++++++++------------------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 934b2a0c0e..0b11355d57 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -5,80 +5,49 @@ open Analyses module Spec = struct - (* Copied & modified from MayLocks. *) - module Arg = - struct - module D = LockDomain.MayLocksetNoRW - module V = - struct - include Node - let is_write_only _ = true - end - - module Locked = - struct - include D - let name () = "locked" - end - module MultiThread = - struct - include BoolDomain.MayBool - let name () = "multithread" - end - module G = Lattice.Prod (Locked) (MultiThread) - - let add ctx (l,r) = - D.add l ctx.local - - let remove ctx l = - match D.Addr.to_mval l with - | Some (v,o) -> - let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in - begin match mtype with - | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local - | _ -> ctx.local (* we cannot remove them here *) - end - | None -> ctx.local (* we cannot remove them here *) - end - - include LocksetAnalysis.MakeMay (Arg) + include UnitAnalysis.Spec let name () = "mutexGhosts" - open Arg + module V = + struct + include Node + let is_write_only _ = true + end - let sync ctx reason = - if !AnalysisState.postsolving then ( - match reason with - | `Return -> ctx.sideg ctx.node (ctx.local, MultiThread.bot ()) - | _ -> ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()) - ); - ctx.local + module Locked = + struct + include LockDomain.Mutexes + let name () = "locked" + end + module Unlocked = + struct + include LockDomain.Mutexes + let name () = "unlocked" + end + module MultiThread = + struct + include BoolDomain.MayBool + let name () = "multithread" + end + module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) let event ctx e octx = begin match e with + | Events.Lock (l, _) -> + ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) + | Events.Unlock l -> + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) | Events.EnterMultiThreaded -> - ctx.sideg ctx.prev_node (Locked.bot (), true) + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) | _ -> () end; - event ctx e octx (* delegate to must lockset analysis *) + ctx.local let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let module Cfg = (val !MyCFG.current_cfg) in - let (lockset, multithread) = ctx.global g in - let next_lockset = - match Cfg.next g with - | [] -> lockset (* HACK for return nodes *) - | nexts -> - List.fold_left (fun acc (_, next_node) -> - let (locked, _) = ctx.global next_node in - D.join acc locked - ) (D.bot ()) nexts - in - let unlocked = D.diff lockset next_lockset in - let locked = D.diff next_lockset lockset in + let (locked, unlocked, multithread) = ctx.global g in let entries = (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> @@ -93,7 +62,7 @@ struct ) locked entries in let entries = - Locked.fold (fun l acc -> + Unlocked.fold (fun l acc -> let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in Queries.YS.add entry acc ) unlocked entries From c472adff1fdf72a6da6142d07f55e59069f91aeb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Apr 2024 18:00:05 +0300 Subject: [PATCH 065/689] Add lock global unknowns to mutexGhosts --- src/analyses/mutexGhosts.ml | 92 +++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 0b11355d57..d80291532f 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -10,8 +10,12 @@ struct module V = struct - include Node - let is_write_only _ = true + include Printable.Either (Node) (LockDomain.Addr) + let node x = `Left x + let lock x = `Right x + let is_write_only = function + | `Left _ -> false + | `Right _ -> true end module Locked = @@ -29,16 +33,29 @@ struct include BoolDomain.MayBool let name () = "multithread" end - module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) + module G = + struct + include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (Lattice.Unit) + let node = function + | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) + | `Lifted1 x -> x + | _ -> failwith "MutexGhosts.node" + let lock = function + | `Bot -> Lattice.Unit.bot () + | `Lifted2 x -> x + | _ -> failwith "MutexGhosts.lock" + let create_node node = `Lifted1 node + let create_lock lock = `Lifted2 lock + end let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())) | Events.Unlock l -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())) | Events.EnterMultiThreaded -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) | _ -> () end; ctx.local @@ -47,36 +64,41 @@ struct match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let (locked, unlocked, multithread) = ctx.global g in - let entries = - (* TODO: do variable_entry-s only once *) - Locked.fold (fun l acc -> - let entry = WitnessGhost.variable_entry ~task (Locked l) in - Queries.YS.add entry acc - ) (Locked.union locked unlocked) (Queries.YS.empty ()) - in - let entries = - Locked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in - Queries.YS.add entry acc - ) locked entries - in - let entries = - Unlocked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in - Queries.YS.add entry acc - ) unlocked entries - in - let entries = - if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let entry = WitnessGhost.variable_entry ~task Multithreaded in - let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in - Queries.YS.add entry (Queries.YS.add entry' entries) - ) - else + begin match g with + | `Left g' -> + let (locked, unlocked, multithread) = G.node (ctx.global g) in + let g = g' in + let entries = + (* TODO: do variable_entry-s only once *) + Locked.fold (fun l acc -> + let entry = WitnessGhost.variable_entry ~task (Locked l) in + Queries.YS.add entry acc + ) (Locked.union locked unlocked) (Queries.YS.empty ()) + in + let entries = + Locked.fold (fun l acc -> + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in + Queries.YS.add entry acc + ) locked entries + in + let entries = + Unlocked.fold (fun l acc -> + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in + Queries.YS.add entry acc + ) unlocked entries + in + let entries = + if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( + let entry = WitnessGhost.variable_entry ~task Multithreaded in + let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in + Queries.YS.add entry (Queries.YS.add entry' entries) + ) + else + entries + in entries - in - entries + | `Right _ -> assert false + end | _ -> Queries.Result.top q end From fd64898163e98115a3d3dfd253856005796c68a9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:34:37 +0300 Subject: [PATCH 066/689] Add PARAM to 56-witness/64-ghost-multiple-protecting --- tests/regression/56-witness/64-ghost-multiple-protecting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index 012318ac49..589aa92bff 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -1,6 +1,6 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType #include #include - int g1, g2; pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; From e3ded4e20de4790baf9d9bf5b6fad2904d3ae598 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:34:55 +0300 Subject: [PATCH 067/689] Find ambiguous mutexes in mutexGhosts --- src/analyses/mutexGhosts.ml | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index d80291532f..083763f41b 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -35,7 +35,7 @@ struct end module G = struct - include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (Lattice.Unit) + include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (BoolDomain.MayBool) let node = function | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) | `Lifted1 x -> x @@ -51,9 +51,25 @@ struct let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); + if !AnalysisState.postsolving then ( + let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + if Locked.cardinal locked > 1 then ( + Locked.iter (fun lock -> + ctx.sideg (V.lock lock) (G.create_lock true) + ) locked + ); + ) | Events.Unlock l -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); + if !AnalysisState.postsolving then ( + let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in + if Locked.cardinal unlocked > 1 then ( + Locked.iter (fun lock -> + ctx.sideg (V.lock lock) (G.create_lock true) + ) unlocked + ); + ) | Events.EnterMultiThreaded -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) | _ -> () @@ -97,7 +113,7 @@ struct entries in entries - | `Right _ -> assert false + | `Right _ -> Queries.Result.top q end | _ -> Queries.Result.top q end From b96f8a210c18fa6f1380f29d90fe53f7ad77efbe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:50:04 +0300 Subject: [PATCH 068/689] Avoid emitting witness ghosts for ambiguous mutexes --- src/analyses/base.ml | 5 +- src/analyses/basePriv.ml | 10 +- src/analyses/mutexGhosts.ml | 42 ++++-- src/domains/queries.ml | 7 + src/witness/witnessGhost.ml | 4 +- .../56-witness/65-ghost-ambiguous-lock.t | 130 +----------------- 6 files changed, 55 insertions(+), 143 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 4cc5c51262..ac31e29163 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1248,7 +1248,10 @@ struct inv else ( let var = WitnessGhost.to_varinfo Multithreaded in - Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if ctx.ask (GhostVarAvailable var) then + Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + else + Invariant.none ) | `Right _ -> (* thread return *) Invariant.none diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 832aaf54c1..129d0d5d69 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -343,7 +343,10 @@ struct ) cpa Invariant.none in let var = WitnessGhost.to_varinfo (Locked m') in - Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if ask.f (GhostVarAvailable var) then + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + else + Invariant.none | g -> (* global *) invariant_global ask getg g @@ -859,7 +862,10 @@ struct let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> let var = WitnessGhost.to_varinfo (Locked m) in - Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if ask.f (GhostVarAvailable var) then + Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + else + Invariant.none ) locks inv ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 083763f41b..21a12db7a1 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -41,7 +41,7 @@ struct | `Lifted1 x -> x | _ -> failwith "MutexGhosts.node" let lock = function - | `Bot -> Lattice.Unit.bot () + | `Bot -> BoolDomain.MayBool.bot () | `Lifted2 x -> x | _ -> failwith "MutexGhosts.lock" let create_node node = `Lifted1 node @@ -76,8 +76,14 @@ struct end; ctx.local + let ghost_var_available ctx = function + | WitnessGhost.Var.Locked lock -> not (G.lock (ctx.global (V.lock lock)): bool) + | Multithreaded -> true + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with + | GhostVarAvailable vi -> + GobOption.exists (ghost_var_available ctx) (WitnessGhost.from_varinfo vi) | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with @@ -87,27 +93,43 @@ struct let entries = (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> - let entry = WitnessGhost.variable_entry ~task (Locked l) in - Queries.YS.add entry acc + if ghost_var_available ctx (Locked l) then ( + let entry = WitnessGhost.variable_entry ~task (Locked l) in + Queries.YS.add entry acc + ) + else + acc ) (Locked.union locked unlocked) (Queries.YS.empty ()) in let entries = Locked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in - Queries.YS.add entry acc + if ghost_var_available ctx (Locked l) then ( + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in + Queries.YS.add entry acc + ) + else + acc ) locked entries in let entries = Unlocked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in - Queries.YS.add entry acc + if ghost_var_available ctx (Locked l) then ( + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in + Queries.YS.add entry acc + ) + else + acc ) unlocked entries in let entries = if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let entry = WitnessGhost.variable_entry ~task Multithreaded in - let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in - Queries.YS.add entry (Queries.YS.add entry' entries) + if ghost_var_available ctx Multithreaded then ( + let entry = WitnessGhost.variable_entry ~task Multithreaded in + let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in + Queries.YS.add entry (Queries.YS.add entry' entries) + ) + else + entries ) else entries diff --git a/src/domains/queries.ml b/src/domains/queries.ml index b9b13a7584..9a50af1907 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -130,6 +130,7 @@ type _ t = | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t + | GhostVarAvailable: varinfo -> MustBool.t t type 'a result = 'a @@ -202,6 +203,7 @@ struct | TmpSpecial _ -> (module ML) | MaySignedOverflow _ -> (module MayBool) | YamlEntryGlobal _ -> (module YS) + | GhostVarAvailable _ -> (module MustBool) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -273,6 +275,7 @@ struct | TmpSpecial _ -> ML.top () | MaySignedOverflow _ -> MayBool.top () | YamlEntryGlobal _ -> YS.top () + | GhostVarAvailable _ -> MustBool.top () end (* The type any_query can't be directly defined in Any as t, @@ -341,6 +344,7 @@ struct | Any (MaySignedOverflow _) -> 58 | Any (YamlEntryGlobal _) -> 59 | Any (MustProtectingLocks _) -> 60 + | Any (GhostVarAvailable _) -> 61 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -397,6 +401,7 @@ struct | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 | Any (MaySignedOverflow e1), Any (MaySignedOverflow e2) -> CilType.Exp.compare e1 e2 + | Any (GhostVarAvailable vi1), Any (GhostVarAvailable vi2) -> CilType.Varinfo.compare vi1 vi2 (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) @@ -441,6 +446,7 @@ struct | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv | Any (MaySignedOverflow e) -> CilType.Exp.hash e + | Any (GhostVarAvailable vi) -> CilType.Varinfo.hash vi (* IterSysVars: *) (* - argument is a function and functions cannot be compared in any meaningful way. *) (* - doesn't matter because IterSysVars is always queried from outside of the analysis, so MCP's query caching is not done for it. *) @@ -506,6 +512,7 @@ struct | Any IsEverMultiThreaded -> Pretty.dprintf "IsEverMultiThreaded" | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e + | Any (GhostVarAvailable vi) -> Pretty.dprintf "GhostVarAvailable %a" CilType.Varinfo.pretty vi end let to_value_domain_ask (ask: ask) = diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 2aca886e78..010f450954 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -19,6 +19,8 @@ struct | Locked _ -> assert false | Multithreaded -> "multithreaded" + let describe_varinfo _ _ = "" + let typ = function | Locked _ -> GoblintCil.intType | Multithreaded -> GoblintCil.intType @@ -30,7 +32,7 @@ end include Var -module Map = RichVarinfo.Make (Var) +module Map = RichVarinfo.BiVarinfoMap.Make (Var) include Map diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index ee586bd531..708e27ca64 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -4,7 +4,7 @@ dead: 0 total lines: 23 [Info][Witness] witness generation summary: - total generation entries: 20 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -21,139 +21,11 @@ line: 29 column: 3 function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 37 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 24 - column: 3 - function: fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 37 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 24 - column: 3 - function: fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m2_locked || g2 == 0)' - type: assertion - format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m1_locked || g1 == 0)' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' From c6f12a60491f6650fcb07ba01dd54344a4a30fe3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:57:06 +0300 Subject: [PATCH 069/689] Move LockDomain.Symbolic to SymbLocksDomain --- src/analyses/symbLocks.ml | 4 +-- src/cdomains/lockDomain.ml | 50 -------------------------------- src/cdomains/symbLocksDomain.ml | 51 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 6fd18de6ff..b1727ace81 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -23,8 +23,8 @@ struct exception Top - module D = LockDomain.Symbolic - module C = LockDomain.Symbolic + module D = SymbLocksDomain.Symbolic + module C = SymbLocksDomain.Symbolic let name () = "symb_locks" diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index b22931001b..5aaa441428 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -74,53 +74,3 @@ module MayLocksetNoRW = struct include PreValueDomain.AD end - -module Symbolic = -struct - (* TODO: use SetDomain.Reverse *) - module S = SetDomain.ToppedSet (Exp) (struct let topname = "All mutexes" end) - include Lattice.Reverse (S) - - let rec eq_set (ask: Queries.ask) e = - S.union - (match ask.f (Queries.EqualSet e) with - | es when not (Queries.ES.is_bot es) -> - Queries.ES.fold S.add es (S.empty ()) - | _ -> S.empty ()) - (match e with - | SizeOf _ - | SizeOfE _ - | SizeOfStr _ - | AlignOf _ - | Const _ - | AlignOfE _ - | UnOp _ - | BinOp _ - | Question _ - | Real _ - | Imag _ - | AddrOfLabel _ -> S.empty () - | AddrOf (Var _,_) - | StartOf (Var _,_) - | Lval (Var _,_) -> S.singleton e - | AddrOf (Mem e,ofs) -> S.map (fun e -> AddrOf (Mem e,ofs)) (eq_set ask e) - | StartOf (Mem e,ofs) -> S.map (fun e -> StartOf (Mem e,ofs)) (eq_set ask e) - | Lval (Mem e,ofs) -> S.map (fun e -> Lval (Mem e,ofs)) (eq_set ask e) - | CastE (_,e) -> eq_set ask e - ) - - let add (ask: Queries.ask) e st = - let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in - let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in - S.union addrs st - let remove ask e st = - (* TODO: Removing based on must-equality sets is not sound! *) - let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in - let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in - S.diff st addrs - let remove_var v st = S.filter (fun x -> not (SymbLocksDomain.Exp.contains_var v x)) st - - let filter = S.filter - let fold = S.fold - -end diff --git a/src/cdomains/symbLocksDomain.ml b/src/cdomains/symbLocksDomain.ml index ba2b96e8d0..bb260ad412 100644 --- a/src/cdomains/symbLocksDomain.ml +++ b/src/cdomains/symbLocksDomain.ml @@ -317,3 +317,54 @@ struct let of_mval (v, o) = of_mval (v, conv_const_offset o) end + + +module Symbolic = +struct + (* TODO: use SetDomain.Reverse *) + module S = SetDomain.ToppedSet (Exp) (struct let topname = "All mutexes" end) + include Lattice.Reverse (S) + + let rec eq_set (ask: Queries.ask) e = + S.union + (match ask.f (Queries.EqualSet e) with + | es when not (Queries.ES.is_bot es) -> + Queries.ES.fold S.add es (S.empty ()) + | _ -> S.empty ()) + (match e with + | SizeOf _ + | SizeOfE _ + | SizeOfStr _ + | AlignOf _ + | Const _ + | AlignOfE _ + | UnOp _ + | BinOp _ + | Question _ + | Real _ + | Imag _ + | AddrOfLabel _ -> S.empty () + | AddrOf (Var _,_) + | StartOf (Var _,_) + | Lval (Var _,_) -> S.singleton e + | AddrOf (Mem e,ofs) -> S.map (fun e -> AddrOf (Mem e,ofs)) (eq_set ask e) + | StartOf (Mem e,ofs) -> S.map (fun e -> StartOf (Mem e,ofs)) (eq_set ask e) + | Lval (Mem e,ofs) -> S.map (fun e -> Lval (Mem e,ofs)) (eq_set ask e) + | CastE (_,e) -> eq_set ask e + ) + + let add (ask: Queries.ask) e st = + let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in + let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in + S.union addrs st + let remove ask e st = + (* TODO: Removing based on must-equality sets is not sound! *) + let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in + let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in + S.diff st addrs + let remove_var v st = S.filter (fun x -> not (Exp.contains_var v x)) st + + let filter = S.filter + let fold = S.fold + +end From 8985d64633a0b3d0f6812df8ee784c87f332f499 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:57:37 +0300 Subject: [PATCH 070/689] Extract WitnessGhostVar to break dependency cycle --- src/witness/witnessGhost.ml | 30 +---------------------------- src/witness/witnessGhostVar.ml | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 src/witness/witnessGhostVar.ml diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 010f450954..cdd26b36aa 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,34 +1,6 @@ (** Ghost variables for YAML witnesses. *) -module Var = -struct - type t = - | Locked of LockDomain.Addr.t - | Multithreaded - [@@deriving eq, hash] - - let name_varinfo = function - | Locked (Addr (v, _) as l) -> - let name = - if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then - Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) - else - LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) - in - name ^ "_locked" - | Locked _ -> assert false - | Multithreaded -> "multithreaded" - - let describe_varinfo _ _ = "" - - let typ = function - | Locked _ -> GoblintCil.intType - | Multithreaded -> GoblintCil.intType - - let initial = function - | Locked _ -> GoblintCil.zero - | Multithreaded -> GoblintCil.zero -end +module Var = WitnessGhostVar include Var diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml new file mode 100644 index 0000000000..afcf5d4dba --- /dev/null +++ b/src/witness/witnessGhostVar.ml @@ -0,0 +1,35 @@ +(** Ghost variables for YAML witnesses. *) + +type t = + | Locked of LockDomain.Addr.t + | Multithreaded +[@@deriving eq, ord, hash] + +let name_varinfo = function + | Locked (Addr (v, _) as l) -> + let name = + if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then + Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) + else + LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) + in + name ^ "_locked" + | Locked _ -> assert false + | Multithreaded -> "multithreaded" + +let show = name_varinfo + +include Printable.SimpleShow (struct + type nonrec t = t + let show = show + end) + +let describe_varinfo _ _ = "" + +let typ = function + | Locked _ -> GoblintCil.intType + | Multithreaded -> GoblintCil.intType + +let initial = function + | Locked _ -> GoblintCil.zero + | Multithreaded -> GoblintCil.zero From b04af51f2d86bb20d7908a72948fd97275fdce14 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:58:55 +0300 Subject: [PATCH 071/689] Refactor GhostVarAvailable query --- src/analyses/base.ml | 5 +++-- src/analyses/basePriv.ml | 10 ++++++---- src/analyses/mutexGhosts.ml | 3 +-- src/domains/queries.ml | 12 ++++++------ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index ac31e29163..c1001f8b80 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1247,9 +1247,10 @@ struct if get_bool "exp.earlyglobs" then inv else ( - let var = WitnessGhost.to_varinfo Multithreaded in - if ctx.ask (GhostVarAvailable var) then + if ctx.ask (GhostVarAvailable Multithreaded) then ( + let var = WitnessGhost.to_varinfo Multithreaded in Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) else Invariant.none ) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 129d0d5d69..7a667c9c43 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -342,9 +342,10 @@ struct acc ) cpa Invariant.none in - let var = WitnessGhost.to_varinfo (Locked m') in - if ask.f (GhostVarAvailable var) then + if ask.f (GhostVarAvailable (Locked m')) then ( + let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) else Invariant.none | g -> (* global *) @@ -861,9 +862,10 @@ struct else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> - let var = WitnessGhost.to_varinfo (Locked m) in - if ask.f (GhostVarAvailable var) then + if ask.f (GhostVarAvailable (Locked m)) then ( + let var = WitnessGhost.to_varinfo (Locked m) in Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) else Invariant.none ) locks inv diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 21a12db7a1..5ffdac6110 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -82,8 +82,7 @@ struct let query ctx (type a) (q: a Queries.t): a Queries.result = match q with - | GhostVarAvailable vi -> - GobOption.exists (ghost_var_available ctx) (WitnessGhost.from_varinfo vi) + | GhostVarAvailable v -> ghost_var_available ctx v | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 9a50af1907..44a0402a93 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -130,7 +130,7 @@ type _ t = | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t - | GhostVarAvailable: varinfo -> MustBool.t t + | GhostVarAvailable: WitnessGhostVar.t -> MayBool.t t type 'a result = 'a @@ -203,7 +203,7 @@ struct | TmpSpecial _ -> (module ML) | MaySignedOverflow _ -> (module MayBool) | YamlEntryGlobal _ -> (module YS) - | GhostVarAvailable _ -> (module MustBool) + | GhostVarAvailable _ -> (module MayBool) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -275,7 +275,7 @@ struct | TmpSpecial _ -> ML.top () | MaySignedOverflow _ -> MayBool.top () | YamlEntryGlobal _ -> YS.top () - | GhostVarAvailable _ -> MustBool.top () + | GhostVarAvailable _ -> MayBool.top () end (* The type any_query can't be directly defined in Any as t, @@ -401,7 +401,7 @@ struct | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 | Any (MaySignedOverflow e1), Any (MaySignedOverflow e2) -> CilType.Exp.compare e1 e2 - | Any (GhostVarAvailable vi1), Any (GhostVarAvailable vi2) -> CilType.Varinfo.compare vi1 vi2 + | Any (GhostVarAvailable v1), Any (GhostVarAvailable v2) -> WitnessGhostVar.compare v1 v2 (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) @@ -446,7 +446,7 @@ struct | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv | Any (MaySignedOverflow e) -> CilType.Exp.hash e - | Any (GhostVarAvailable vi) -> CilType.Varinfo.hash vi + | Any (GhostVarAvailable v) -> WitnessGhostVar.hash v (* IterSysVars: *) (* - argument is a function and functions cannot be compared in any meaningful way. *) (* - doesn't matter because IterSysVars is always queried from outside of the analysis, so MCP's query caching is not done for it. *) @@ -512,7 +512,7 @@ struct | Any IsEverMultiThreaded -> Pretty.dprintf "IsEverMultiThreaded" | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e - | Any (GhostVarAvailable vi) -> Pretty.dprintf "GhostVarAvailable %a" CilType.Varinfo.pretty vi + | Any (GhostVarAvailable v) -> Pretty.dprintf "GhostVarAvailable %a" WitnessGhostVar.pretty v end let to_value_domain_ask (ask: ask) = From d8bd13d7a6770e75fc14958a69510b964bdc4937 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 16:23:05 +0300 Subject: [PATCH 072/689] Exclude WitnessGhostVar from docs check --- scripts/goblint-lib-modules.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/goblint-lib-modules.py b/scripts/goblint-lib-modules.py index 017530f838..98b8acd39f 100755 --- a/scripts/goblint-lib-modules.py +++ b/scripts/goblint-lib-modules.py @@ -44,6 +44,7 @@ "MessageCategory", # included in Messages "PreValueDomain", # included in ValueDomain + "WitnessGhostVar", # included in WitnessGhost "ConfigVersion", "ConfigProfile", From 5160bbbb7fe172e10590ac76b52b1bcff42d3222 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 23 Apr 2024 09:17:56 +0200 Subject: [PATCH 073/689] Pass `ctx` to context --- src/analyses/abortUnless.ml | 2 +- src/analyses/accessAnalysis.ml | 2 +- src/analyses/apron/relationAnalysis.apron.ml | 2 +- src/analyses/base.ml | 4 +- src/analyses/callstring.ml | 30 ++++----- src/analyses/mCP.ml | 24 +++---- src/analyses/memLeak.ml | 2 +- src/analyses/memOutOfBounds.ml | 2 +- src/analyses/threadId.ml | 2 +- src/analyses/tutorials/taint.ml | 2 +- src/framework/analyses.ml | 6 +- src/framework/constraints.ml | 66 +++++++++++--------- src/framework/control.ml | 23 +++++-- src/util/wideningTokens.ml | 4 +- src/witness/witnessConstraints.ml | 13 ++-- 15 files changed, 105 insertions(+), 79 deletions(-) diff --git a/src/analyses/abortUnless.ml b/src/analyses/abortUnless.ml index 88937d027a..c3d91d2668 100644 --- a/src/analyses/abortUnless.ml +++ b/src/analyses/abortUnless.ml @@ -13,7 +13,7 @@ struct module D = BoolDomain.MustBool module C = Printable.Unit - let context _ _ = () + let context ctx _ _ = () (* transfer functions *) let assign ctx (lval:lval) (rval:exp) : D.t = diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 24cb7399bc..5be31f0b0a 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -56,7 +56,7 @@ struct let startstate v = () let threadenter ctx ~multiple lval f args = [()] let exitstate v = () - let context fd d = () + let context ctx fd d = () (** Transfer functions: *) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index f1ea72d0a1..3b751b3a1c 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -40,7 +40,7 @@ struct (* Result map used for comparison of results for relational traces paper. *) let results = PCU.RH.create 103 - let context fd x = + let context ctx fd x = if ContextUtil.should_keep ~isAttr:GobContext ~keepOption:"ana.relation.context" ~removeAttr:"relation.no-context" ~keepAttr:"relation.context" fd then x else diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 44649ac31b..385e47a2be 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -618,7 +618,7 @@ struct let drop_intervalSet = CPA.map (function Int x -> Int (ID.no_intervalSet x) | x -> x ) - let context (fd: fundec) (st: store): store = + let context ctx (fd: fundec) (st: store): store = let f keep drop_fn (st: store) = if keep then st else { st with cpa = drop_fn st.cpa} in st |> (* Here earlyglobs only drops syntactic globals from the context and does not consider e.g. escaped globals. *) @@ -1271,7 +1271,7 @@ struct | _, `Bot -> false | `Lifted i1, `Lifted i2 -> ( let divisor_contains_zero = (ID.is_bot @@ ID.meet i2 (ID.of_int ik Z.zero)) in - if divisor_contains_zero then true else + if divisor_contains_zero then true else ( let (min_ik, max_ik) = IntDomain.Size.range ik in let (min_i1, max_i1) = (IntDomain.IntDomTuple.minimal i1, IntDomain.IntDomTuple.maximal i1) in let (min_i2, max_i2) = (IntDomain.IntDomTuple.minimal i2, IntDomain.IntDomTuple.maximal i2) in diff --git a/src/analyses/callstring.ml b/src/analyses/callstring.ml index a8734cdf1c..5ccf7c76b3 100644 --- a/src/analyses/callstring.ml +++ b/src/analyses/callstring.ml @@ -1,7 +1,7 @@ (** - Call String analysis [call_string] and/or Call Site analysis [call_site]. - The call string limitation for both approaches can be adjusted with the "callString_length" option. - By adding new implementations of the CallstringType, additional analyses can be added. + Call String analysis [call_string] and/or Call Site analysis [call_site]. + The call string limitation for both approaches can be adjusted with the "callString_length" option. + By adding new implementations of the CallstringType, additional analyses can be added. *) open Analyses @@ -18,7 +18,7 @@ end (** Analysis with infinite call string or with limited call string (k-CFA, tracks the last k call stack elements). With the CT argument it is possible to specify the type of the call string elements *) -module Spec (CT:CallstringType) : MCPSpec = +module Spec (CT:CallstringType) : MCPSpec = struct include Analyses.IdentitySpec @@ -27,11 +27,11 @@ struct include Printable.PQueue (CT) (* pushes "elem" to the call string, guarantees a depth of k if limitation is specified with "ana.context.callString_length" *) - let push callstr elem = + let push callstr elem = match elem with | None -> callstr - | Some e -> - let new_callstr = BatDeque.cons e callstr in (* pushes new element to callstr *) + | Some e -> + let new_callstr = BatDeque.cons e callstr in (* pushes new element to callstr *) if get_int "ana.context.callString_length" < 0 then new_callstr (* infinite call string *) else (* maximum of k elements *) @@ -41,7 +41,7 @@ struct | _ -> failwith "CallString Error: It shouldn't happen that more than one element must be deleted to maintain the correct height!" end - module D = Lattice.Flat (CallString) (* should be the CallString (C=D). Since a Lattice is required, Lattice.Flat is used to fulfill the type *) + module D = Lattice.Flat (CallString) (* should be the CallString (C=D). Since a Lattice is required, Lattice.Flat is used to fulfill the type *) module C = CallString module V = EmptyV module G = Lattice.Unit @@ -50,13 +50,13 @@ struct let startstate v = `Lifted (BatDeque.empty) let exitstate v = `Lifted (BatDeque.empty) - let context fd x = match x with + let context ctx fd x = match x with | `Lifted x -> x | _ -> failwith "CallString: Context error! The context cannot be derived from Top or Bottom!" - let callee_state ctx f = + let callee_state ctx f = let elem = CT.new_ele f ctx in (* receive element that should be added to call string *) - let new_callstr = CallString.push (context f ctx.local) elem in + let new_callstr = CallString.push (context ctx f ctx.local) elem in `Lifted new_callstr let enter ctx r f args = [ctx.local, callee_state ctx f] @@ -70,9 +70,9 @@ end module Callstring: CallstringType = struct include CilType.Fundec let ana_name = "string" - let new_ele f ctx = - let f' = Node.find_fundec ctx.node in - if CilType.Fundec.equal f' dummyFunDec + let new_ele f ctx = + let f' = Node.find_fundec ctx.node in + if CilType.Fundec.equal f' dummyFunDec then None else Some f' end @@ -80,7 +80,7 @@ end module Callsite: CallstringType = struct include CilType.Stmt let ana_name = "site" - let new_ele f ctx = + let new_ele f ctx = match ctx.prev_node with | Statement stmt -> Some stmt | _ -> None (* first statement is filtered *) diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 1ead43e7d8..fd19c7f47e 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -83,10 +83,10 @@ struct check_deps !activated; activated := topo_sort_an !activated; begin - match get_string_list "ana.ctx_sens" with + match get_string_list "ana.ctx_sens" with | [] -> (* use values of "ana.ctx_insens" (blacklist) *) let cont_inse = map' find_id @@ get_string_list "ana.ctx_insens" in - activated_ctx_sens := List.filter (fun (n, _) -> not (List.mem n cont_inse)) !activated; + activated_ctx_sens := List.filter (fun (n, _) -> not (List.mem n cont_inse)) !activated; | sens -> (* use values of "ana.ctx_sens" (whitelist) *) let cont_sens = map' find_id @@ sens in activated_ctx_sens := List.filter (fun (n, _) -> List.mem n cont_sens) !activated; @@ -113,15 +113,6 @@ struct let ys = fold_left one_el [] xs in List.rev ys, !dead - let context fd x = - let x = spec_list x in - filter_map (fun (n,(module S:MCPSpec),d) -> - if Set.is_empty !act_cont_sens || not (Set.mem n !act_cont_sens) then (*n is insensitive*) - None - else - Some (n, repr @@ S.context fd (obj d)) - ) x - let exitstate v = map (fun (n,{spec=(module S:MCPSpec); _}) -> n, repr @@ S.exitstate v) !activated let startstate v = map (fun (n,{spec=(module S:MCPSpec); _}) -> n, repr @@ S.startstate v) !activated let morphstate v x = map (fun (n,(module S:MCPSpec),d) -> n, repr @@ S.morphstate v (obj d)) (spec_list x) @@ -235,6 +226,17 @@ struct if M.tracing then M.traceu "event" ""; ctx'.local + and context ctx fd x = + let ctx'' = outer_ctx "context_computation" ctx in + let x = spec_list x in + filter_map (fun (n,(module S:MCPSpec),d) -> + if Set.is_empty !act_cont_sens || not (Set.mem n !act_cont_sens) then (*n is insensitive*) + None + else + let ctx' : (S.D.t, S.G.t, S.C.t, S.V.t) ctx = inner_ctx "context_computation" ctx'' n d in + Some (n, repr @@ S.context ctx' fd (obj d)) + ) x + and branch (ctx:(D.t, G.t, C.t, V.t) ctx) (e:exp) (tv:bool) = let spawns = ref [] in let splits = ref [] in diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index f2d707067d..7c7cc7b16c 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -20,7 +20,7 @@ struct module V = UnitV module G = WasMallocCalled - let context _ d = d + let context ctx _ d = d let must_be_single_threaded ~since_start ctx = ctx.ask (Queries.MustBeSingleThreaded { since_start }) diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 51304f5bf5..3a763cdba3 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -22,7 +22,7 @@ struct module D = Lattice.Unit module C = D - let context _ _ = () + let context ctx _ _ = () let name () = "memOutOfBounds" diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index 70ae13661e..ae9c8f5357 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -60,7 +60,7 @@ struct let name () = "threadid" - let context fd ((n,current,td) as d) = + let context ctx fd ((n,current,td) as d) = if GobConfig.get_bool "ana.thread.context.create-edges" then d else diff --git a/src/analyses/tutorials/taint.ml b/src/analyses/tutorials/taint.ml index 1015188d88..0193a423df 100644 --- a/src/analyses/tutorials/taint.ml +++ b/src/analyses/tutorials/taint.ml @@ -28,7 +28,7 @@ struct module C = Printable.Unit (* We are context insensitive in this analysis *) - let context _ _ = () + let context ctx _ _ = () (** Determines whether an expression [e] is tainted, given a [state]. *) let rec is_exp_tainted (state:D.t) (e:Cil.exp) = match e with diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index c8464f6e84..49a638d951 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -206,7 +206,7 @@ sig val morphstate : varinfo -> D.t -> D.t val exitstate : varinfo -> D.t - val context : fundec -> D.t -> C.t + val context : (D.t, G.t, C.t, V.t) ctx -> fundec -> D.t -> C.t val sync : (D.t, G.t, C.t, V.t) ctx -> [`Normal | `Join | `Return] -> D.t val query : (D.t, G.t, C.t, V.t) ctx -> 'a Queries.t -> 'a Queries.result @@ -375,7 +375,7 @@ struct let sync ctx _ = ctx.local (* Most domains do not have a global part. *) - let context fd x = x + let context ctx fd x = x (* Everything is context sensitive --- override in MCP and maybe elsewhere*) let paths_as_set ctx = [ctx.local] @@ -420,7 +420,7 @@ module IdentityUnitContextsSpec = struct include IdentitySpec module C = Printable.Unit - let context _ _ = () + let context ctx _ _ = () end module type SpecSys = diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 1f2bf29f51..3af13a6a8a 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -43,13 +43,13 @@ struct let exitstate v = D.lift (S.exitstate v) let morphstate v d = D.lift (S.morphstate v (D.unlift d)) - let context fd = S.context fd % D.unlift - let conv ctx = { ctx with local = D.unlift ctx.local ; split = (fun d es -> ctx.split (D.lift d) es ) } + let context ctx fd = S.context (conv ctx) fd % D.unlift + let sync ctx reason = D.lift @@ S.sync (conv ctx) reason @@ -125,11 +125,11 @@ struct let exitstate = S.exitstate let morphstate = S.morphstate - let context fd = C.lift % S.context fd - let conv ctx = { ctx with context = (fun () -> C.unlift (ctx.context ())) } + let context ctx fd = C.lift % S.context (conv ctx) fd + let sync ctx reason = S.sync (conv ctx) reason @@ -224,13 +224,13 @@ struct let exitstate v = (S.exitstate v, !start_level) let morphstate v (d,l) = (S.morphstate v d, l) - let context fd (d,_) = S.context fd d - let conv ctx = { ctx with local = fst ctx.local ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) } + let context ctx fd (d,_) = S.context (conv ctx) fd d + let lift_fun ctx f g h = f @@ h (g (conv ctx)) @@ -379,12 +379,14 @@ struct let exitstate = inj S.exitstate let morphstate v (d,m) = S.morphstate v d, m - let context fd (d,m) = S.context fd d (* just the child analysis' context *) let conv ctx = { ctx with local = fst ctx.local ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) } + + let context ctx fd (d,m) = S.context (conv ctx) fd d (* just the child analysis' context *) + let lift_fun ctx f g = g (f (conv ctx)), snd ctx.local let sync ctx reason = lift_fun ctx S.sync ((|>) reason) @@ -457,13 +459,14 @@ struct let exitstate v = `Lifted (S.exitstate v) let morphstate v d = try `Lifted (S.morphstate v (D.unlift d)) with Deadcode -> d - let context fd = S.context fd % D.unlift let conv ctx = { ctx with local = D.unlift ctx.local ; split = (fun d es -> ctx.split (D.lift d) es ) } + let context ctx fd = S.context (conv ctx) fd % D.unlift + let lift_fun ctx f g h b = try f @@ h (g (conv ctx)) with Deadcode -> b @@ -498,7 +501,7 @@ struct end module NoContext = struct let name = "no context" end -module IntConf = +module IntConf = struct let n () = max_int let names x = Format.asprintf "%d" x @@ -507,15 +510,15 @@ end (** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) module ContextGasLifter (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Lattice.Chain (IntConf)) + : Spec with module D = Lattice.Prod (S.D) (Lattice.Chain (IntConf)) and module C = Printable.Option (S.C) (NoContext) and module G = S.G = struct include S - module Context_Gas_Prod (Base1: Lattice.S) (Base2: Lattice.S) = - struct + module Context_Gas_Prod (Base1: Lattice.S) (Base2: Lattice.S) = + struct include Lattice.Prod (Base1) (Base2) let printXml f (x,y) = BatPrintf.fprintf f "\n\n\n%s\n\n%a\nContext Gas Value\n\n%a\n\n" (XmlUtil.escape (Base1.name ())) Base1.printXml x Base2.printXml y @@ -542,12 +545,8 @@ struct let exitstate v = S.exitstate v, get_int "ana.context.gas_value" let morphstate v (d,i) = S.morphstate v d, i - let context fd (d,i) = - (* only keep context if the context gas is greater zero *) - if i <= 0 then None else Some (S.context fd d) - let conv (ctx:(D.t,G.t,C.t,V.t) ctx): (S.D.t,G.t,S.C.t,V.t)ctx = - if (cg_val ctx <= 0) + if (cg_val ctx <= 0) then {ctx with local = fst ctx.local ; split = (fun d es -> ctx.split (d, cg_val ctx) es) ; context = (fun () -> ctx_failwith "no context (contextGas = 0)")} @@ -555,14 +554,18 @@ struct ; split = (fun d es -> ctx.split (d, cg_val ctx) es) ; context = (fun () -> Option.get (ctx.context ()))} + let context ctx fd (d,i) = + (* only keep context if the context gas is greater zero *) + if i <= 0 then None else Some (S.context (conv ctx) fd d) + let enter ctx r f args = (* callee gas = caller gas - 1 *) let liftmap_tup = List.map (fun (x,y) -> (x, cg_val ctx), (y, max 0 (cg_val ctx - 1))) in - liftmap_tup (S.enter (conv ctx) r f args) + liftmap_tup (S.enter (conv ctx) r f args) - let threadenter ctx ~multiple lval f args = + let threadenter ctx ~multiple lval f args = let liftmap f = List.map (fun (x) -> (x, max 0 (cg_val ctx - 1))) f in - liftmap (S.threadenter (conv ctx) ~multiple lval f args) + liftmap (S.threadenter (conv ctx) ~multiple lval f args) let sync ctx reason = S.sync (conv ctx) reason, cg_val ctx let query ctx q = S.query (conv ctx) q @@ -576,7 +579,7 @@ struct let special ctx r f args = S.special (conv ctx) r f args, cg_val ctx let combine_env ctx r fe f args fc es f_ask = S.combine_env (conv ctx) r fe f args (Option.bind fc Fun.id) (fst es) f_ask, cg_val ctx let combine_assign ctx r fe f args fc es f_ask = S.combine_assign (conv ctx) r fe f args (Option.bind fc Fun.id) (fst es) f_ask, cg_val ctx - let paths_as_set ctx = List.map (fun (x) -> (x, cg_val ctx)) @@ S.paths_as_set (conv ctx) + let paths_as_set ctx = List.map (fun (x) -> (x, cg_val ctx)) @@ S.paths_as_set (conv ctx) let threadspawn ctx ~multiple lval f args fctx = S.threadspawn (conv ctx) ~multiple lval f args (conv fctx), cg_val ctx let event ctx e octx = S.event (conv ctx) e (conv octx), cg_val ctx end @@ -648,7 +651,7 @@ struct spawns := (lval, f, args, d, multiple) :: !spawns; match Cilfacade.find_varinfo_fundec f with | fd -> - let c = S.context fd d in + let c = S.context ctx fd d in sidel (FunctionEntry fd, c) d; ignore (getl (Function fd, c)) | exception Not_found -> @@ -789,7 +792,7 @@ struct r in let paths = S.enter ctx lv f args in - let paths = List.map (fun (c,v) -> (c, S.context f v, v)) paths in + let paths = List.map (fun (c,v) -> (c, S.context ctx f v, v)) paths in List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then sidel (FunctionEntry f, fc) v) paths; let paths = List.map (fun (c,fc,v) -> (c, fc, if S.D.is_bot v then v else getl (Function f, fc))) paths in (* Don't filter bot paths, otherwise LongjmpLifter is not called. *) @@ -1150,12 +1153,6 @@ struct let startstate v = D.singleton (Spec.startstate v) let morphstate v d = D.map (Spec.morphstate v) d - let context fd l = - if D.cardinal l <> 1 then - failwith "PathSensitive2.context must be called with a singleton set." - else - Spec.context fd @@ D.choose l - let conv ctx x = let rec ctx' = { ctx with ask = (fun (type a) (q: a Queries.t) -> Spec.query ctx' q) ; local = x @@ -1163,6 +1160,14 @@ struct in ctx' + let context ctx fd l = + if D.cardinal l <> 1 then + failwith "PathSensitive2.context must be called with a singleton set." + else + let x = D.choose l in + Spec.context (conv ctx x) fd x + + let map ctx f g = let h x xs = try D.add (g (f (conv ctx x))) xs @@ -1352,6 +1357,7 @@ struct let branch ctx = S.branch (conv ctx) + let context ctx = S.context (conv ctx) let branch ctx exp tv = if !AnalysisState.postsolving then ( @@ -1466,6 +1472,7 @@ struct let paths_as_set ctx = S.paths_as_set (conv ctx) let body ctx = S.body (conv ctx) let return ctx = S.return (conv ctx) + let context ctx = S.context (conv ctx) let combine_env ctx lv e f args fc fd f_ask = let conv_ctx = conv ctx in @@ -1746,6 +1753,7 @@ struct sideg (V.call callee) (G.create_singleton_caller caller) let enter ctx = S.enter (conv ctx) + let context ctx = S.context (conv ctx) let paths_as_set ctx = S.paths_as_set (conv ctx) let body ctx = S.body (conv ctx) let return ctx = S.return (conv ctx) diff --git a/src/framework/control.ml b/src/framework/control.ml index 714a83b236..9a6a4342da 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -23,7 +23,7 @@ let spec_module: (module Spec) Lazy.t = lazy ( let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter) + |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) @@ -458,14 +458,29 @@ struct AnalysisState.global_initialization := false; + let ctx e = + { ask = (fun (type a) (q: a Queries.t) -> Queries.Result.top q) + ; emit = (fun _ -> failwith "Cannot \"emit\" in enter_with context.") + ; node = MyCFG.dummy_node + ; prev_node = MyCFG.dummy_node + ; control_context = (fun () -> ctx_failwith "enter_func has no context.") + ; context = (fun () -> ctx_failwith "enter_func has no context.") + ; edge = MyCFG.Skip + ; local = e + ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) + ; 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)) + } + in let startvars' = if get_bool "exp.forward" then - List.map (fun (n,e) -> (MyCFG.FunctionEntry n, Spec.context n e)) startvars + List.map (fun (n,e) -> (MyCFG.FunctionEntry n, Spec.context (ctx e) n e)) startvars else - List.map (fun (n,e) -> (MyCFG.Function n, Spec.context n e)) startvars + List.map (fun (n,e) -> (MyCFG.Function n, Spec.context (ctx e) n e)) startvars in - let entrystates = List.map (fun (n,e) -> (MyCFG.FunctionEntry n, Spec.context n e), e) startvars in + let entrystates = List.map (fun (n,e) -> (MyCFG.FunctionEntry n, Spec.context (ctx e) n e), e) startvars in let entrystates_global = GHT.to_list gh in let uncalled_dead = ref 0 in diff --git a/src/util/wideningTokens.ml b/src/util/wideningTokens.ml index 1816de90c7..f8c508d411 100644 --- a/src/util/wideningTokens.ml +++ b/src/util/wideningTokens.ml @@ -126,8 +126,6 @@ struct let exitstate v = (S.exitstate v, TS.bot ()) let morphstate v (d, t) = (S.morphstate v d, t) - let context fd = S.context fd % D.unlift - let conv (ctx: (D.t, G.t, C.t, V.t) ctx): (S.D.t, S.G.t, S.C.t, S.V.t) ctx = { ctx with local = D.unlift ctx.local ; split = (fun d es -> ctx.split (d, snd ctx.local) es) (* Split keeps local widening tokens. *) @@ -135,6 +133,8 @@ struct ; sideg = (fun v g -> ctx.sideg v (g, !side_tokens)) (* Using side_tokens for side effect. *) } + let context ctx fd = S.context (conv ctx) fd % D.unlift + let lift_fun ctx f g h = let new_tokens = ref (snd ctx.local) in (* New tokens not yet used during this transfer function, such that it is deterministic. *) let old_add = !add_ref in diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index 4af9dd898d..3e4185a1e4 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -107,12 +107,6 @@ struct let startstate v = (Dom.singleton (Spec.startstate v) (R.bot ()), Sync.bot ()) let morphstate v (d, _) = (Dom.map_keys (Spec.morphstate v) d, Sync.bot ()) - let context fd (l, _) = - if Dom.cardinal l <> 1 then - failwith "PathSensitive3.context must be called with a singleton set." - else - Spec.context fd @@ Dom.choose_key l - let step n c i e = R.singleton ((n, c, i), e) let step n c i e sync = match Sync.find i sync with @@ -146,6 +140,13 @@ struct in ctx' + let context ctx fd (l, _) = + if Dom.cardinal l <> 1 then + failwith "PathSensitive3.context must be called with a singleton set." + else + let x = Dom.choose_key l in + Spec.context (conv ctx x) fd @@ x + let map ctx f g = (* we now use Sync for every tf such that threadspawn after tf could look up state before tf *) let h x (xs, sync) = From 6e6126040c42f7e92fc7414d38a97b74ceb9daf7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 23 Apr 2024 09:47:58 +0200 Subject: [PATCH 074/689] Simplify callstring --- src/analyses/callstring.ml | 31 +++++++++++-------------------- src/framework/analyses.ml | 3 +++ src/framework/control.ml | 8 ++++---- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/analyses/callstring.ml b/src/analyses/callstring.ml index 5ccf7c76b3..57e8250810 100644 --- a/src/analyses/callstring.ml +++ b/src/analyses/callstring.ml @@ -20,12 +20,14 @@ end With the CT argument it is possible to specify the type of the call string elements *) module Spec (CT:CallstringType) : MCPSpec = struct - include Analyses.IdentitySpec + include UnitAnalysis.Spec (* simulates a call string (with or without limitation)*) module CallString = struct include Printable.PQueue (CT) + let (empty:t) = BatDeque.empty + (* pushes "elem" to the call string, guarantees a depth of k if limitation is specified with "ana.context.callString_length" *) let push callstr elem = match elem with @@ -41,29 +43,18 @@ struct | _ -> failwith "CallString Error: It shouldn't happen that more than one element must be deleted to maintain the correct height!" end - module D = Lattice.Flat (CallString) (* should be the CallString (C=D). Since a Lattice is required, Lattice.Flat is used to fulfill the type *) module C = CallString - module V = EmptyV - module G = Lattice.Unit let name () = "call_"^ CT.ana_name - let startstate v = `Lifted (BatDeque.empty) - let exitstate v = `Lifted (BatDeque.empty) - - let context ctx fd x = match x with - | `Lifted x -> x - | _ -> failwith "CallString: Context error! The context cannot be derived from Top or Bottom!" - - let callee_state ctx f = - let elem = CT.new_ele f ctx in (* receive element that should be added to call string *) - let new_callstr = CallString.push (context ctx f ctx.local) elem in - `Lifted new_callstr - - let enter ctx r f args = [ctx.local, callee_state ctx f] - - let combine_env ctx lval fexp f args fc au f_ask = ctx.local - let threadenter ctx ~multiple lval v args = [callee_state ctx (Cilfacade.find_varinfo_fundec v)] + let context ctx fd _ = + let curr_ctx = + try + ctx.context () + with Enter_func_has_no_context -> CallString.empty + in + let elem = CT.new_ele fd ctx in (* receive element that should be added to call string *) + CallString.push curr_ctx elem end (* implementations of CallstringTypes*) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 49a638d951..ae93d863c1 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -171,8 +171,11 @@ type ('d,'g,'c,'v) ctx = exception Ctx_failure of string (** Failure from ctx, e.g. global initializer *) +exception Enter_func_has_no_context +(** Tried to call ctx() on enter_func. Caught by callstring-based approaches and turned into an initial context *) let ctx_failwith s = raise (Ctx_failure s) (* TODO: use everywhere in ctx *) +let enter_func_has_no_context () = raise Enter_func_has_no_context (** Convert [ctx] to [Queries.ask]. *) let ask_of_ctx ctx: Queries.ask = { Queries.f = ctx.ask } diff --git a/src/framework/control.ml b/src/framework/control.ml index 9a6a4342da..2054a750d4 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -404,8 +404,8 @@ struct ; emit = (fun _ -> failwith "Cannot \"emit\" in enter_with context.") ; node = MyCFG.dummy_node ; prev_node = MyCFG.dummy_node - ; control_context = (fun () -> ctx_failwith "enter_func has no context.") - ; context = (fun () -> ctx_failwith "enter_func has no context.") + ; control_context = enter_func_has_no_context + ; context = enter_func_has_no_context ; edge = MyCFG.Skip ; local = st ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) @@ -463,8 +463,8 @@ struct ; emit = (fun _ -> failwith "Cannot \"emit\" in enter_with context.") ; node = MyCFG.dummy_node ; prev_node = MyCFG.dummy_node - ; control_context = (fun () -> ctx_failwith "enter_func has no context.") - ; context = (fun () -> ctx_failwith "enter_func has no context.") + ; control_context = enter_func_has_no_context + ; context = enter_func_has_no_context ; edge = MyCFG.Skip ; local = e ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) From 19ef33c38df994718742311c776eb783793d7bdf Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Tue, 23 Apr 2024 10:01:10 +0200 Subject: [PATCH 075/689] Simplify loopfreeCallstring --- src/analyses/callstring.ml | 4 +- src/analyses/loopfreeCallstring.ml | 78 ++++++++++++++---------------- src/witness/witnessConstraints.ml | 2 +- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/analyses/callstring.ml b/src/analyses/callstring.ml index 57e8250810..cb65011860 100644 --- a/src/analyses/callstring.ml +++ b/src/analyses/callstring.ml @@ -48,13 +48,13 @@ struct let name () = "call_"^ CT.ana_name let context ctx fd _ = - let curr_ctx = + let curr_context = try ctx.context () with Enter_func_has_no_context -> CallString.empty in let elem = CT.new_ele fd ctx in (* receive element that should be added to call string *) - CallString.push curr_ctx elem + CallString.push curr_context elem end (* implementations of CallstringTypes*) diff --git a/src/analyses/loopfreeCallstring.ml b/src/analyses/loopfreeCallstring.ml index 172114d37c..f5c9867e1f 100644 --- a/src/analyses/loopfreeCallstring.ml +++ b/src/analyses/loopfreeCallstring.ml @@ -1,60 +1,54 @@ -(** +(** Loopfree Callstring analysis [loopfree_callstring] that reduces the call string length of the classical Call String approach for recursions - The idea is to improve the Call String analysis by representing all detected call cycle of the call string in a set + The idea is to improve the Call String analysis by representing all detected call cycle of the call string in a set In case no call cycles appears, the call string is identical to the call string of the Call String approach - For example: + For example: - call string [main, a, b, c, a] is represented as [main, {a, b, c}] - call string [main, a, a, b, b, b] is represented as [main, {a}, {b}] This approach is inspired by - @see Schwarz, M., Saan, S., Seidl, H., Erhard, J., Vojdani, V. Clustered Relational Thread-Modular Abstract Interpretation with Local Traces. Appendix F. + @see Schwarz, M., Saan, S., Seidl, H., Erhard, J., Vojdani, V. Clustered Relational Thread-Modular Abstract Interpretation with Local Traces. Appendix F. *) open Analyses module Spec : MCPSpec = struct - include Analyses.IdentitySpec + include UnitAnalysis.Spec let name () = "loopfree_callstring" module FundecSet = SetDomain.Make (CilType.Fundec) - module Either = Printable.Either (CilType.Fundec) (FundecSet) - - module D = Lattice.Flat (Printable.Liszt (Either)) (* A domain element is a list containing fundecs and sets of fundecs.*) - module C = D - module V = EmptyV - module G = Lattice.Unit - let startstate v = `Lifted([]) - let exitstate v = `Lifted([]) - - let get_list list = match list with - | `Lifted e -> e - | _ -> failwith "Error loopfreeCallstring (get_list): The list cannot be derived from Top or Bottom!" - - let loop_detected f = function - (* note: a call string contains each Fundec at most once *) - | `Left ele -> CilType.Fundec.equal f ele - | `Right set -> FundecSet.mem f set - - let add_to_set old = function - | `Left ele -> FundecSet.add ele old - | `Right set -> FundecSet.join old set - - let rec callee_state f prev_set prev_list = function - | [] -> (`Left f)::(List.rev prev_list) (* f is not yet contained in the call string *) - | e::rem_list -> - let new_set = add_to_set prev_set e in - if loop_detected f e (* f is already present in the call string *) - then (`Right new_set)::rem_list (* combine all elements of the call cycle in a set *) - else callee_state f new_set (e::prev_list) rem_list - - let callee_state f ctx = `Lifted(callee_state f (FundecSet.empty ()) [] (get_list ctx.local)) - - let enter ctx r f args = [ctx.local, callee_state f ctx] - - let threadenter ctx ~multiple lval v args = [callee_state (Cilfacade.find_varinfo_fundec v) ctx] - - let combine_env ctx lval fexp f args fc au f_ask = ctx.local + module Either = Printable.Either (CilType.Fundec) (FundecSet) + + module C = Printable.Liszt (Either) + + let append fd current = + let loop_detected f = function + (* note: a call string contains each Fundec at most once *) + | `Left ele -> CilType.Fundec.equal f ele + | `Right set -> FundecSet.mem f set + in + let add_to_set old = function + | `Left ele -> FundecSet.add ele old + | `Right set -> FundecSet.join old set + in + let rec append f prev_set prev_list = function + | [] -> (`Left f)::(List.rev prev_list) (* f is not yet contained in the call string *) + | e::rem_list -> + let new_set = add_to_set prev_set e in + if loop_detected f e (* f is already present in the call string *) + then (`Right new_set)::rem_list (* combine all elements of the call cycle in a set *) + else append f new_set (e::prev_list) rem_list + in + append fd (FundecSet.empty ()) [] current + + let context ctx fd x = + let curr_context = + try + ctx.context () + with Enter_func_has_no_context -> [] + in + append fd curr_context end let _ = MCP.register_analysis (module Spec : MCPSpec) diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index 3e4185a1e4..5e8e97d380 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -120,7 +120,7 @@ struct let step_ctx ctx x e = try step ctx.prev_node (ctx.context ()) x e (snd ctx.local) - with Ctx_failure _ -> + with Ctx_failure _ | Enter_func_has_no_context -> R.bot () let step_ctx_edge ctx x = step_ctx ctx x (CFGEdge ctx.edge) let step_ctx_inlined_edge ctx x = step_ctx ctx x (InlinedEdge ctx.edge) From 947d6bc4382c36778c5f6de2d07b07be9637a7ab Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 12:51:14 +0300 Subject: [PATCH 076/689] Fix __VERIFIER_atomic special mutex ghost varialbe name --- src/witness/witnessGhostVar.ml | 5 +- tests/regression/29-svcomp/16-atomic_priv.t | 88 +++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/regression/29-svcomp/16-atomic_priv.t diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index afcf5d4dba..bc0f98f915 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -8,10 +8,13 @@ type t = let name_varinfo = function | Locked (Addr (v, _) as l) -> let name = + if CilType.Varinfo.equal v LibraryFunctions.verifier_atomic_var then + "__VERIFIER_atomic" + else if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) else - LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) + LockDomain.Addr.show l (* TODO: valid names with fields, interval offsets, etc *) in name ^ "_locked" | Locked _ -> assert false diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t new file mode 100644 index 0000000000..98584b96d0 --- /dev/null +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -0,0 +1,88 @@ + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) + [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:24:3-24:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:26:3-26:33) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 17 + dead: 0 + total lines: 17 + [Warning][Race] Memory location myglobal (race with conf. 110): (16-atomic_priv.c:8:5-8:17) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) + read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 1 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: __VERIFIER_atomic_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || myglobal == 5' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' + type: assertion + format: C From 4ada6eb2ced86b2021bde12937a237d716b6daa4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 12:55:56 +0300 Subject: [PATCH 077/689] Avoid emitting useless protected invariants from protection privatization --- src/analyses/basePriv.ml | 2 ++ tests/regression/29-svcomp/16-atomic_priv.t | 7 +------ tests/regression/56-witness/64-ghost-multiple-protecting.t | 7 +------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7a667c9c43..7cadf637ad 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -859,6 +859,8 @@ struct let locks = ask.f (Q.MustProtectingLocks g') in if Q.AD.is_top locks || Q.AD.is_empty locks then Invariant.none + else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then + Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 98584b96d0..15425f68dd 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -13,7 +13,7 @@ write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 8 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -81,8 +81,3 @@ string: '! multithreaded || myglobal == 5' type: assertion format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' - type: assertion - format: C diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index d51db2285e..53323355c5 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -4,7 +4,7 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 18 + total generation entries: 17 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -133,11 +133,6 @@ protection doesn't have precise protected invariant for g2. string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' type: assertion format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m2_locked || (m1_locked || (0 <= g2 && g2 <= 1)))' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' From a7d43a938181ca404666147d2fc705c09a0fa8e4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 13:04:26 +0300 Subject: [PATCH 078/689] Avoid useless work in mutex-meet invariant_global if ghost variable isn't available --- src/analyses/basePriv.ml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7cadf637ad..799290c4fe 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -333,16 +333,16 @@ struct let invariant_global (ask: Q.ask) getg = function | `Left m' as m -> (* mutex *) - let cpa = getg m in - let inv = CPA.fold (fun v _ acc -> - if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then - let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in - Invariant.(acc && inv) - else - acc - ) cpa Invariant.none - in if ask.f (GhostVarAvailable (Locked m')) then ( + let cpa = getg m in + let inv = CPA.fold (fun v _ acc -> + if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then + let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in + Invariant.(acc && inv) + else + acc + ) cpa Invariant.none + in let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) From d6abc0b4f14dccbd1c500ce3a9e23f72497aa966 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 13:44:29 +0300 Subject: [PATCH 079/689] Fix struct field mutex ghost variable name --- src/witness/witnessGhostVar.ml | 11 ++- tests/regression/13-privatized/25-struct_nr.t | 83 +++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 tests/regression/13-privatized/25-struct_nr.t diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index bc0f98f915..cac48050de 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -6,7 +6,7 @@ type t = [@@deriving eq, ord, hash] let name_varinfo = function - | Locked (Addr (v, _) as l) -> + | Locked (Addr (v, os)) -> let name = if CilType.Varinfo.equal v LibraryFunctions.verifier_atomic_var then "__VERIFIER_atomic" @@ -14,9 +14,14 @@ let name_varinfo = function if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) else - LockDomain.Addr.show l (* TODO: valid names with fields, interval offsets, etc *) + Basetype.Variables.show v in - name ^ "_locked" + let rec offs: LockDomain.Addr.Offs.t -> string = function + | `NoOffset -> "" + | `Field (f, os') -> "_" ^ f.fname ^ offs os' + | `Index (i, os') -> failwith "TODO" (* TODO: valid names with interval offsets, etc *) + in + name ^ offs os ^ "_locked" | Locked _ -> assert false | Multithreaded -> "multithreaded" diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t new file mode 100644 index 0000000000..f3ebcd1c52 --- /dev/null +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -0,0 +1,83 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 25-struct_nr.c + [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) + [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) + [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) + [Success][Assert] Assertion "glob1 == 6" will succeed (25-struct_nr.c:30:3-30:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "1" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "1" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "0" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 32 + column: 3 + function: main + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "0" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: lock1_mutex_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (lock1_mutex_locked || glob1 == 5)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((-128 <= glob1 && glob1 <= 127) && glob1 != 0)' + type: assertion + format: C From 6db1d04eeb551a5726bb373e7cc6e6e0394a4368 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 14:34:05 +0300 Subject: [PATCH 080/689] Fix definite array index mutex ghost variable name --- src/witness/witnessGhostVar.ml | 5 +- tests/regression/13-privatized/80-idx_priv.c | 26 +++++++ tests/regression/13-privatized/80-idx_priv.t | 80 ++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 tests/regression/13-privatized/80-idx_priv.c create mode 100644 tests/regression/13-privatized/80-idx_priv.t diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index cac48050de..cec61b0e2d 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -19,7 +19,10 @@ let name_varinfo = function let rec offs: LockDomain.Addr.Offs.t -> string = function | `NoOffset -> "" | `Field (f, os') -> "_" ^ f.fname ^ offs os' - | `Index (i, os') -> failwith "TODO" (* TODO: valid names with interval offsets, etc *) + | `Index (i, os') -> + match ValueDomain.ID.to_int i with + | Some i -> assert Z.Compare.(i >= Z.zero); "_" ^ Z.to_string i + | _ -> assert false (* must locksets cannot have ambiguous indices *) in name ^ offs os ^ "_locked" | Locked _ -> assert false diff --git a/tests/regression/13-privatized/80-idx_priv.c b/tests/regression/13-privatized/80-idx_priv.c new file mode 100644 index 0000000000..ed0e8d3228 --- /dev/null +++ b/tests/regression/13-privatized/80-idx_priv.c @@ -0,0 +1,26 @@ +#include +#include + +int data; +pthread_mutex_t m[10]; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[4]); + data++; // NORACE + data--; // NORACE + pthread_mutex_unlock(&m[4]); + return NULL; +} + +int main() { + for (int i = 0; i < 10; i++) + pthread_mutex_init(&m[i], NULL); + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&m[4]); + __goblint_check(data == 0); // NORACE + pthread_mutex_unlock(&m[4]); + return 0; +} + diff --git a/tests/regression/13-privatized/80-idx_priv.t b/tests/regression/13-privatized/80-idx_priv.t new file mode 100644 index 0000000000..698744924c --- /dev/null +++ b/tests/regression/13-privatized/80-idx_priv.t @@ -0,0 +1,80 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 80-idx_priv.c + [Success][Assert] Assertion "data == 0" will succeed (80-idx_priv.c:22:3-22:29) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "1" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "1" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_4_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_4_locked || data == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= data && data <= 1)' + type: assertion + format: C From 53a714fe979757f8f71c1ea408f3a3e5ccd4120c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 15:28:26 +0300 Subject: [PATCH 081/689] Make non-definite ghost variables unavailable --- src/analyses/mutexGhosts.ml | 2 +- .../56-witness/68-ghost-ambiguous-idx.c | 28 +++++++ .../56-witness/68-ghost-ambiguous-idx.t | 78 +++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/regression/56-witness/68-ghost-ambiguous-idx.c create mode 100644 tests/regression/56-witness/68-ghost-ambiguous-idx.t diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 5ffdac6110..128355e919 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -77,7 +77,7 @@ struct ctx.local let ghost_var_available ctx = function - | WitnessGhost.Var.Locked lock -> not (G.lock (ctx.global (V.lock lock)): bool) + | WitnessGhost.Var.Locked lock -> LockDomain.Addr.is_definite lock && not (G.lock (ctx.global (V.lock lock))) | Multithreaded -> true let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.c b/tests/regression/56-witness/68-ghost-ambiguous-idx.c new file mode 100644 index 0000000000..7babbe003c --- /dev/null +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.c @@ -0,0 +1,28 @@ +#include +#include + +int data; +pthread_mutex_t m[10]; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[4]); + data++; + data--; + pthread_mutex_unlock(&m[4]); + return NULL; +} + +int main() { + for (int i = 0; i < 10; i++) + pthread_mutex_init(&m[i], NULL); + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + int r; + int j = r ? 4 : 5; + pthread_mutex_lock(&m[r]); + __goblint_check(data == 0); // UNKNOWN! + pthread_mutex_unlock(&m[4]); + return 0; +} + diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t new file mode 100644 index 0000000000..0f6191188e --- /dev/null +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -0,0 +1,78 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 68-ghost-ambiguous-idx.c + [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) + [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 15 + dead: 0 + total lines: 15 + [Warning][Race] Memory location data (race with conf. 110): (68-ghost-ambiguous-idx.c:4:5-4:9) + write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:9:3-9:9) + write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) + read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) + [Info][Witness] witness generation summary: + total generation entries: 8 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 1 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "1" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_4_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_4_locked || data == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= data && data <= 1)' + type: assertion + format: C + +TODO: there shouldn't be invariant with m_4_locked because it's ambiguously used From 413b2e17dd3e4e8b7e53ec50af475eee539d44ee Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 15:32:59 +0300 Subject: [PATCH 082/689] Disable mutex ghosts with indices --- src/analyses/mutexGhosts.ml | 3 +- tests/regression/13-privatized/80-idx_priv.t | 50 ++----------------- .../56-witness/68-ghost-ambiguous-idx.t | 41 +-------------- 3 files changed, 6 insertions(+), 88 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 128355e919..b7001c6c2f 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -77,7 +77,8 @@ struct ctx.local let ghost_var_available ctx = function - | WitnessGhost.Var.Locked lock -> LockDomain.Addr.is_definite lock && not (G.lock (ctx.global (V.lock lock))) + | WitnessGhost.Var.Locked (Addr (v, o) as lock) -> not (LockDomain.Offs.contains_index o) && not (G.lock (ctx.global (V.lock lock))) + | Locked _ -> false | Multithreaded -> true let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/tests/regression/13-privatized/80-idx_priv.t b/tests/regression/13-privatized/80-idx_priv.t index 698744924c..bf15cfb538 100644 --- a/tests/regression/13-privatized/80-idx_priv.t +++ b/tests/regression/13-privatized/80-idx_priv.t @@ -5,7 +5,7 @@ dead: 0 total lines: 14 [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -22,59 +22,15 @@ line: 20 column: 3 function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "1" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 21 - column: 3 - function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "1" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: m_4_locked - scope: global - type: int - initial: "0" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m_4_locked || data == 0)' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' type: assertion format: C + +TODO: protected invariant with m_4_locked without making 56-witness/68-ghost-ambiguous-idx unsound diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 0f6191188e..48837fcabb 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -10,7 +10,7 @@ write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) [Info][Witness] witness generation summary: - total generation entries: 8 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -27,52 +27,13 @@ line: 20 column: 3 function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "1" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: m_4_locked - scope: global - type: int - initial: "0" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m_4_locked || data == 0)' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' type: assertion format: C - -TODO: there shouldn't be invariant with m_4_locked because it's ambiguously used From 355550bbec358ed2b7a0c007d728f2c82768086d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:23:32 +0300 Subject: [PATCH 083/689] Switch to Mval-based must locksets --- src/analyses/mutexAnalysis.ml | 64 +++++++++++--------- src/cdomains/lockDomain.ml | 50 +++++++++++++++ tests/regression/06-symbeq/21-mult_accs_rc.t | 2 - 3 files changed, 86 insertions(+), 30 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 138f65ab47..0a02fd60f9 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -3,6 +3,7 @@ module M = Messages module Addr = ValueDomain.Addr module Lockset = LockDomain.Lockset +module MLockset = LockDomain.MLockset module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open GoblintCil @@ -47,8 +48,8 @@ struct (add v (current - 1) x, current - 1 = 0) end - module D = struct include Lattice.Prod(Lockset)(Multiplicity) - let empty () = (Lockset.empty (), Multiplicity.empty ()) + module D = struct include Lattice.Prod(MLockset)(Multiplicity) + let empty () = (MLockset.empty (), Multiplicity.empty ()) end @@ -146,36 +147,43 @@ struct let create_protected protected = `Lifted2 protected end - let add ctx (l:Mutexes.elt*bool) = + let add ctx (l:Mutexes.elt*bool): D.t = let s,m = ctx.local in - let s' = Lockset.add l s in match Addr.to_mval (fst l) with | Some mval when MutexTypeAnalysis.must_be_recursive ctx mval -> + let s' = MLockset.add (mval, snd l) s in (s', Multiplicity.increment (fst l) m) - | _ -> (s', m) + | Some mval -> + let s' = MLockset.add (mval, snd l) s in + (s', m) + | _ -> (s, m) - let remove' ctx ~warn l = - let s, m = ctx.local in - let rm s = Lockset.remove (l, true) (Lockset.remove (l, false) s) in - if warn && (not (Lockset.mem (l,true) s || Lockset.mem (l,false) s)) then M.warn "unlocking mutex (%a) which may not be held" Addr.pretty l; + let remove' ctx ~warn l: D.t = match Addr.to_mval l with - | Some mval when MutexTypeAnalysis.must_be_recursive ctx mval -> - let m',rmed = Multiplicity.decrement l m in - if rmed then - (rm s, m') + | None -> ctx.local + | Some l -> + let s, m = ctx.local in + let rm s = MLockset.remove (l, true) (MLockset.remove (l, false) s) in + if warn && (not (MLockset.mem (l,true) s || MLockset.mem (l,false) s)) then M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty l; + if MutexTypeAnalysis.must_be_recursive ctx l then ( + let m',rmed = Multiplicity.decrement (Addr l) m in + if rmed then + (rm s, m') + else + (s, m') + ) else - (s, m') - | _ -> (rm s, m) + (rm s, m) let remove = remove' ~warn:true - let remove_all ctx = + let remove_all ctx: D.t = (* Mutexes.iter (fun m -> ctx.emit (MustUnlock m) ) (D.export_locks ctx.local); *) (* TODO: used to have remove_nonspecial, which kept v.vname.[0] = '{' variables *) M.warn "unlocking unknown mutex which may not be held"; - (Lockset.empty (), Multiplicity.empty ()) + (MLockset.empty (), Multiplicity.empty ()) let empty () = (Lockset.empty (), Multiplicity.empty ()) end @@ -201,24 +209,24 @@ struct num_mutexes := 0; sum_protected := 0 - let query ctx (type a) (q: a Queries.t): a Queries.result = + let query (ctx: (D.t, _, _, _) ctx) (type a) (q: a Queries.t): a Queries.result = let ls, m = ctx.local in (* get the set of mutexes protecting the variable v in the given mode *) let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in let non_overlapping locks1 locks2 = Mutexes.is_empty @@ Mutexes.inter locks1 locks2 in match q with - | Queries.MayBePublic _ when Lockset.is_bot ls -> false + | Queries.MayBePublic _ when MLockset.is_bot ls -> false | Queries.MayBePublic {global=v; write; protection} -> - let held_locks = Lockset.export_locks (Lockset.filter snd ls) in + let held_locks = MLockset.export_locks (MLockset.filter snd ls) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks ctx.local) then false else *) non_overlapping held_locks protecting - | Queries.MayBePublicWithout _ when Lockset.is_bot ls -> false + | Queries.MayBePublicWithout _ when MLockset.is_bot ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> - let held_locks = Lockset.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in + let held_locks = MLockset.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) ctx.local)) then @@ -234,10 +242,10 @@ struct else *) Mutexes.leq mutex_lockset protecting | Queries.MustLockset -> - let held_locks = Lockset.export_locks (Lockset.filter snd ls) in + let held_locks = MLockset.export_locks (MLockset.filter snd ls) in Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) | Queries.MustBeAtomic -> - let held_locks = Lockset.export_locks (Lockset.filter snd ls) in + let held_locks = MLockset.export_locks (MLockset.filter snd ls) in Mutexes.mem (LockDomain.Addr.of_var LF.verifier_atomic_var) held_locks | Queries.MustProtectedVars {mutex = m; write} -> let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected m))) in @@ -269,7 +277,7 @@ struct module A = struct - include Lockset + include MLockset let name () = "lock" let may_race ls1 ls2 = (* not mutually exclusive *) @@ -287,7 +295,7 @@ struct let access ctx (a: Queries.access) = fst ctx.local - let event ctx e octx = + let event (ctx: (D.t, _, _, _) ctx) e (octx: (D.t, _, _, _) ctx) = match e with | Events.Access {exp; ad; kind; _} when ThreadFlag.has_ever_been_multi (Analyses.ask_of_ctx ctx) -> (* threadflag query in post-threadspawn ctx *) let is_recovered_to_st = not (ThreadFlag.is_currently_multi (Analyses.ask_of_ctx ctx)) in @@ -297,8 +305,8 @@ struct (*privatization*) match var_opt with | Some v -> - if not (Lockset.is_bot (fst octx.local)) then - let locks = Lockset.export_locks (Lockset.filter snd (fst octx.local)) in + if not (MLockset.is_bot (fst octx.local)) then + let locks = MLockset.export_locks (MLockset.filter snd (fst octx.local)) in let write = match kind with | Write | Free -> true | Read -> false diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index baee8a2ce6..056b62dc31 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -1,6 +1,7 @@ (** Lockset domains. *) module Addr = ValueDomain.Addr +module Mval = ValueDomain.Mval module Offs = ValueDomain.Offs module Exp = CilType.Exp module IdxDom = ValueDomain.IndexDomain @@ -60,6 +61,55 @@ struct fold f ls (Mutexes.empty ()) end +module MLockset = +struct + + (* true means exclusive lock and false represents reader lock*) + module RW = IntDomain.Booleans + + (* pair Addr and RW; also change pretty printing*) + module Lock = + struct + include Printable.Prod (Mval) (RW) + + let pretty () (a, write) = + if write then + Mval.pretty () a + else + Pretty.dprintf "read lock %a" Mval.pretty a + + include Printable.SimplePretty ( + struct + type nonrec t = t + let pretty = pretty + end + ) + end + + include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) + let name () = "lockset" + + let add ((addr, _) as lock) set = + match addr with + | mv when Addr.Mval.is_definite mv -> (* avoids NULL *) + add lock set + | _ -> + set + + let remove ((addr, _) as lock) set = + match addr with + | mv when Addr.Mval.is_definite mv -> (* avoids NULL *) + remove lock set + | _ -> + filter (fun (addr', _) -> + Mval.semantic_equal addr addr' = Some false + ) set + + let export_locks ls = + let f (x,_) set = Mutexes.add (Addr.Addr x) set in + fold f ls (Mutexes.empty ()) +end + module MayLockset = struct include Lockset diff --git a/tests/regression/06-symbeq/21-mult_accs_rc.t b/tests/regression/06-symbeq/21-mult_accs_rc.t index 90f0661f67..711205e38c 100644 --- a/tests/regression/06-symbeq/21-mult_accs_rc.t +++ b/tests/regression/06-symbeq/21-mult_accs_rc.t @@ -10,7 +10,6 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Race] Memory location (struct s).data (race with conf. 100): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) - [Warning][Unknown] unlocking mutex (NULL) which may not be held (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:13:3-13:14) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:15:3-15:14) @@ -26,7 +25,6 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) [Success][Race] Memory location (struct s).data (safe): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) - [Warning][Unknown] unlocking mutex (NULL) which may not be held (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:13:3-13:14) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:15:3-15:14) From be41e8e3b5db72700eb021467b985ea239ff6f9a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:25:01 +0300 Subject: [PATCH 084/689] Remove unused LockDomain.MayLocks --- src/cdomains/lockDomain.ml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 056b62dc31..4954ae9598 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -110,16 +110,6 @@ struct fold f ls (Mutexes.empty ()) end -module MayLockset = -struct - include Lockset - let leq x y = leq y x - let join = Lockset.meet - let meet = Lockset.join - let top = Lockset.bot - let bot = Lockset.top -end - module MayLocksetNoRW = struct include PreValueDomain.AD From 23b3df8b545ce689b0da359f0060cc75da03fcf4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:29:22 +0300 Subject: [PATCH 085/689] Remove unused set parts of LockDomain.Lockset --- src/analyses/mutexAnalysis.ml | 6 ++---- src/cdomains/lockDomain.ml | 23 ----------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 0a02fd60f9..23ac4c8715 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -184,8 +184,6 @@ struct (* TODO: used to have remove_nonspecial, which kept v.vname.[0] = '{' variables *) M.warn "unlocking unknown mutex which may not be held"; (MLockset.empty (), Multiplicity.empty ()) - - let empty () = (Lockset.empty (), Multiplicity.empty ()) end include LocksetAnalysis.MakeMust (Arg) let name () = "mutex" @@ -233,8 +231,8 @@ struct false else *) non_overlapping held_locks protecting - | Queries.MustBeProtectedBy {mutex; global=v; write; protection} -> - let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (mutex, true) in + | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> + let mutex_lockset = MLockset.export_locks @@ MLockset.singleton (mutex, true) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 4954ae9598..0240665b91 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -36,29 +36,6 @@ struct end ) end - - include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) - let name () = "lockset" - - let add ((addr, _) as lock) set = - match addr with - | Addr.Addr mv when Addr.Mval.is_definite mv -> (* avoids NULL *) - add lock set - | _ -> - set - - let remove ((addr, _) as lock) set = - match addr with - | Addr.Addr mv when Addr.Mval.is_definite mv -> (* avoids NULL *) - remove lock set - | _ -> - filter (fun (addr', _) -> - Addr.semantic_equal addr addr' = Some false - ) set - - let export_locks ls = - let f (x,_) set = Mutexes.add x set in - fold f ls (Mutexes.empty ()) end module MLockset = From 30661a5c870af6a1e28285e4437e51e74d299784 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:31:18 +0300 Subject: [PATCH 086/689] Remove LockDomain.Lockset --- src/analyses/deadlock.ml | 2 +- src/analyses/locksetAnalysis.ml | 2 +- src/analyses/mutexAnalysis.ml | 1 - src/analyses/mutexEventsAnalysis.ml | 1 - src/cdomains/lockDomain.ml | 42 +++++++++++++---------------- src/domains/events.ml | 4 +-- 6 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/analyses/deadlock.ml b/src/analyses/deadlock.ml index c23d6f4294..23b9faa882 100644 --- a/src/analyses/deadlock.ml +++ b/src/analyses/deadlock.ml @@ -30,7 +30,7 @@ struct let part_access ctx: MCPAccess.A.t = Obj.obj (ctx.ask (PartAccess Point)) - let add ctx ((l, _): LockDomain.Lockset.Lock.t) = + let add ctx ((l, _): LockDomain.Lock.t) = let after: LockEvent.t = (l, ctx.prev_node, part_access ctx) in (* use octx for access to use locksets before event *) D.iter (fun before -> side_lock_event_pair ctx before after diff --git a/src/analyses/locksetAnalysis.ml b/src/analyses/locksetAnalysis.ml index 6a816b9e6c..c7c7395dc1 100644 --- a/src/analyses/locksetAnalysis.ml +++ b/src/analyses/locksetAnalysis.ml @@ -29,7 +29,7 @@ sig module G: Lattice.S module V: SpecSysVar - val add: (D.t, G.t, D.t, V.t) ctx -> LockDomain.Lockset.Lock.t -> D.t + val add: (D.t, G.t, D.t, V.t) ctx -> LockDomain.Lock.t -> D.t val remove: (D.t, G.t, D.t, V.t) ctx -> ValueDomain.Addr.t -> D.t end diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 23ac4c8715..005316aff8 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -2,7 +2,6 @@ module M = Messages module Addr = ValueDomain.Addr -module Lockset = LockDomain.Lockset module MLockset = LockDomain.MLockset module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions diff --git a/src/analyses/mutexEventsAnalysis.ml b/src/analyses/mutexEventsAnalysis.ml index 7f544b0ffd..2252dae8a7 100644 --- a/src/analyses/mutexEventsAnalysis.ml +++ b/src/analyses/mutexEventsAnalysis.ml @@ -4,7 +4,6 @@ module M = Messages module Addr = ValueDomain.Addr -module Lockset = LockDomain.Lockset module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open Batteries diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 0240665b91..b1200959cb 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -12,30 +12,26 @@ module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" module Simple = Lattice.Reverse (Mutexes) module Priorities = IntDomain.Lifted -module Lockset = -struct - - (* true means exclusive lock and false represents reader lock*) - module RW = IntDomain.Booleans - - (* pair Addr and RW; also change pretty printing*) - module Lock = - struct - include Printable.Prod (Addr) (RW) - - let pretty () (a, write) = - if write then - Addr.pretty () a - else - Pretty.dprintf "read lock %a" Addr.pretty a +(* true means exclusive lock and false represents reader lock*) +module RW = IntDomain.Booleans - include Printable.SimplePretty ( - struct - type nonrec t = t - let pretty = pretty - end - ) - end +(* pair Addr and RW; also change pretty printing*) +module Lock = +struct + include Printable.Prod (Addr) (RW) + + let pretty () (a, write) = + if write then + Addr.pretty () a + else + Pretty.dprintf "read lock %a" Addr.pretty a + + include Printable.SimplePretty ( + struct + type nonrec t = t + let pretty = pretty + end + ) end module MLockset = diff --git a/src/domains/events.ml b/src/domains/events.ml index 06561bddbe..90eb7611be 100644 --- a/src/domains/events.ml +++ b/src/domains/events.ml @@ -4,7 +4,7 @@ open GoblintCil open Pretty type t = - | Lock of LockDomain.Lockset.Lock.t + | Lock of LockDomain.Lock.t | Unlock of LockDomain.Addr.t | Escape of EscapeDomain.EscapedVars.t | EnterMultiThreaded @@ -35,7 +35,7 @@ let emit_on_deadcode = function false let pretty () = function - | Lock m -> dprintf "Lock %a" LockDomain.Lockset.Lock.pretty m + | Lock m -> dprintf "Lock %a" LockDomain.Lock.pretty m | Unlock m -> dprintf "Unlock %a" LockDomain.Addr.pretty m | Escape escaped -> dprintf "Escape %a" EscapeDomain.EscapedVars.pretty escaped | EnterMultiThreaded -> text "EnterMultiThreaded" From 4de9d0d3d9675a0d381371c57619c55c83d0aff1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:32:35 +0300 Subject: [PATCH 087/689] Rename LockDomain.MLockset -> Lockset --- src/analyses/mutexAnalysis.ml | 36 +++++++++++++++++------------------ src/cdomains/lockDomain.ml | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 005316aff8..2375ff9535 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -2,7 +2,7 @@ module M = Messages module Addr = ValueDomain.Addr -module MLockset = LockDomain.MLockset +module Lockset = LockDomain.Lockset module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open GoblintCil @@ -47,8 +47,8 @@ struct (add v (current - 1) x, current - 1 = 0) end - module D = struct include Lattice.Prod(MLockset)(Multiplicity) - let empty () = (MLockset.empty (), Multiplicity.empty ()) + module D = struct include Lattice.Prod(Lockset)(Multiplicity) + let empty () = (Lockset.empty (), Multiplicity.empty ()) end @@ -150,10 +150,10 @@ struct let s,m = ctx.local in match Addr.to_mval (fst l) with | Some mval when MutexTypeAnalysis.must_be_recursive ctx mval -> - let s' = MLockset.add (mval, snd l) s in + let s' = Lockset.add (mval, snd l) s in (s', Multiplicity.increment (fst l) m) | Some mval -> - let s' = MLockset.add (mval, snd l) s in + let s' = Lockset.add (mval, snd l) s in (s', m) | _ -> (s, m) @@ -162,8 +162,8 @@ struct | None -> ctx.local | Some l -> let s, m = ctx.local in - let rm s = MLockset.remove (l, true) (MLockset.remove (l, false) s) in - if warn && (not (MLockset.mem (l,true) s || MLockset.mem (l,false) s)) then M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty l; + let rm s = Lockset.remove (l, true) (Lockset.remove (l, false) s) in + if warn && (not (Lockset.mem (l,true) s || Lockset.mem (l,false) s)) then M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty l; if MutexTypeAnalysis.must_be_recursive ctx l then ( let m',rmed = Multiplicity.decrement (Addr l) m in if rmed then @@ -182,7 +182,7 @@ struct ) (D.export_locks ctx.local); *) (* TODO: used to have remove_nonspecial, which kept v.vname.[0] = '{' variables *) M.warn "unlocking unknown mutex which may not be held"; - (MLockset.empty (), Multiplicity.empty ()) + (Lockset.empty (), Multiplicity.empty ()) end include LocksetAnalysis.MakeMust (Arg) let name () = "mutex" @@ -212,18 +212,18 @@ struct let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in let non_overlapping locks1 locks2 = Mutexes.is_empty @@ Mutexes.inter locks1 locks2 in match q with - | Queries.MayBePublic _ when MLockset.is_bot ls -> false + | Queries.MayBePublic _ when Lockset.is_bot ls -> false | Queries.MayBePublic {global=v; write; protection} -> - let held_locks = MLockset.export_locks (MLockset.filter snd ls) in + let held_locks = Lockset.export_locks (Lockset.filter snd ls) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks ctx.local) then false else *) non_overlapping held_locks protecting - | Queries.MayBePublicWithout _ when MLockset.is_bot ls -> false + | Queries.MayBePublicWithout _ when Lockset.is_bot ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> - let held_locks = MLockset.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in + let held_locks = Lockset.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) ctx.local)) then @@ -231,7 +231,7 @@ struct else *) non_overlapping held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> - let mutex_lockset = MLockset.export_locks @@ MLockset.singleton (mutex, true) in + let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (mutex, true) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then @@ -239,10 +239,10 @@ struct else *) Mutexes.leq mutex_lockset protecting | Queries.MustLockset -> - let held_locks = MLockset.export_locks (MLockset.filter snd ls) in + let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) | Queries.MustBeAtomic -> - let held_locks = MLockset.export_locks (MLockset.filter snd ls) in + let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Mutexes.mem (LockDomain.Addr.of_var LF.verifier_atomic_var) held_locks | Queries.MustProtectedVars {mutex = m; write} -> let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected m))) in @@ -274,7 +274,7 @@ struct module A = struct - include MLockset + include Lockset let name () = "lock" let may_race ls1 ls2 = (* not mutually exclusive *) @@ -302,8 +302,8 @@ struct (*privatization*) match var_opt with | Some v -> - if not (MLockset.is_bot (fst octx.local)) then - let locks = MLockset.export_locks (MLockset.filter snd (fst octx.local)) in + if not (Lockset.is_bot (fst octx.local)) then + let locks = Lockset.export_locks (Lockset.filter snd (fst octx.local)) in let write = match kind with | Write | Free -> true | Read -> false diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index b1200959cb..d26a66c7b6 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -34,7 +34,7 @@ struct ) end -module MLockset = +module Lockset = struct (* true means exclusive lock and false represents reader lock*) From 87143edbb59bd16a24559d15929eee1cc57abb8a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:35:18 +0300 Subject: [PATCH 088/689] Extract LockDomain.MakeLockRW --- src/cdomains/lockDomain.ml | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index d26a66c7b6..89e317f6b2 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -16,15 +16,15 @@ module Priorities = IntDomain.Lifted module RW = IntDomain.Booleans (* pair Addr and RW; also change pretty printing*) -module Lock = +module MakeLockRW (P: Printable.S) = struct - include Printable.Prod (Addr) (RW) + include Printable.Prod (P) (RW) let pretty () (a, write) = if write then - Addr.pretty () a + P.pretty () a else - Pretty.dprintf "read lock %a" Addr.pretty a + Pretty.dprintf "read lock %a" P.pretty a include Printable.SimplePretty ( struct @@ -34,30 +34,11 @@ struct ) end +module Lock = MakeLockRW (Addr) + module Lockset = struct - - (* true means exclusive lock and false represents reader lock*) - module RW = IntDomain.Booleans - - (* pair Addr and RW; also change pretty printing*) - module Lock = - struct - include Printable.Prod (Mval) (RW) - - let pretty () (a, write) = - if write then - Mval.pretty () a - else - Pretty.dprintf "read lock %a" Mval.pretty a - - include Printable.SimplePretty ( - struct - type nonrec t = t - let pretty = pretty - end - ) - end + module Lock = MakeLockRW (Mval) include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) let name () = "lockset" From 86c235037e7331cb367df49bb243a70b0c4545e2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:53:21 +0300 Subject: [PATCH 089/689] Clean up mutex analysis add and remove --- src/analyses/mutexAnalysis.ml | 45 +++++++++++++++++++---------------- src/cdomains/lockDomain.ml | 18 +++++++------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 2375ff9535..4ea8048e9b 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -2,6 +2,7 @@ module M = Messages module Addr = ValueDomain.Addr +module Lock = LockDomain.Lock module Lockset = LockDomain.Lockset module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions @@ -146,26 +147,30 @@ struct let create_protected protected = `Lifted2 protected end - let add ctx (l:Mutexes.elt*bool): D.t = - let s,m = ctx.local in - match Addr.to_mval (fst l) with - | Some mval when MutexTypeAnalysis.must_be_recursive ctx mval -> - let s' = Lockset.add (mval, snd l) s in - (s', Multiplicity.increment (fst l) m) - | Some mval -> - let s' = Lockset.add (mval, snd l) s in - (s', m) - | _ -> (s, m) - - let remove' ctx ~warn l: D.t = - match Addr.to_mval l with + let add ctx ((addr, rw): Lock.t): D.t = + match Addr.to_mval addr with + | Some mv -> + let (s, m) = ctx.local in + let s' = Lockset.add (mv, rw) s in + let m' = + if MutexTypeAnalysis.must_be_recursive ctx mv then + Multiplicity.increment addr m + else + m + in + (s', m') + | None -> ctx.local + + let remove' ctx ~warn (addr: Addr.t): D.t = + match Addr.to_mval addr with | None -> ctx.local - | Some l -> - let s, m = ctx.local in - let rm s = Lockset.remove (l, true) (Lockset.remove (l, false) s) in - if warn && (not (Lockset.mem (l,true) s || Lockset.mem (l,false) s)) then M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty l; - if MutexTypeAnalysis.must_be_recursive ctx l then ( - let m',rmed = Multiplicity.decrement (Addr l) m in + | Some mv -> + let (s, m) = ctx.local in + if warn && (not (Lockset.mem (mv, true) s || Lockset.mem (mv, false) s)) then + M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty mv; + let rm s = Lockset.remove (mv, true) (Lockset.remove (mv, false) s) in + if MutexTypeAnalysis.must_be_recursive ctx mv then ( + let (m', rmed) = Multiplicity.decrement (Addr mv) m in if rmed then (rm s, m') else @@ -182,7 +187,7 @@ struct ) (D.export_locks ctx.local); *) (* TODO: used to have remove_nonspecial, which kept v.vname.[0] = '{' variables *) M.warn "unlocking unknown mutex which may not be held"; - (Lockset.empty (), Multiplicity.empty ()) + D.empty () end include LocksetAnalysis.MakeMust (Arg) let name () = "mutex" diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 89e317f6b2..002c5fc2b4 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -43,20 +43,18 @@ struct include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) let name () = "lockset" - let add ((addr, _) as lock) set = - match addr with - | mv when Addr.Mval.is_definite mv -> (* avoids NULL *) + let add ((mv, _) as lock) set = + if Addr.Mval.is_definite mv then add lock set - | _ -> + else set - let remove ((addr, _) as lock) set = - match addr with - | mv when Addr.Mval.is_definite mv -> (* avoids NULL *) + let remove ((mv, _) as lock) set = + if Addr.Mval.is_definite mv then remove lock set - | _ -> - filter (fun (addr', _) -> - Mval.semantic_equal addr addr' = Some false + else + filter (fun (mv', _) -> + Mval.semantic_equal mv mv' = Some false ) set let export_locks ls = From 87f001425d163c32b1b5972852b10b0cf4e92cfd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 16:55:13 +0300 Subject: [PATCH 090/689] Use Mval for mutex analysis multiplicity --- src/analyses/mutexAnalysis.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 4ea8048e9b..01b02fdee5 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -29,7 +29,7 @@ struct ) ) - include MapDomain.MapTop_LiftBot (ValueDomain.Addr) (Count) + include MapDomain.MapTop_LiftBot (LockDomain.Mval) (Count) let name () = "multiplicity" @@ -154,7 +154,7 @@ struct let s' = Lockset.add (mv, rw) s in let m' = if MutexTypeAnalysis.must_be_recursive ctx mv then - Multiplicity.increment addr m + Multiplicity.increment mv m else m in @@ -170,7 +170,7 @@ struct M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty mv; let rm s = Lockset.remove (mv, true) (Lockset.remove (mv, false) s) in if MutexTypeAnalysis.must_be_recursive ctx mv then ( - let (m', rmed) = Multiplicity.decrement (Addr mv) m in + let (m', rmed) = Multiplicity.decrement mv m in if rmed then (rm s, m') else From 51635a65a4e5d18bba7c9a8ca5f124d1369afc64 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 17:12:26 +0300 Subject: [PATCH 091/689] Use Mval for mutex analysis protecting --- src/analyses/mutexAnalysis.ml | 33 +++++++++++++++++---------------- src/cdomains/lockDomain.ml | 6 +++--- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 01b02fdee5..6d69e6887c 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -4,6 +4,7 @@ module M = Messages module Addr = ValueDomain.Addr module Lock = LockDomain.Lock module Lockset = LockDomain.Lockset +module Simple = LockDomain.Simple module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open GoblintCil @@ -99,17 +100,17 @@ struct (** Collects information about which variables are protected by which mutexes *) module GProtecting: sig include Lattice.S - val make: write:bool -> recovered:bool -> Mutexes.t -> t - val get: write:bool -> Queries.Protection.t -> t -> Mutexes.t + val make: write:bool -> recovered:bool -> Simple.t -> t + val get: write:bool -> Queries.Protection.t -> t -> Simple.t end = struct - include MakeP (LockDomain.Simple) + include MakeP (Simple) let make ~write ~recovered locks = (* If the access is not a write, set to T so intersection with current write-protecting is identity *) - let wlocks = if write then locks else Mutexes.top () in + let wlocks = if write then locks else Simple.bot () in if recovered then (* If we are in single-threaded mode again, this does not need to be added to set of mutexes protecting in mt-mode only *) - ((locks, wlocks), (Mutexes.top (), Mutexes.top ())) + ((locks, wlocks), (Simple.bot (), Simple.bot ())) else ((locks, wlocks), (locks, wlocks)) end @@ -200,7 +201,7 @@ struct module GProtected = Arg.GProtected module G = Arg.G - module GM = Hashtbl.Make (ValueDomain.Addr) + module GM = Hashtbl.Make (LockDomain.Mval) let max_protected = ref 0 let num_mutexes = ref 0 @@ -215,7 +216,7 @@ struct let ls, m = ctx.local in (* get the set of mutexes protecting the variable v in the given mode *) let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in - let non_overlapping locks1 locks2 = Mutexes.is_empty @@ Mutexes.inter locks1 locks2 in + let non_overlapping locks1 locks2 = Simple.is_empty @@ Simple.inter locks1 locks2 in match q with | Queries.MayBePublic _ when Lockset.is_bot ls -> false | Queries.MayBePublic {global=v; write; protection} -> @@ -242,13 +243,13 @@ struct (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then true else *) - Mutexes.leq mutex_lockset protecting + Simple.subset mutex_lockset protecting | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in - Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) + Simple.fold (fun addr ls -> Queries.AD.add (Addr addr) ls) held_locks (Queries.AD.empty ()) | Queries.MustBeAtomic -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in - Mutexes.mem (LockDomain.Addr.of_var LF.verifier_atomic_var) held_locks + Simple.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) | Queries.MustProtectedVars {mutex = m; write} -> let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected m))) in VarSet.fold (fun v acc -> @@ -262,8 +263,8 @@ struct | `Left g' -> (* protecting *) if GobConfig.get_bool "dbg.print_protection" then ( let protecting = GProtecting.get ~write:false Strong (G.protecting (ctx.global g)) in (* readwrite protecting *) - let s = Mutexes.cardinal protecting in - M.info_noloc ~category:Race "Variable %a read-write protected by %d mutex(es): %a" CilType.Varinfo.pretty g' s Mutexes.pretty protecting + let s = Simple.cardinal protecting in + M.info_noloc ~category:Race "Variable %a read-write protected by %d mutex(es): %a" CilType.Varinfo.pretty g' s Simple.pretty protecting ) | `Right m -> (* protected *) if GobConfig.get_bool "dbg.print_protection" then ( @@ -297,7 +298,7 @@ struct let access ctx (a: Queries.access) = fst ctx.local - let event (ctx: (D.t, _, _, _) ctx) e (octx: (D.t, _, _, _) ctx) = + let event (ctx: (D.t, _, _, V.t) ctx) e (octx: (D.t, _, _, _) ctx) = match e with | Events.Access {exp; ad; kind; _} when ThreadFlag.has_ever_been_multi (Analyses.ask_of_ctx ctx) -> (* threadflag query in post-threadspawn ctx *) let is_recovered_to_st = not (ThreadFlag.is_currently_multi (Analyses.ask_of_ctx ctx)) in @@ -324,10 +325,10 @@ struct let held_weak = protecting Weak in let vs = VarSet.singleton v in let protected = G.create_protected @@ GProtected.make ~write vs in - Mutexes.iter (fun addr -> ctx.sideg (V.protected addr) protected) held_strong; + Simple.iter (fun addr -> ctx.sideg (V.protected (Addr.Addr addr)) protected) held_strong; (* TODO: remove Addr *) (* If the mutex set here is top, it is actually not accessed *) - if is_recovered_to_st && not @@ Mutexes.is_top held_weak then - Mutexes.iter (fun addr -> ctx.sideg (V.protected addr) protected) held_weak; + if is_recovered_to_st && not @@ Simple.is_bot held_weak then + Simple.iter (fun addr -> ctx.sideg (V.protected (Addr.Addr addr)) protected) held_weak; (* TODO: remove Addr *) ) | None -> M.info ~category:Unsound "Write to unknown address: privatization is unsound." in diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 002c5fc2b4..a7b7f9bec7 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -9,7 +9,7 @@ module IdxDom = ValueDomain.IndexDomain open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) -module Simple = Lattice.Reverse (Mutexes) +module Simple = SetDomain.Reverse (SetDomain.ToppedSet (Mval) (struct let topname = "All mutexes" end)) module Priorities = IntDomain.Lifted (* true means exclusive lock and false represents reader lock*) @@ -58,8 +58,8 @@ struct ) set let export_locks ls = - let f (x,_) set = Mutexes.add (Addr.Addr x) set in - fold f ls (Mutexes.empty ()) + let f (x,_) set = Simple.add x set in + fold f ls (Simple.empty ()) end module MayLocksetNoRW = From 03895dab004b2f1637c3ba3bdd9486f30a7a7d11 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 18:03:33 +0300 Subject: [PATCH 092/689] Use Mval for mutex analysis protected --- src/analyses/mutexAnalysis.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 6d69e6887c..204b064c1c 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -62,7 +62,7 @@ struct module V = struct - include Printable.Either (struct include CilType.Varinfo let name () = "protecting" end) (struct include ValueDomain.Addr let name () = "protected" end) + include Printable.Either (struct include CilType.Varinfo let name () = "protecting" end) (struct include LockDomain.Mval let name () = "protected" end) let name () = "mutex" let protecting x = `Left x let protected x = `Right x @@ -236,7 +236,7 @@ struct false else *) non_overlapping held_locks protecting - | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> + | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (mutex, true) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) @@ -250,7 +250,7 @@ struct | Queries.MustBeAtomic -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Simple.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) - | Queries.MustProtectedVars {mutex = m; write} -> + | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected m))) in VarSet.fold (fun v acc -> Queries.VS.add v acc @@ -273,7 +273,7 @@ struct max_protected := max !max_protected s; sum_protected := !sum_protected + s; incr num_mutexes; - M.info_noloc ~category:Race "Mutex %a read-write protects %d variable(s): %a" ValueDomain.Addr.pretty m s VarSet.pretty protected + M.info_noloc ~category:Race "Mutex %a read-write protects %d variable(s): %a" LockDomain.Mval.pretty m s VarSet.pretty protected ) end | _ -> Queries.Result.top q @@ -325,10 +325,10 @@ struct let held_weak = protecting Weak in let vs = VarSet.singleton v in let protected = G.create_protected @@ GProtected.make ~write vs in - Simple.iter (fun addr -> ctx.sideg (V.protected (Addr.Addr addr)) protected) held_strong; (* TODO: remove Addr *) + Simple.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_strong; (* If the mutex set here is top, it is actually not accessed *) if is_recovered_to_st && not @@ Simple.is_bot held_weak then - Simple.iter (fun addr -> ctx.sideg (V.protected (Addr.Addr addr)) protected) held_weak; (* TODO: remove Addr *) + Simple.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_weak; ) | None -> M.info ~category:Unsound "Write to unknown address: privatization is unsound." in From 7b4d3684fb7d0ca9f5cf3102ea0f4b4c1d1361fc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 18:53:37 +0300 Subject: [PATCH 093/689] Add Mval.Z with definite indices --- src/cdomain/value/cdomains/mval.ml | 1 + src/cdomain/value/cdomains/mval_intf.ml | 3 +++ src/cdomain/value/cdomains/offset.ml | 30 +++++++++++++++++++++++ src/cdomain/value/cdomains/offset_intf.ml | 7 ++++++ 4 files changed, 41 insertions(+) diff --git a/src/cdomain/value/cdomains/mval.ml b/src/cdomain/value/cdomains/mval.ml index 2bc5658460..6dd64b68da 100644 --- a/src/cdomain/value/cdomains/mval.ml +++ b/src/cdomain/value/cdomains/mval.ml @@ -72,3 +72,4 @@ end module Unit = MakePrintable (Offset.Unit) module Exp = MakePrintable (Offset.Exp) +module Z = MakePrintable (Offset.Z) diff --git a/src/cdomain/value/cdomains/mval_intf.ml b/src/cdomain/value/cdomains/mval_intf.ml index 7b956bf8b8..18aa81c16b 100644 --- a/src/cdomain/value/cdomains/mval_intf.ml +++ b/src/cdomain/value/cdomains/mval_intf.ml @@ -57,4 +57,7 @@ sig (** Mvalue with {!Offset.Exp} indices in offset. *) module Exp: Printable with type idx = GoblintCil.exp + + (** Mvalue with {!Offset.Z} indices in offset. *) + module Z: Printable with type idx = Z.t end diff --git a/src/cdomain/value/cdomains/offset.ml b/src/cdomain/value/cdomains/offset.ml index 7166e0642e..1329f461eb 100644 --- a/src/cdomain/value/cdomains/offset.ml +++ b/src/cdomain/value/cdomains/offset.ml @@ -43,6 +43,29 @@ struct let to_int _ = None (* TODO: more precise for definite indices *) let top () = Lazy.force any end + + module Z = + struct + include Printable.StdLeaf (* TODO: move to GobZ *) + include GobZ + let name () = "Z index" + + (* TODO: move to GobZ *) + include Printable.SimplePretty ( + struct + type nonrec t = t + let pretty = pretty + end + ) + + let top () = failwith "Offset.Index.Z.top" (* TODO: remove from interface? *) + let to_int z = Some z + let equal_to z1 z2 = + if Z.equal z2 z2 then + `Eq + else + `Neq + end end @@ -258,6 +281,13 @@ struct | `Field (f,o) -> Field (f, to_cil o) end +module Z = +struct + include MakePrintable (Index.Z) + + let is_definite _ = true (* override to avoid iterating over offset *) +end + let () = Printexc.register_printer (function | Type_of_error (t, o) -> Some (GobPretty.sprintf "Offset.Type_of_error(%a, %s)" d_plaintype t o) diff --git a/src/cdomain/value/cdomains/offset_intf.ml b/src/cdomain/value/cdomains/offset_intf.ml index 82117b7d9f..a0d9ce144c 100644 --- a/src/cdomain/value/cdomains/offset_intf.ml +++ b/src/cdomain/value/cdomains/offset_intf.ml @@ -136,6 +136,10 @@ sig Used for Goblint-specific witness invariants. *) val all: GoblintCil.exp Lazy.t end + + module Z: Printable with type t = Z.t + (** {!Z} index. + Represents a definite index. *) end exception Type_of_error of GoblintCil.typ * string @@ -172,4 +176,7 @@ sig val to_cil : t -> GoblintCil.offset (** Convert to CIL offset. *) end + + (** Offset with {!Index.Z} indices. *) + module Z: Printable with type idx = Z.t end From 34e705db7de7e75ed25618decb0d0227f2d2e3a0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 19:07:19 +0300 Subject: [PATCH 094/689] Extract mem_rw and remove_rw to LockDomain.Lockset --- src/analyses/mutexAnalysis.ml | 7 +++---- src/cdomains/lockDomain.ml | 6 ++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 204b064c1c..063c9e5333 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -167,18 +167,17 @@ struct | None -> ctx.local | Some mv -> let (s, m) = ctx.local in - if warn && (not (Lockset.mem (mv, true) s || Lockset.mem (mv, false) s)) then + if warn && not (Lockset.mem_rw mv s) then M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty mv; - let rm s = Lockset.remove (mv, true) (Lockset.remove (mv, false) s) in if MutexTypeAnalysis.must_be_recursive ctx mv then ( let (m', rmed) = Multiplicity.decrement mv m in if rmed then - (rm s, m') + (Lockset.remove_rw mv s, m') else (s, m') ) else - (rm s, m) + (Lockset.remove_rw mv s, m) let remove = remove' ~warn:true diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index a7b7f9bec7..1b156333ed 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -57,6 +57,12 @@ struct Mval.semantic_equal mv mv' = Some false ) set + let mem_rw mv set = + mem (mv, true) set || mem (mv, false) set + + let remove_rw mv set = + remove (mv, true) (remove (mv, false) set) + let export_locks ls = let f (x,_) set = Simple.add x set in fold f ls (Simple.empty ()) From ea849fbb840452090517c6395c78fbffd5226ea4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 10:28:28 +0300 Subject: [PATCH 095/689] Detect thread create nodes in mutexGhosts --- src/analyses/mutexGhosts.ml | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index b7001c6c2f..803f80f3e6 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -33,11 +33,16 @@ struct include BoolDomain.MayBool let name () = "multithread" end + module ThreadCreate = + struct + include BoolDomain.MayBool + let name () = "threadcreate" + end module G = struct - include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (BoolDomain.MayBool) + include Lattice.Lift2 (Lattice.Prod4 (Locked) (Unlocked) (MultiThread) (ThreadCreate)) (BoolDomain.MayBool) let node = function - | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) + | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ()) | `Lifted1 x -> x | _ -> failwith "MutexGhosts.node" let lock = function @@ -51,9 +56,9 @@ struct let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ())); if !AnalysisState.postsolving then ( - let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (locked, _, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal locked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -61,9 +66,9 @@ struct ); ) | Events.Unlock l -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot (), ThreadCreate.bot ())); if !AnalysisState.postsolving then ( - let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (_, unlocked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal unlocked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -71,11 +76,15 @@ struct ); ) | Events.EnterMultiThreaded -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true, ThreadCreate.bot ())) | _ -> () end; ctx.local + let threadspawn ctx ~multiple lval f args octx = + ctx.sideg (V.node ctx.node) (G.create_node (Locked.bot (), Unlocked.bot (), MultiThread.bot (), true)); + ctx.local + let ghost_var_available ctx = function | WitnessGhost.Var.Locked (Addr (v, o) as lock) -> not (LockDomain.Offs.contains_index o) && not (G.lock (ctx.global (V.lock lock))) | Locked _ -> false @@ -88,7 +97,7 @@ struct let g: V.t = Obj.obj g in begin match g with | `Left g' -> - let (locked, unlocked, multithread) = G.node (ctx.global g) in + let (locked, unlocked, multithread, threadcreate) = G.node (ctx.global g) in let g = g' in let entries = (* TODO: do variable_entry-s only once *) From 594beaceed70cb0e85ed0b56c9c26711becc1956 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 10:44:00 +0300 Subject: [PATCH 096/689] Refactor mutexGhosts thread creation collection --- src/analyses/mutexGhosts.ml | 44 +++++++++++++++++++++---------------- src/domains/queries.ml | 1 + 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 803f80f3e6..9ddde5d37e 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -2,20 +2,25 @@ open Analyses +module NodeSet = Queries.NS + module Spec = struct include UnitAnalysis.Spec let name () = "mutexGhosts" + module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) module V = struct - include Printable.Either (Node) (LockDomain.Addr) + include Printable.Either3 (Node) (LockDomain.Addr) (ThreadCreate) let node x = `Left x - let lock x = `Right x + let lock x = `Middle x + let threadcreate = `Right () let is_write_only = function | `Left _ -> false - | `Right _ -> true + | `Middle _ -> true + | `Right _ -> false end module Locked = @@ -33,32 +38,32 @@ struct include BoolDomain.MayBool let name () = "multithread" end - module ThreadCreate = - struct - include BoolDomain.MayBool - let name () = "threadcreate" - end module G = struct - include Lattice.Lift2 (Lattice.Prod4 (Locked) (Unlocked) (MultiThread) (ThreadCreate)) (BoolDomain.MayBool) + include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (Lattice.Lift2 (BoolDomain.MayBool) (NodeSet)) let node = function - | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ()) + | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) | `Lifted1 x -> x | _ -> failwith "MutexGhosts.node" let lock = function | `Bot -> BoolDomain.MayBool.bot () - | `Lifted2 x -> x + | `Lifted2 (`Lifted1 x) -> x | _ -> failwith "MutexGhosts.lock" + let threadcreate = function + | `Bot -> NodeSet.bot () + | `Lifted2 (`Lifted2 x) -> x + | _ -> failwith "MutexGhosts.threadcreate" let create_node node = `Lifted1 node - let create_lock lock = `Lifted2 lock + let create_lock lock = `Lifted2 (`Lifted1 lock) + let create_threadcreate threadcreate = `Lifted2 (`Lifted2 threadcreate) end let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); if !AnalysisState.postsolving then ( - let (locked, _, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal locked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -66,9 +71,9 @@ struct ); ) | Events.Unlock l -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot (), ThreadCreate.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); if !AnalysisState.postsolving then ( - let (_, unlocked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal unlocked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -76,13 +81,13 @@ struct ); ) | Events.EnterMultiThreaded -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true, ThreadCreate.bot ())) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) | _ -> () end; ctx.local let threadspawn ctx ~multiple lval f args octx = - ctx.sideg (V.node ctx.node) (G.create_node (Locked.bot (), Unlocked.bot (), MultiThread.bot (), true)); + ctx.sideg V.threadcreate (G.create_threadcreate (NodeSet.singleton ctx.node)); ctx.local let ghost_var_available ctx = function @@ -97,7 +102,7 @@ struct let g: V.t = Obj.obj g in begin match g with | `Left g' -> - let (locked, unlocked, multithread, threadcreate) = G.node (ctx.global g) in + let (locked, unlocked, multithread) = G.node (ctx.global g) in let g = g' in let entries = (* TODO: do variable_entry-s only once *) @@ -144,6 +149,7 @@ struct entries in entries + | `Middle _ -> Queries.Result.top q | `Right _ -> Queries.Result.top q end | _ -> Queries.Result.top q diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 44a0402a93..515198854d 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -10,6 +10,7 @@ module LS = VDQ.LS module TS = SetDomain.ToppedSet (CilType.Typ) (struct let topname = "All" end) module ES = SetDomain.Reverse (SetDomain.ToppedSet (CilType.Exp) (struct let topname = "All" end)) module VS = SetDomain.ToppedSet (CilType.Varinfo) (struct let topname = "All" end) +module NS = SetDomain.ToppedSet (Node) (struct let topname = "All" end) module NFL = WrapperFunctionAnalysis0.NodeFlatLattice module TC = WrapperFunctionAnalysis0.ThreadCreateUniqueCount From 584b78842a0a38fee98c73d59629a707218b0e0a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 11:06:39 +0300 Subject: [PATCH 097/689] Add option to emit flow_insensitive_invariant-s as location_invariant-s --- src/analyses/mutexGhosts.ml | 1 + src/config/options.schema.json | 6 +++ src/domains/queries.ml | 5 +++ src/witness/yamlWitness.ml | 21 ++++++++-- tests/regression/13-privatized/74-mutex.t | 50 ++++++++++++++++++++++- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 9ddde5d37e..75195e4662 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -152,6 +152,7 @@ struct | `Middle _ -> Queries.Result.top q | `Right _ -> Queries.Result.top q end + | InvariantGlobalNodes -> (G.threadcreate (ctx.global V.threadcreate): NodeSet.t) | _ -> Queries.Result.top q end diff --git a/src/config/options.schema.json b/src/config/options.schema.json index db93e74ff4..3065325f4e 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2493,6 +2493,12 @@ "description": "Emit invariants with typedef-ed types (e.g. in casts). Our validator cannot parse these.", "type": "boolean", "default": true + }, + "flow_insensitive-as-location": { + "title": "witness.invariant.flow_insensitive-as-location", + "description": "Emit flow-insensitive invariants as location invariants at certain locations.", + "type": "boolean", + "default": false } }, "additionalProperties": false diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 515198854d..152fb5f1a5 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -132,6 +132,7 @@ type _ t = | MaySignedOverflow: exp -> MayBool.t t | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t | GhostVarAvailable: WitnessGhostVar.t -> MayBool.t t + | InvariantGlobalNodes: NS.t t (* TODO: V.t argument? *) type 'a result = 'a @@ -205,6 +206,7 @@ struct | MaySignedOverflow _ -> (module MayBool) | YamlEntryGlobal _ -> (module YS) | GhostVarAvailable _ -> (module MayBool) + | InvariantGlobalNodes -> (module NS) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -277,6 +279,7 @@ struct | MaySignedOverflow _ -> MayBool.top () | YamlEntryGlobal _ -> YS.top () | GhostVarAvailable _ -> MayBool.top () + | InvariantGlobalNodes -> NS.top () end (* The type any_query can't be directly defined in Any as t, @@ -346,6 +349,7 @@ struct | Any (YamlEntryGlobal _) -> 59 | Any (MustProtectingLocks _) -> 60 | Any (GhostVarAvailable _) -> 61 + | Any InvariantGlobalNodes -> 62 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -514,6 +518,7 @@ struct | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e | Any (GhostVarAvailable v) -> Pretty.dprintf "GhostVarAvailable %a" WitnessGhostVar.pretty v + | Any InvariantGlobalNodes -> Pretty.dprintf "InvariantGlobalNodes" end let to_value_domain_ask (ask: ask) = diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 9eafae009f..49fe889c22 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -325,18 +325,33 @@ struct (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( + let ns = R.ask_global InvariantGlobalNodes in GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) - begin match R.ask_global (InvariantGlobal (Obj.repr g)) with - | `Lifted inv -> + begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_bool "witness.invariant.flow_insensitive-as-location" with + | `Lifted inv, false -> let invs = WitnessUtil.InvariantExp.process_exp inv in List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.flow_insensitive_invariant ~task ~invariant in entry :: acc ) acc invs - | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) + | `Lifted inv, true -> + (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + let invs = WitnessUtil.InvariantExp.process_exp inv in + Queries.NS.fold (fun n acc -> + let fundec = Node.find_fundec n in + let loc = Node.location n in + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + let invariant = Entry.invariant (CilType.Exp.show inv) in + let entry = Entry.location_invariant ~task ~location ~invariant in + entry :: acc + ) acc invs + ) ns acc + | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end | `Right _ -> (* contexts global *) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 6f84aa184f..a00f49eb1a 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -15,7 +15,7 @@ unsafe: 0 total memory locations: 1 - $ yamlWitnessStrip < witness.yml + $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml - entry_type: ghost_update variable: multithreaded expression: "1" @@ -82,6 +82,54 @@ type: assertion format: C +Flow-insensitive invariants as location invariants. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 15 + dead: 1 + total lines: 16 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml > witness.location.yml + + $ diff witness.flow_insensitive.yml witness.location.yml + 56,57c56,63 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 74-mutex.c + > file_hash: $FILE_HASH + > line: 36 + > column: 3 + > function: main + > location_invariant: + 61,62c67,74 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 74-mutex.c + > file_hash: $FILE_HASH + > line: 36 + > column: 3 + > function: main + > location_invariant: + [1] + Should also work with earlyglobs. Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. From 19854c3f810421f244854b0b83799d09424bd8b5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 11:24:18 +0300 Subject: [PATCH 098/689] Use Mval.Z for must locksets --- src/analyses/mutexAnalysis.ml | 14 +++++++------- src/cdomains/lockDomain.ml | 35 ++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 063c9e5333..1759f278e9 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -155,7 +155,7 @@ struct let s' = Lockset.add (mv, rw) s in let m' = if MutexTypeAnalysis.must_be_recursive ctx mv then - Multiplicity.increment mv m + Multiplicity.increment (LockDomain.Mval.of_mval mv) m (* TODO: no definite check? *) else m in @@ -168,9 +168,9 @@ struct | Some mv -> let (s, m) = ctx.local in if warn && not (Lockset.mem_rw mv s) then - M.warn "unlocking mutex (%a) which may not be held" LockDomain.Mval.pretty mv; + M.warn "unlocking mutex (%a) which may not be held" ValueDomain.Mval.pretty mv; if MutexTypeAnalysis.must_be_recursive ctx mv then ( - let (m', rmed) = Multiplicity.decrement mv m in + let (m', rmed) = Multiplicity.decrement (LockDomain.Mval.of_mval mv) m in (* TODO: no definite check? *) if rmed then (Lockset.remove_rw mv s, m') else @@ -211,7 +211,7 @@ struct num_mutexes := 0; sum_protected := 0 - let query (ctx: (D.t, _, _, _) ctx) (type a) (q: a Queries.t): a Queries.result = + let query (ctx: (D.t, _, _, V.t) ctx) (type a) (q: a Queries.t): a Queries.result = let ls, m = ctx.local in (* get the set of mutexes protecting the variable v in the given mode *) let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in @@ -236,7 +236,7 @@ struct else *) non_overlapping held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) - let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (mutex, true) in + let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (LockDomain.Mval.of_mval mutex, true) in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then @@ -245,12 +245,12 @@ struct Simple.subset mutex_lockset protecting | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in - Simple.fold (fun addr ls -> Queries.AD.add (Addr addr) ls) held_locks (Queries.AD.empty ()) + Simple.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.Mval.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) | Queries.MustBeAtomic -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Simple.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) - let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected m))) in + let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.Mval.of_mval m)))) in (* TODO: what if non-definite? *) VarSet.fold (fun v acc -> Queries.VS.add v acc ) protected (Queries.VS.empty ()) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 1b156333ed..0637f1ce59 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -1,7 +1,26 @@ (** Lockset domains. *) module Addr = ValueDomain.Addr -module Mval = ValueDomain.Mval +module Mval = +struct + include Mval.Z + + let of_mval ((v, o): ValueDomain.Mval.t): t = + let rec offs = function + | `NoOffset -> `NoOffset + | `Field (f, os') -> `Field (f, offs os') + | `Index (i, os') -> `Index (ValueDomain.IndexDomain.to_int i |> Option.get, offs os') + in + (v, offs o) + + let to_mval ((v, o): t): ValueDomain.Mval.t = + let rec offs = function + | `NoOffset -> `NoOffset + | `Field (f, os') -> `Field (f, offs os') + | `Index (i, os') -> `Index (ValueDomain.IndexDomain.of_int (Cilfacade.ptrdiff_ikind ()) i, offs os') + in + (v, offs o) +end module Offs = ValueDomain.Offs module Exp = CilType.Exp module IdxDom = ValueDomain.IndexDomain @@ -43,22 +62,24 @@ struct include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) let name () = "lockset" - let add ((mv, _) as lock) set = + let add (mv, rw) set = if Addr.Mval.is_definite mv then - add lock set + add (Mval.of_mval mv, rw) set else set - let remove ((mv, _) as lock) set = + let remove (mv, rw) set = if Addr.Mval.is_definite mv then - remove lock set + remove (Mval.of_mval mv, rw) set else filter (fun (mv', _) -> - Mval.semantic_equal mv mv' = Some false + (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) + ValueDomain.Mval.semantic_equal mv (Mval.to_mval mv') = Some false ) set let mem_rw mv set = - mem (mv, true) set || mem (mv, false) set + ValueDomain.Mval.is_definite mv && ( + mem (Mval.of_mval mv, true) set || mem (Mval.of_mval mv, false) set) let remove_rw mv set = remove (mv, true) (remove (mv, false) set) From ffd6a8550728e99cee7afe5c024fa84b4c28892d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 11:59:35 +0300 Subject: [PATCH 099/689] Add test for unsound recursive mutex handling due to non-definite index --- .../05-lval_ls/24-idxunknown_recursive.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/regression/05-lval_ls/24-idxunknown_recursive.c diff --git a/tests/regression/05-lval_ls/24-idxunknown_recursive.c b/tests/regression/05-lval_ls/24-idxunknown_recursive.c new file mode 100644 index 0000000000..95e8bff798 --- /dev/null +++ b/tests/regression/05-lval_ls/24-idxunknown_recursive.c @@ -0,0 +1,38 @@ +// PARAM: --enable ana.sv-comp.functions --set ana.activated[+] pthreadMutexType +_Bool __VERIFIER_nondet_bool(); + +#define _GNU_SOURCE +#include + +int g; + +#ifdef __APPLE__ +pthread_mutex_t m[2] = {PTHREAD_RECURSIVE_MUTEX_INITIALIZER, PTHREAD_RECURSIVE_MUTEX_INITIALIZER}; +#else +pthread_mutex_t m[2] = {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}; +#endif + +void *t_fun(void *arg) { + int i, j, k; + i = __VERIFIER_nondet_bool(); + j = __VERIFIER_nondet_bool(); + k = __VERIFIER_nondet_bool(); + + pthread_mutex_lock(&m[i]); // may lock m[1] + pthread_mutex_lock(&m[j]); // may lock m[1] recursively + pthread_mutex_lock(&m[0]); // must lock m[0] + pthread_mutex_unlock(&m[k]); // may unlock m[0] + // m[0] should not be in must-lockset here! + g++; // RACE! + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m[0]); + g++; // RACE! + pthread_mutex_unlock(&m[0]); + return 0; +} From 47bca4ba9744555dd8952b8cc4fc4e3bacaa0f99 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 12:07:16 +0300 Subject: [PATCH 100/689] Fix unsound recursive mutex handling due to non-definite index --- src/analyses/mutexAnalysis.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 1759f278e9..cf78d66e1f 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -154,8 +154,8 @@ struct let (s, m) = ctx.local in let s' = Lockset.add (mv, rw) s in let m' = - if MutexTypeAnalysis.must_be_recursive ctx mv then - Multiplicity.increment (LockDomain.Mval.of_mval mv) m (* TODO: no definite check? *) + if ValueDomain.Mval.is_definite mv && MutexTypeAnalysis.must_be_recursive ctx mv then + Multiplicity.increment (LockDomain.Mval.of_mval mv) m else m in @@ -169,8 +169,8 @@ struct let (s, m) = ctx.local in if warn && not (Lockset.mem_rw mv s) then M.warn "unlocking mutex (%a) which may not be held" ValueDomain.Mval.pretty mv; - if MutexTypeAnalysis.must_be_recursive ctx mv then ( - let (m', rmed) = Multiplicity.decrement (LockDomain.Mval.of_mval mv) m in (* TODO: no definite check? *) + if ValueDomain.Mval.is_definite mv && MutexTypeAnalysis.must_be_recursive ctx mv then ( + let (m', rmed) = Multiplicity.decrement (LockDomain.Mval.of_mval mv) m in (* TODO: non-definite should also decrement (to 0)? *) if rmed then (Lockset.remove_rw mv s, m') else From 65e1a58df3a8a5e187f23aa8f45d22dd66642da9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 12:23:28 +0300 Subject: [PATCH 101/689] Add second test for unsound recursive mutex handling due to non-definite index --- .../05-lval_ls/25-idxunknown_recursive_2.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/regression/05-lval_ls/25-idxunknown_recursive_2.c diff --git a/tests/regression/05-lval_ls/25-idxunknown_recursive_2.c b/tests/regression/05-lval_ls/25-idxunknown_recursive_2.c new file mode 100644 index 0000000000..47ea1ce0a7 --- /dev/null +++ b/tests/regression/05-lval_ls/25-idxunknown_recursive_2.c @@ -0,0 +1,36 @@ +// PARAM: --enable ana.sv-comp.functions --set ana.activated[+] pthreadMutexType +_Bool __VERIFIER_nondet_bool(); + +#define _GNU_SOURCE +#include + +int g; + +#ifdef __APPLE__ +pthread_mutex_t m[2] = {PTHREAD_RECURSIVE_MUTEX_INITIALIZER, PTHREAD_RECURSIVE_MUTEX_INITIALIZER}; +#else +pthread_mutex_t m[2] = {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}; +#endif + +void *t_fun(void *arg) { + int i; + i = __VERIFIER_nondet_bool(); + + pthread_mutex_lock(&m[0]); // must lock m[0] + pthread_mutex_unlock(&m[i]); // may unlock m[0] + pthread_mutex_lock(&m[0]); // must lock m[0] + pthread_mutex_unlock(&m[0]); // must unlock m[0] + // m[0] should not be in must-lockset here! + g++; // RACE! + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m[0]); + g++; // RACE! + pthread_mutex_unlock(&m[0]); + return 0; +} From 666ebbd978f7bcd9f240598f0f5bc9fd50dee0dd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 12:56:28 +0300 Subject: [PATCH 102/689] Fix second unsound recursive mutex handling due to non-definite index --- src/analyses/mutexAnalysis.ml | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index cf78d66e1f..a3d124900c 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -41,12 +41,33 @@ struct else add v (current + 1) x + let increment mv m = + if Addr.Mval.is_definite mv then + increment (LockDomain.Mval.of_mval mv) m + else + m + let decrement v x = let current = find v x in if current = 0 then (x, true) else - (add v (current - 1) x, current - 1 = 0) + (add v (current - 1) x, current - 1 = 0) (* TODO: remove if 0? *) + + let decrement mv m = + if Addr.Mval.is_definite mv then + decrement (LockDomain.Mval.of_mval mv) m + else + (* TODO: non-definite should also decrement (to 0)? *) + fold (fun mv' _ (m, rmed) -> + (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) + if ValueDomain.Mval.semantic_equal mv (LockDomain.Mval.to_mval mv') = Some false then + (m, rmed) + else ( + let (m', rmed') = decrement mv' m in + (m', rmed || rmed') + ) + ) m (m, false) end module D = struct include Lattice.Prod(Lockset)(Multiplicity) @@ -154,8 +175,8 @@ struct let (s, m) = ctx.local in let s' = Lockset.add (mv, rw) s in let m' = - if ValueDomain.Mval.is_definite mv && MutexTypeAnalysis.must_be_recursive ctx mv then - Multiplicity.increment (LockDomain.Mval.of_mval mv) m + if MutexTypeAnalysis.must_be_recursive ctx mv then + Multiplicity.increment mv m else m in @@ -169,15 +190,17 @@ struct let (s, m) = ctx.local in if warn && not (Lockset.mem_rw mv s) then M.warn "unlocking mutex (%a) which may not be held" ValueDomain.Mval.pretty mv; - if ValueDomain.Mval.is_definite mv && MutexTypeAnalysis.must_be_recursive ctx mv then ( - let (m', rmed) = Multiplicity.decrement (LockDomain.Mval.of_mval mv) m in (* TODO: non-definite should also decrement (to 0)? *) + if MutexTypeAnalysis.must_be_recursive ctx mv then ( + let (m', rmed) = Multiplicity.decrement mv m in if rmed then + (* TODO: don't repeat the same semantic_equal checks *) + (* TODO: rmed per lockset element, not aggregated *) (Lockset.remove_rw mv s, m') else (s, m') ) else - (Lockset.remove_rw mv s, m) + (Lockset.remove_rw mv s, m) (* TODO: should decrement something if may be recursive? *) let remove = remove' ~warn:true From 3fee53e7f9706a7ab6d329524ba9053b299ae7de Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 13:01:48 +0300 Subject: [PATCH 103/689] Fix LockDomain indentation --- src/cdomains/lockDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 0637f1ce59..96ee361318 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -79,7 +79,7 @@ struct let mem_rw mv set = ValueDomain.Mval.is_definite mv && ( - mem (Mval.of_mval mv, true) set || mem (Mval.of_mval mv, false) set) + mem (Mval.of_mval mv, true) set || mem (Mval.of_mval mv, false) set) let remove_rw mv set = remove (mv, true) (remove (mv, false) set) From ff3657f1bfb53a6cf997b3e8f3b34e765c205151 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 13:48:08 +0300 Subject: [PATCH 104/689] Move Multiplicity to LockDomain --- src/analyses/mutexAnalysis.ml | 54 +---------------------------------- src/cdomains/lockDomain.ml | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index a3d124900c..f746eafb0d 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -4,6 +4,7 @@ module M = Messages module Addr = ValueDomain.Addr module Lock = LockDomain.Lock module Lockset = LockDomain.Lockset +module Multiplicity = LockDomain.Multiplicity module Simple = LockDomain.Simple module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions @@ -17,59 +18,6 @@ module Spec = struct module Arg = struct - module Multiplicity = struct - (* the maximum multiplicity which we keep track of precisely *) - let max_count () = 4 - - module Count = Lattice.Reverse ( - Lattice.Chain ( - struct - let n () = max_count () + 1 - let names x = if x = max_count () then Format.asprintf ">= %d" x else Format.asprintf "%d" x - end - ) - ) - - include MapDomain.MapTop_LiftBot (LockDomain.Mval) (Count) - - let name () = "multiplicity" - - let increment v x = - let current = find v x in - if current = max_count () then - x - else - add v (current + 1) x - - let increment mv m = - if Addr.Mval.is_definite mv then - increment (LockDomain.Mval.of_mval mv) m - else - m - - let decrement v x = - let current = find v x in - if current = 0 then - (x, true) - else - (add v (current - 1) x, current - 1 = 0) (* TODO: remove if 0? *) - - let decrement mv m = - if Addr.Mval.is_definite mv then - decrement (LockDomain.Mval.of_mval mv) m - else - (* TODO: non-definite should also decrement (to 0)? *) - fold (fun mv' _ (m, rmed) -> - (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) - if ValueDomain.Mval.semantic_equal mv (LockDomain.Mval.to_mval mv') = Some false then - (m, rmed) - else ( - let (m', rmed') = decrement mv' m in - (m', rmed || rmed') - ) - ) m (m, false) - end - module D = struct include Lattice.Prod(Lockset)(Multiplicity) let empty () = (Lockset.empty (), Multiplicity.empty ()) end diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 96ee361318..ef8e7c46fe 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -89,6 +89,59 @@ struct fold f ls (Simple.empty ()) end +module Multiplicity = struct + (* the maximum multiplicity which we keep track of precisely *) + let max_count () = 4 + + module Count = Lattice.Reverse ( + Lattice.Chain ( + struct + let n () = max_count () + 1 + let names x = if x = max_count () then Format.asprintf ">= %d" x else Format.asprintf "%d" x + end + ) + ) + + include MapDomain.MapTop_LiftBot (Mval) (Count) + + let name () = "multiplicity" + + let increment v x = + let current = find v x in + if current = max_count () then + x + else + add v (current + 1) x + + let increment mv m = + if Addr.Mval.is_definite mv then + increment (Mval.of_mval mv) m + else + m + + let decrement v x = + let current = find v x in + if current = 0 then + (x, true) + else + (add v (current - 1) x, current - 1 = 0) (* TODO: remove if 0? *) + + let decrement mv m = + if Addr.Mval.is_definite mv then + decrement (Mval.of_mval mv) m + else + (* TODO: non-definite should also decrement (to 0)? *) + fold (fun mv' _ (m, rmed) -> + (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) + if ValueDomain.Mval.semantic_equal mv (Mval.to_mval mv') = Some false then + (m, rmed) + else ( + let (m', rmed') = decrement mv' m in + (m', rmed || rmed') + ) + ) m (m, false) +end + module MayLocksetNoRW = struct include PreValueDomain.AD From 8b625568340a27b050a81ef651b25dd4cec46b7b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 13:52:07 +0300 Subject: [PATCH 105/689] Rename LockDomain.Mval -> MustLock --- src/analyses/mutexAnalysis.ml | 12 ++++++------ src/cdomains/lockDomain.ml | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index f746eafb0d..9989308967 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -31,7 +31,7 @@ struct module V = struct - include Printable.Either (struct include CilType.Varinfo let name () = "protecting" end) (struct include LockDomain.Mval let name () = "protected" end) + include Printable.Either (struct include CilType.Varinfo let name () = "protecting" end) (struct include LockDomain.MustLock let name () = "protected" end) let name () = "mutex" let protecting x = `Left x let protected x = `Right x @@ -171,7 +171,7 @@ struct module GProtected = Arg.GProtected module G = Arg.G - module GM = Hashtbl.Make (LockDomain.Mval) + module GM = Hashtbl.Make (LockDomain.MustLock) let max_protected = ref 0 let num_mutexes = ref 0 @@ -207,7 +207,7 @@ struct else *) non_overlapping held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) - let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (LockDomain.Mval.of_mval mutex, true) in (* TODO: what if non-definite? *) + let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then @@ -216,12 +216,12 @@ struct Simple.subset mutex_lockset protecting | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in - Simple.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.Mval.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) + Simple.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) | Queries.MustBeAtomic -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Simple.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) - let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.Mval.of_mval m)))) in (* TODO: what if non-definite? *) + let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval m)))) in (* TODO: what if non-definite? *) VarSet.fold (fun v acc -> Queries.VS.add v acc ) protected (Queries.VS.empty ()) @@ -243,7 +243,7 @@ struct max_protected := max !max_protected s; sum_protected := !sum_protected + s; incr num_mutexes; - M.info_noloc ~category:Race "Mutex %a read-write protects %d variable(s): %a" LockDomain.Mval.pretty m s VarSet.pretty protected + M.info_noloc ~category:Race "Mutex %a read-write protects %d variable(s): %a" LockDomain.MustLock.pretty m s VarSet.pretty protected ) end | _ -> Queries.Result.top q diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index ef8e7c46fe..e68c39252c 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -1,7 +1,7 @@ (** Lockset domains. *) module Addr = ValueDomain.Addr -module Mval = +module MustLock = struct include Mval.Z @@ -28,7 +28,7 @@ module IdxDom = ValueDomain.IndexDomain open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) -module Simple = SetDomain.Reverse (SetDomain.ToppedSet (Mval) (struct let topname = "All mutexes" end)) +module Simple = SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) module Priorities = IntDomain.Lifted (* true means exclusive lock and false represents reader lock*) @@ -57,29 +57,29 @@ module Lock = MakeLockRW (Addr) module Lockset = struct - module Lock = MakeLockRW (Mval) + module Lock = MakeLockRW (MustLock) include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) let name () = "lockset" let add (mv, rw) set = if Addr.Mval.is_definite mv then - add (Mval.of_mval mv, rw) set + add (MustLock.of_mval mv, rw) set else set let remove (mv, rw) set = if Addr.Mval.is_definite mv then - remove (Mval.of_mval mv, rw) set + remove (MustLock.of_mval mv, rw) set else filter (fun (mv', _) -> (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) - ValueDomain.Mval.semantic_equal mv (Mval.to_mval mv') = Some false + ValueDomain.Mval.semantic_equal mv (MustLock.to_mval mv') = Some false ) set let mem_rw mv set = ValueDomain.Mval.is_definite mv && ( - mem (Mval.of_mval mv, true) set || mem (Mval.of_mval mv, false) set) + mem (MustLock.of_mval mv, true) set || mem (MustLock.of_mval mv, false) set) let remove_rw mv set = remove (mv, true) (remove (mv, false) set) @@ -102,7 +102,7 @@ module Multiplicity = struct ) ) - include MapDomain.MapTop_LiftBot (Mval) (Count) + include MapDomain.MapTop_LiftBot (MustLock) (Count) let name () = "multiplicity" @@ -115,7 +115,7 @@ module Multiplicity = struct let increment mv m = if Addr.Mval.is_definite mv then - increment (Mval.of_mval mv) m + increment (MustLock.of_mval mv) m else m @@ -128,12 +128,12 @@ module Multiplicity = struct let decrement mv m = if Addr.Mval.is_definite mv then - decrement (Mval.of_mval mv) m + decrement (MustLock.of_mval mv) m else (* TODO: non-definite should also decrement (to 0)? *) fold (fun mv' _ (m, rmed) -> (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) - if ValueDomain.Mval.semantic_equal mv (Mval.to_mval mv') = Some false then + if ValueDomain.Mval.semantic_equal mv (MustLock.to_mval mv') = Some false then (m, rmed) else ( let (m', rmed') = decrement mv' m in From 4445d466964de34c3beab479507cd2ad47bd0705 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 13:54:56 +0300 Subject: [PATCH 106/689] Rename LockDomain.Lockset -> MustLocksetRW --- src/analyses/mutexAnalysis.ml | 36 ++++++++++++++++++----------------- src/cdomains/lockDomain.ml | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 9989308967..ac1d480e3f 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -3,7 +3,7 @@ module M = Messages module Addr = ValueDomain.Addr module Lock = LockDomain.Lock -module Lockset = LockDomain.Lockset +module MustLocksetRW = LockDomain.MustLocksetRW module Multiplicity = LockDomain.Multiplicity module Simple = LockDomain.Simple module Mutexes = LockDomain.Mutexes @@ -18,8 +18,10 @@ module Spec = struct module Arg = struct - module D = struct include Lattice.Prod(Lockset)(Multiplicity) - let empty () = (Lockset.empty (), Multiplicity.empty ()) + module D = + struct + include Lattice.Prod (MustLocksetRW) (Multiplicity) + let empty () = (MustLocksetRW.empty (), Multiplicity.empty ()) end @@ -121,7 +123,7 @@ struct match Addr.to_mval addr with | Some mv -> let (s, m) = ctx.local in - let s' = Lockset.add (mv, rw) s in + let s' = MustLocksetRW.add (mv, rw) s in let m' = if MutexTypeAnalysis.must_be_recursive ctx mv then Multiplicity.increment mv m @@ -136,19 +138,19 @@ struct | None -> ctx.local | Some mv -> let (s, m) = ctx.local in - if warn && not (Lockset.mem_rw mv s) then + if warn && not (MustLocksetRW.mem_rw mv s) then M.warn "unlocking mutex (%a) which may not be held" ValueDomain.Mval.pretty mv; if MutexTypeAnalysis.must_be_recursive ctx mv then ( let (m', rmed) = Multiplicity.decrement mv m in if rmed then (* TODO: don't repeat the same semantic_equal checks *) (* TODO: rmed per lockset element, not aggregated *) - (Lockset.remove_rw mv s, m') + (MustLocksetRW.remove_rw mv s, m') else (s, m') ) else - (Lockset.remove_rw mv s, m) (* TODO: should decrement something if may be recursive? *) + (MustLocksetRW.remove_rw mv s, m) (* TODO: should decrement something if may be recursive? *) let remove = remove' ~warn:true @@ -188,18 +190,18 @@ struct let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in let non_overlapping locks1 locks2 = Simple.is_empty @@ Simple.inter locks1 locks2 in match q with - | Queries.MayBePublic _ when Lockset.is_bot ls -> false + | Queries.MayBePublic _ when MustLocksetRW.is_bot ls -> false | Queries.MayBePublic {global=v; write; protection} -> - let held_locks = Lockset.export_locks (Lockset.filter snd ls) in + let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks ctx.local) then false else *) non_overlapping held_locks protecting - | Queries.MayBePublicWithout _ when Lockset.is_bot ls -> false + | Queries.MayBePublicWithout _ when MustLocksetRW.is_bot ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> - let held_locks = Lockset.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in + let held_locks = MustLocksetRW.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) ctx.local)) then @@ -207,7 +209,7 @@ struct else *) non_overlapping held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) - let mutex_lockset = Lockset.export_locks @@ Lockset.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) + let mutex_lockset = MustLocksetRW.export_locks @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then @@ -215,10 +217,10 @@ struct else *) Simple.subset mutex_lockset protecting | Queries.MustLockset -> - let held_locks = Lockset.export_locks (Lockset.filter snd ls) in + let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in Simple.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) | Queries.MustBeAtomic -> - let held_locks = Lockset.export_locks (Lockset.filter snd ls) in + let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in Simple.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval m)))) in (* TODO: what if non-definite? *) @@ -250,7 +252,7 @@ struct module A = struct - include Lockset + include MustLocksetRW let name () = "lock" let may_race ls1 ls2 = (* not mutually exclusive *) @@ -278,8 +280,8 @@ struct (*privatization*) match var_opt with | Some v -> - if not (Lockset.is_bot (fst octx.local)) then - let locks = Lockset.export_locks (Lockset.filter snd (fst octx.local)) in + if not (MustLocksetRW.is_bot (fst octx.local)) then + let locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd (fst octx.local)) in let write = match kind with | Write | Free -> true | Read -> false diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index e68c39252c..779b59ba6c 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -55,7 +55,7 @@ end module Lock = MakeLockRW (Addr) -module Lockset = +module MustLocksetRW = struct module Lock = MakeLockRW (MustLock) From 18e725c36f5ce3c0f007e452594d312b3e6288f9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 13:56:52 +0300 Subject: [PATCH 107/689] Extract LockDomain.MustLockRW --- src/cdomains/lockDomain.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 779b59ba6c..2b214b5852 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -55,11 +55,11 @@ end module Lock = MakeLockRW (Addr) +module MustLockRW = MakeLockRW (MustLock) + module MustLocksetRW = struct - module Lock = MakeLockRW (MustLock) - - include SetDomain.Reverse(SetDomain.ToppedSet (Lock) (struct let topname = "All mutexes" end)) + include SetDomain.Reverse (SetDomain.ToppedSet (MustLockRW) (struct let topname = "All mutexes" end)) let name () = "lockset" let add (mv, rw) set = From cf514f778183beef7e407af27aee0e75131b0a79 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 13:58:32 +0300 Subject: [PATCH 108/689] Rename LockDomain.Multiplicity -> MustMultiplicity --- src/analyses/mutexAnalysis.ml | 10 +++++----- src/cdomains/lockDomain.ml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index ac1d480e3f..49c08024ac 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -4,7 +4,7 @@ module M = Messages module Addr = ValueDomain.Addr module Lock = LockDomain.Lock module MustLocksetRW = LockDomain.MustLocksetRW -module Multiplicity = LockDomain.Multiplicity +module MustMultiplicity = LockDomain.MustMultiplicity module Simple = LockDomain.Simple module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions @@ -20,8 +20,8 @@ struct struct module D = struct - include Lattice.Prod (MustLocksetRW) (Multiplicity) - let empty () = (MustLocksetRW.empty (), Multiplicity.empty ()) + include Lattice.Prod (MustLocksetRW) (MustMultiplicity) + let empty () = (MustLocksetRW.empty (), MustMultiplicity.empty ()) end @@ -126,7 +126,7 @@ struct let s' = MustLocksetRW.add (mv, rw) s in let m' = if MutexTypeAnalysis.must_be_recursive ctx mv then - Multiplicity.increment mv m + MustMultiplicity.increment mv m else m in @@ -141,7 +141,7 @@ struct if warn && not (MustLocksetRW.mem_rw mv s) then M.warn "unlocking mutex (%a) which may not be held" ValueDomain.Mval.pretty mv; if MutexTypeAnalysis.must_be_recursive ctx mv then ( - let (m', rmed) = Multiplicity.decrement mv m in + let (m', rmed) = MustMultiplicity.decrement mv m in if rmed then (* TODO: don't repeat the same semantic_equal checks *) (* TODO: rmed per lockset element, not aggregated *) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 2b214b5852..532db49661 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -89,7 +89,7 @@ struct fold f ls (Simple.empty ()) end -module Multiplicity = struct +module MustMultiplicity = struct (* the maximum multiplicity which we keep track of precisely *) let max_count () = 4 From 41df679f6b2816fbef2b6619652f4bf468e8b7fa Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:02:25 +0300 Subject: [PATCH 109/689] Rename LockDomain.Simple -> MustLockset --- src/analyses/mutexAnalysis.ml | 30 +++++++++++++++--------------- src/cdomains/lockDomain.ml | 6 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 49c08024ac..5ac8f91513 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -3,9 +3,9 @@ module M = Messages module Addr = ValueDomain.Addr module Lock = LockDomain.Lock +module MustLockset = LockDomain.MustLockset module MustLocksetRW = LockDomain.MustLocksetRW module MustMultiplicity = LockDomain.MustMultiplicity -module Simple = LockDomain.Simple module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open GoblintCil @@ -71,17 +71,17 @@ struct (** Collects information about which variables are protected by which mutexes *) module GProtecting: sig include Lattice.S - val make: write:bool -> recovered:bool -> Simple.t -> t - val get: write:bool -> Queries.Protection.t -> t -> Simple.t + val make: write:bool -> recovered:bool -> MustLockset.t -> t + val get: write:bool -> Queries.Protection.t -> t -> MustLockset.t end = struct - include MakeP (Simple) + include MakeP (MustLockset) let make ~write ~recovered locks = (* If the access is not a write, set to T so intersection with current write-protecting is identity *) - let wlocks = if write then locks else Simple.bot () in + let wlocks = if write then locks else MustLockset.bot () in if recovered then (* If we are in single-threaded mode again, this does not need to be added to set of mutexes protecting in mt-mode only *) - ((locks, wlocks), (Simple.bot (), Simple.bot ())) + ((locks, wlocks), (MustLockset.bot (), MustLockset.bot ())) else ((locks, wlocks), (locks, wlocks)) end @@ -188,7 +188,7 @@ struct let ls, m = ctx.local in (* get the set of mutexes protecting the variable v in the given mode *) let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in - let non_overlapping locks1 locks2 = Simple.is_empty @@ Simple.inter locks1 locks2 in + let non_overlapping locks1 locks2 = MustLockset.is_empty @@ MustLockset.inter locks1 locks2 in match q with | Queries.MayBePublic _ when MustLocksetRW.is_bot ls -> false | Queries.MayBePublic {global=v; write; protection} -> @@ -215,13 +215,13 @@ struct (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then true else *) - Simple.subset mutex_lockset protecting + MustLockset.subset mutex_lockset protecting | Queries.MustLockset -> let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in - Simple.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) + MustLockset.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) | Queries.MustBeAtomic -> let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in - Simple.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) + MustLockset.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval m)))) in (* TODO: what if non-definite? *) VarSet.fold (fun v acc -> @@ -235,8 +235,8 @@ struct | `Left g' -> (* protecting *) if GobConfig.get_bool "dbg.print_protection" then ( let protecting = GProtecting.get ~write:false Strong (G.protecting (ctx.global g)) in (* readwrite protecting *) - let s = Simple.cardinal protecting in - M.info_noloc ~category:Race "Variable %a read-write protected by %d mutex(es): %a" CilType.Varinfo.pretty g' s Simple.pretty protecting + let s = MustLockset.cardinal protecting in + M.info_noloc ~category:Race "Variable %a read-write protected by %d mutex(es): %a" CilType.Varinfo.pretty g' s MustLockset.pretty protecting ) | `Right m -> (* protected *) if GobConfig.get_bool "dbg.print_protection" then ( @@ -297,10 +297,10 @@ struct let held_weak = protecting Weak in let vs = VarSet.singleton v in let protected = G.create_protected @@ GProtected.make ~write vs in - Simple.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_strong; + MustLockset.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_strong; (* If the mutex set here is top, it is actually not accessed *) - if is_recovered_to_st && not @@ Simple.is_bot held_weak then - Simple.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_weak; + if is_recovered_to_st && not @@ MustLockset.is_bot held_weak then + MustLockset.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_weak; ) | None -> M.info ~category:Unsound "Write to unknown address: privatization is unsound." in diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 532db49661..0a37b45454 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -28,7 +28,7 @@ module IdxDom = ValueDomain.IndexDomain open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) -module Simple = SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) +module MustLockset = SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) module Priorities = IntDomain.Lifted (* true means exclusive lock and false represents reader lock*) @@ -85,8 +85,8 @@ struct remove (mv, true) (remove (mv, false) set) let export_locks ls = - let f (x,_) set = Simple.add x set in - fold f ls (Simple.empty ()) + let f (x,_) set = MustLockset.add x set in + fold f ls (MustLockset.empty ()) end module MustMultiplicity = struct From 8e9e45ef8b3e926ae6b8aa9d8a46d0821238ca4a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:04:55 +0300 Subject: [PATCH 110/689] Remove unused LockDomain.Priorities --- src/cdomains/lockDomain.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 0a37b45454..28f3f5b0c6 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -29,7 +29,6 @@ open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) module MustLockset = SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) -module Priorities = IntDomain.Lifted (* true means exclusive lock and false represents reader lock*) module RW = IntDomain.Booleans From 7526063472b5c74d893641e6d8d2a1b75592d779 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:15:09 +0300 Subject: [PATCH 111/689] Add all and is_all to must locksets --- src/analyses/mutexAnalysis.ml | 14 +++++++------- src/cdomains/lockDomain.ml | 11 ++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 5ac8f91513..5fabc1f597 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -78,10 +78,10 @@ struct let make ~write ~recovered locks = (* If the access is not a write, set to T so intersection with current write-protecting is identity *) - let wlocks = if write then locks else MustLockset.bot () in + let wlocks = if write then locks else MustLockset.all () in if recovered then (* If we are in single-threaded mode again, this does not need to be added to set of mutexes protecting in mt-mode only *) - ((locks, wlocks), (MustLockset.bot (), MustLockset.bot ())) + ((locks, wlocks), (MustLockset.all (), MustLockset.all ())) else ((locks, wlocks), (locks, wlocks)) end @@ -190,7 +190,7 @@ struct let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in let non_overlapping locks1 locks2 = MustLockset.is_empty @@ MustLockset.inter locks1 locks2 in match q with - | Queries.MayBePublic _ when MustLocksetRW.is_bot ls -> false + | Queries.MayBePublic _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublic {global=v; write; protection} -> let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in let protecting = protecting ~write protection v in @@ -199,7 +199,7 @@ struct false else *) non_overlapping held_locks protecting - | Queries.MayBePublicWithout _ when MustLocksetRW.is_bot ls -> false + | Queries.MayBePublicWithout _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> let held_locks = MustLocksetRW.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in let protecting = protecting ~write protection v in @@ -215,7 +215,7 @@ struct (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then true else *) - MustLockset.subset mutex_lockset protecting + MustLockset.subset mutex_lockset protecting (* TODO: some mem? *) | Queries.MustLockset -> let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in MustLockset.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) @@ -280,7 +280,7 @@ struct (*privatization*) match var_opt with | Some v -> - if not (MustLocksetRW.is_bot (fst octx.local)) then + if not (MustLocksetRW.is_all (fst octx.local)) then let locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd (fst octx.local)) in let write = match kind with | Write | Free -> true @@ -299,7 +299,7 @@ struct let protected = G.create_protected @@ GProtected.make ~write vs in MustLockset.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_strong; (* If the mutex set here is top, it is actually not accessed *) - if is_recovered_to_st && not @@ MustLockset.is_bot held_weak then + if is_recovered_to_st && not @@ MustLockset.is_all held_weak then MustLockset.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_weak; ) | None -> M.info ~category:Unsound "Write to unknown address: privatization is unsound." diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 28f3f5b0c6..78f29dbd7f 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -28,7 +28,13 @@ module IdxDom = ValueDomain.IndexDomain open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) -module MustLockset = SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) +module MustLockset = +struct + include SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) + + let all (): t = `Top + let is_all (set: t) = set = `Top +end (* true means exclusive lock and false represents reader lock*) module RW = IntDomain.Booleans @@ -83,6 +89,9 @@ struct let remove_rw mv set = remove (mv, true) (remove (mv, false) set) + let all (): t = `Top + let is_all (set: t) = set = `Top + let export_locks ls = let f (x,_) set = MustLockset.add x set in fold f ls (MustLockset.empty ()) From a7adb466b0e0d7ed32a7eeddd70486fb753c91a1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:25:01 +0300 Subject: [PATCH 112/689] Use MustLockset.disjoint in mutex analysis --- src/analyses/mutexAnalysis.ml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 5fabc1f597..0721263938 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -188,7 +188,6 @@ struct let ls, m = ctx.local in (* get the set of mutexes protecting the variable v in the given mode *) let protecting ~write mode v = GProtecting.get ~write mode (G.protecting (ctx.global (V.protecting v))) in - let non_overlapping locks1 locks2 = MustLockset.is_empty @@ MustLockset.inter locks1 locks2 in match q with | Queries.MayBePublic _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublic {global=v; write; protection} -> @@ -198,7 +197,7 @@ struct (* if Mutexes.mem verifier_atomic (Lockset.export_locks ctx.local) then false else *) - non_overlapping held_locks protecting + MustLockset.disjoint held_locks protecting | Queries.MayBePublicWithout _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> let held_locks = MustLocksetRW.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in @@ -207,7 +206,7 @@ struct (* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) ctx.local)) then false else *) - non_overlapping held_locks protecting + MustLockset.disjoint held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) let mutex_lockset = MustLocksetRW.export_locks @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in From 2e494665af907ee4311e012605a2690b103e8948 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:38:06 +0300 Subject: [PATCH 113/689] Remove Offset.Index.Printable.top --- src/cdomain/value/cdomains/mval.ml | 3 ++- src/cdomain/value/cdomains/mval_intf.ml | 6 +++--- src/cdomain/value/cdomains/offset.ml | 8 ++++---- src/cdomain/value/cdomains/offset_intf.ml | 12 ++++++------ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/cdomain/value/cdomains/mval.ml b/src/cdomain/value/cdomains/mval.ml index 6dd64b68da..b9831fa513 100644 --- a/src/cdomain/value/cdomains/mval.ml +++ b/src/cdomain/value/cdomains/mval.ml @@ -36,12 +36,13 @@ struct let to_cil_exp lv = Lval (to_cil lv) let is_definite (_, o) = Offs.is_definite o - let top_indices (x, o) = (x, Offs.top_indices o) end module MakeLattice (Offs: Offset.Lattice): Lattice with type idx = Offs.idx = struct include MakePrintable (Offs) + + let top_indices (x, o) = (x, Offs.top_indices o) let semantic_equal (x, xoffs) (y, yoffs) = if CilType.Varinfo.equal x y then diff --git a/src/cdomain/value/cdomains/mval_intf.ml b/src/cdomain/value/cdomains/mval_intf.ml index 18aa81c16b..542eb1a300 100644 --- a/src/cdomain/value/cdomains/mval_intf.ml +++ b/src/cdomain/value/cdomains/mval_intf.ml @@ -17,9 +17,6 @@ sig @return [Some o] if it is (such that the variables are equal and [add_offset m1 o = m2]), [None] if it is not. *) - val top_indices: t -> t - (** Change all indices to top indices. *) - val to_cil: t -> GoblintCil.lval (** Convert to CIL lvalue. *) @@ -35,6 +32,9 @@ sig include Printable (** @closed *) include Lattice.S with type t := t (** @closed *) + val top_indices: t -> t + (** Change all indices to top indices. *) + val semantic_equal: t -> t -> bool option (** Check semantic equality of two mvalues. diff --git a/src/cdomain/value/cdomains/offset.ml b/src/cdomain/value/cdomains/offset.ml index 1329f461eb..6d2e312db4 100644 --- a/src/cdomain/value/cdomains/offset.ml +++ b/src/cdomain/value/cdomains/offset.ml @@ -41,7 +41,6 @@ struct let equal_to _ _ = `Top (* TODO: more precise for definite indices *) let to_int _ = None (* TODO: more precise for definite indices *) - let top () = Lazy.force any end module Z = @@ -58,7 +57,6 @@ struct end ) - let top () = failwith "Offset.Index.Z.top" (* TODO: remove from interface? *) let to_int z = Some z let equal_to z1 z2 = if Z.equal z2 z2 then @@ -156,8 +154,6 @@ struct | `Field (f, o) -> `Field (f, map_indices g o) | `Index (i, o) -> `Index (g i, map_indices g o) - let top_indices = map_indices (fun _ -> Idx.top ()) - (* tries to follow o in t *) let rec type_of ~base:t o = match unrollType t, o with (* resolves TNamed *) | t, `NoOffset -> t @@ -202,6 +198,8 @@ struct let widen x y = merge `Widen x y let narrow x y = merge `Narrow x y + let top_indices = map_indices (fun _ -> Idx.top ()) + (* NB! Currently we care only about concrete indexes. Base (seeing only a int domain element) answers with any_index_exp on all non-concrete cases. *) let rec of_exp: exp offs -> t = function @@ -269,6 +267,8 @@ module Exp = struct include MakePrintable (Index.Exp) + let top_indices = map_indices (fun _ -> Lazy.force Index.Exp.any) + let rec of_cil: offset -> t = function | NoOffset -> `NoOffset | Index (i,o) -> `Index (i, of_cil o) diff --git a/src/cdomain/value/cdomains/offset_intf.ml b/src/cdomain/value/cdomains/offset_intf.ml index a0d9ce144c..0c5ccf6a89 100644 --- a/src/cdomain/value/cdomains/offset_intf.ml +++ b/src/cdomain/value/cdomains/offset_intf.ml @@ -15,9 +15,6 @@ struct sig include Printable.S (** @closed *) - val top: unit -> t - (** Unknown index. *) - val equal_to: Z.t -> t -> [`Eq | `Neq | `Top] (** Check semantic equality of an integer and the index. @@ -59,9 +56,6 @@ sig val map_indices: (idx -> idx) -> t -> t (** Apply function to all indexing. *) - val top_indices: t -> t - (** Change all indices to top indices. *) - val to_cil: t -> GoblintCil.offset (** Convert to CIL offset. *) @@ -89,6 +83,9 @@ sig include Printable (** @closed *) include Lattice.S with type t := t (** @closed *) + val top_indices: t -> t + (** Change all indices to top indices. *) + val of_exp: GoblintCil.exp offs -> t (** Convert from Goblint offset with {!GoblintCil.exp} indices. *) @@ -170,6 +167,9 @@ sig sig include Printable with type idx = GoblintCil.exp + val top_indices: t -> t + (** Change all indices to top indices. *) + val of_cil : GoblintCil.offset -> t (** Convert from CIL offset. *) From dcc14cb61a8a9a06bf72938d3fd6599759494ac1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:45:43 +0300 Subject: [PATCH 114/689] Extract Printable.Z --- src/cdomain/value/cdomains/offset.ml | 12 +----------- src/common/domains/printable.ml | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/cdomain/value/cdomains/offset.ml b/src/cdomain/value/cdomains/offset.ml index 6d2e312db4..52867c1a6f 100644 --- a/src/cdomain/value/cdomains/offset.ml +++ b/src/cdomain/value/cdomains/offset.ml @@ -45,18 +45,8 @@ struct module Z = struct - include Printable.StdLeaf (* TODO: move to GobZ *) - include GobZ + include Printable.Z let name () = "Z index" - - (* TODO: move to GobZ *) - include Printable.SimplePretty ( - struct - type nonrec t = t - let pretty = pretty - end - ) - let to_int z = Some z let equal_to z1 z2 = if Z.equal z2 z2 then diff --git a/src/common/domains/printable.ml b/src/common/domains/printable.ml index 24b30ce8e3..1a642c932a 100644 --- a/src/common/domains/printable.ml +++ b/src/common/domains/printable.ml @@ -840,3 +840,17 @@ struct let to_yojson x = x (* override SimplePretty *) end + +module Z: S with type t = Z.t = +struct + include StdLeaf + include GobZ + let name () = "Z" + + include SimplePretty ( + struct + type nonrec t = t + let pretty = pretty + end + ) +end From 32607589bfd0fbf922a2c7cc3f23c80f241c3c71 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 14:57:30 +0300 Subject: [PATCH 115/689] Add Offset.Poly.map_indices --- src/cdomain/value/cdomains/offset.ml | 20 ++++++++++++-------- src/cdomain/value/cdomains/offset_intf.ml | 9 +++++++++ src/cdomains/lockDomain.ml | 14 ++------------ 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/cdomain/value/cdomains/offset.ml b/src/cdomain/value/cdomains/offset.ml index 52867c1a6f..9c9c5c3333 100644 --- a/src/cdomain/value/cdomains/offset.ml +++ b/src/cdomain/value/cdomains/offset.ml @@ -57,6 +57,13 @@ struct end +module Poly = +struct + let rec map_indices g: 'a t -> 'b t = function + | `NoOffset -> `NoOffset + | `Field (f, o) -> `Field (f, map_indices g o) + | `Index (i, o) -> `Index (g i, map_indices g o) +end module MakePrintable (Idx: Index.Printable): Printable with type idx = Idx.t = struct @@ -90,6 +97,8 @@ struct end ) + include Poly + let rec is_definite: t -> bool = function | `NoOffset -> true | `Field (f,o) -> is_definite o @@ -114,7 +123,7 @@ struct | `Field(f,o) -> Field(f, to_cil_offset o) | `Index(i,o) -> NoOffset (* array domain can not deal with this -> leads to being handeled as access to unknown part *) - let rec to_exp: t -> exp offs = function + let rec to_exp: t -> exp offs = function (* TODO: Poly.map_indices *) | `NoOffset -> `NoOffset | `Index (i,o) -> let i_exp = match Idx.to_int i with @@ -139,11 +148,6 @@ struct | `Field (_, os) -> contains_index os | `Index _ -> true - let rec map_indices g: t -> t = function - | `NoOffset -> `NoOffset - | `Field (f, o) -> `Field (f, map_indices g o) - | `Index (i, o) -> `Index (g i, map_indices g o) - (* tries to follow o in t *) let rec type_of ~base:t o = match unrollType t, o with (* resolves TNamed *) | t, `NoOffset -> t @@ -192,7 +196,7 @@ struct (* NB! Currently we care only about concrete indexes. Base (seeing only a int domain element) answers with any_index_exp on all non-concrete cases. *) - let rec of_exp: exp offs -> t = function + let rec of_exp: exp offs -> t = function (* TODO: Poly.map_indices *) | `NoOffset -> `NoOffset | `Index (Const (CInt (i,ik,s)),o) -> `Index (Idx.of_int ik i, of_exp o) | `Index (_,o) -> `Index (Idx.top (), of_exp o) @@ -242,7 +246,7 @@ struct include MakePrintable (Index.Unit) (* TODO: rename to of_poly? *) - let rec of_offs: 'i offs -> t = function + let rec of_offs: 'i offs -> t = function (* TODO: Poly.map_indices *) | `NoOffset -> `NoOffset | `Field (f,o) -> `Field (f, of_offs o) | `Index (i,o) -> `Index ((), of_offs o) diff --git a/src/cdomain/value/cdomains/offset_intf.ml b/src/cdomain/value/cdomains/offset_intf.ml index 0c5ccf6a89..e858f72214 100644 --- a/src/cdomain/value/cdomains/offset_intf.ml +++ b/src/cdomain/value/cdomains/offset_intf.ml @@ -142,6 +142,15 @@ sig exception Type_of_error of GoblintCil.typ * string (** {!Printable.type_of} could not follow offset completely. *) + (** Polymorphic offset operations. *) + module Poly: + sig + val map_indices: ('a -> 'b) -> 'a t -> 'b t + (** Apply function to all indexing. *) + + (* TODO: include more operations *) + end + module type Printable = Printable module type Lattice = Lattice diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 78f29dbd7f..bb365a0def 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -6,20 +6,10 @@ struct include Mval.Z let of_mval ((v, o): ValueDomain.Mval.t): t = - let rec offs = function - | `NoOffset -> `NoOffset - | `Field (f, os') -> `Field (f, offs os') - | `Index (i, os') -> `Index (ValueDomain.IndexDomain.to_int i |> Option.get, offs os') - in - (v, offs o) + (v, Offset.Poly.map_indices (fun i -> ValueDomain.IndexDomain.to_int i |> Option.get) o) let to_mval ((v, o): t): ValueDomain.Mval.t = - let rec offs = function - | `NoOffset -> `NoOffset - | `Field (f, os') -> `Field (f, offs os') - | `Index (i, os') -> `Index (ValueDomain.IndexDomain.of_int (Cilfacade.ptrdiff_ikind ()) i, offs os') - in - (v, offs o) + (v, Offset.Poly.map_indices (ValueDomain.IndexDomain.of_int (Cilfacade.ptrdiff_ikind ())) o) end module Offs = ValueDomain.Offs module Exp = CilType.Exp From 91a838f360877249dfb6b1a52f3f0c5b11a0c908 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 15:08:16 +0300 Subject: [PATCH 116/689] Clean up module aliases in LockDomain --- src/analyses/mutexAnalysis.ml | 3 ++- src/cdomains/lockDomain.ml | 35 +++++++++++++++++++---------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 0721263938..bce072e3ee 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -1,6 +1,7 @@ (** Must lockset and protecting lockset analysis ([mutex]). *) module M = Messages +module Mval = ValueDomain.Mval module Addr = ValueDomain.Addr module Lock = LockDomain.Lock module MustLockset = LockDomain.MustLockset @@ -139,7 +140,7 @@ struct | Some mv -> let (s, m) = ctx.local in if warn && not (MustLocksetRW.mem_rw mv s) then - M.warn "unlocking mutex (%a) which may not be held" ValueDomain.Mval.pretty mv; + M.warn "unlocking mutex (%a) which may not be held" Mval.pretty mv; if MutexTypeAnalysis.must_be_recursive ctx mv then ( let (m', rmed) = MustMultiplicity.decrement mv m in if rmed then diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index bb365a0def..6d14a4099e 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -1,21 +1,24 @@ (** Lockset domains. *) +open GoblintCil +open struct + module MvalZ = Mval.Z (* So we can define MustLock using Mval.Z after redefining Mval *) +end + +module IndexDomain = ValueDomain.IndexDomain +module Mval = ValueDomain.Mval module Addr = ValueDomain.Addr + module MustLock = struct - include Mval.Z + include MvalZ - let of_mval ((v, o): ValueDomain.Mval.t): t = - (v, Offset.Poly.map_indices (fun i -> ValueDomain.IndexDomain.to_int i |> Option.get) o) + let of_mval ((v, o): Mval.t): t = + (v, Offset.Poly.map_indices (fun i -> IndexDomain.to_int i |> Option.get) o) - let to_mval ((v, o): t): ValueDomain.Mval.t = - (v, Offset.Poly.map_indices (ValueDomain.IndexDomain.of_int (Cilfacade.ptrdiff_ikind ())) o) + let to_mval ((v, o): t): Mval.t = + (v, Offset.Poly.map_indices (IndexDomain.of_int (Cilfacade.ptrdiff_ikind ())) o) end -module Offs = ValueDomain.Offs -module Exp = CilType.Exp -module IdxDom = ValueDomain.IndexDomain - -open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) module MustLockset = @@ -68,12 +71,12 @@ struct remove (MustLock.of_mval mv, rw) set else filter (fun (mv', _) -> - (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) - ValueDomain.Mval.semantic_equal mv (MustLock.to_mval mv') = Some false + (* TODO: avoid conversion: semantic_equal between Mval and Mval *) + Mval.semantic_equal mv (MustLock.to_mval mv') = Some false ) set let mem_rw mv set = - ValueDomain.Mval.is_definite mv && ( + Mval.is_definite mv && ( mem (MustLock.of_mval mv, true) set || mem (MustLock.of_mval mv, false) set) let remove_rw mv set = @@ -130,8 +133,8 @@ module MustMultiplicity = struct else (* TODO: non-definite should also decrement (to 0)? *) fold (fun mv' _ (m, rmed) -> - (* TODO: avoid conversion: semantic_equal between ValueDomain.Mval and Mval *) - if ValueDomain.Mval.semantic_equal mv (MustLock.to_mval mv') = Some false then + (* TODO: avoid conversion: semantic_equal between Mval and Mval *) + if Mval.semantic_equal mv (MustLock.to_mval mv') = Some false then (m, rmed) else ( let (m', rmed') = decrement mv' m in @@ -148,7 +151,7 @@ end module Symbolic = struct (* TODO: use SetDomain.Reverse *) - module S = SetDomain.ToppedSet (Exp) (struct let topname = "All mutexes" end) + module S = SetDomain.ToppedSet (CilType.Exp) (struct let topname = "All mutexes" end) include Lattice.Reverse (S) let rec eq_set (ask: Queries.ask) e = From 9d53138406ad77d6a16f62d340ba8a25635a8100 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 15:10:31 +0300 Subject: [PATCH 117/689] Rename LockDomain.Lock -> AddrRW --- src/analyses/deadlock.ml | 2 +- src/analyses/locksetAnalysis.ml | 2 +- src/analyses/mutexAnalysis.ml | 4 ++-- src/cdomains/lockDomain.ml | 7 +++---- src/domains/events.ml | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/analyses/deadlock.ml b/src/analyses/deadlock.ml index 23b9faa882..e83b122fd9 100644 --- a/src/analyses/deadlock.ml +++ b/src/analyses/deadlock.ml @@ -30,7 +30,7 @@ struct let part_access ctx: MCPAccess.A.t = Obj.obj (ctx.ask (PartAccess Point)) - let add ctx ((l, _): LockDomain.Lock.t) = + let add ctx ((l, _): LockDomain.AddrRW.t) = let after: LockEvent.t = (l, ctx.prev_node, part_access ctx) in (* use octx for access to use locksets before event *) D.iter (fun before -> side_lock_event_pair ctx before after diff --git a/src/analyses/locksetAnalysis.ml b/src/analyses/locksetAnalysis.ml index c7c7395dc1..4c8ec3544c 100644 --- a/src/analyses/locksetAnalysis.ml +++ b/src/analyses/locksetAnalysis.ml @@ -29,7 +29,7 @@ sig module G: Lattice.S module V: SpecSysVar - val add: (D.t, G.t, D.t, V.t) ctx -> LockDomain.Lock.t -> D.t + val add: (D.t, G.t, D.t, V.t) ctx -> LockDomain.AddrRW.t -> D.t val remove: (D.t, G.t, D.t, V.t) ctx -> ValueDomain.Addr.t -> D.t end diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index bce072e3ee..23246326b2 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -3,7 +3,7 @@ module M = Messages module Mval = ValueDomain.Mval module Addr = ValueDomain.Addr -module Lock = LockDomain.Lock +module AddrRW = LockDomain.AddrRW module MustLockset = LockDomain.MustLockset module MustLocksetRW = LockDomain.MustLocksetRW module MustMultiplicity = LockDomain.MustMultiplicity @@ -120,7 +120,7 @@ struct let create_protected protected = `Lifted2 protected end - let add ctx ((addr, rw): Lock.t): D.t = + let add ctx ((addr, rw): AddrRW.t): D.t = match Addr.to_mval addr with | Some mv -> let (s, m) = ctx.local in diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 6d14a4099e..e492cfe65d 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -33,7 +33,7 @@ end module RW = IntDomain.Booleans (* pair Addr and RW; also change pretty printing*) -module MakeLockRW (P: Printable.S) = +module MakeRW (P: Printable.S) = struct include Printable.Prod (P) (RW) @@ -51,9 +51,8 @@ struct ) end -module Lock = MakeLockRW (Addr) - -module MustLockRW = MakeLockRW (MustLock) +module AddrRW = MakeRW (Addr) +module MustLockRW = MakeRW (MustLock) module MustLocksetRW = struct diff --git a/src/domains/events.ml b/src/domains/events.ml index 90eb7611be..b194847bac 100644 --- a/src/domains/events.ml +++ b/src/domains/events.ml @@ -4,7 +4,7 @@ open GoblintCil open Pretty type t = - | Lock of LockDomain.Lock.t + | Lock of LockDomain.AddrRW.t | Unlock of LockDomain.Addr.t | Escape of EscapeDomain.EscapedVars.t | EnterMultiThreaded @@ -35,7 +35,7 @@ let emit_on_deadcode = function false let pretty () = function - | Lock m -> dprintf "Lock %a" LockDomain.Lock.pretty m + | Lock m -> dprintf "Lock %a" LockDomain.AddrRW.pretty m | Unlock m -> dprintf "Unlock %a" LockDomain.Addr.pretty m | Escape escaped -> dprintf "Escape %a" EscapeDomain.EscapedVars.pretty escaped | EnterMultiThreaded -> text "EnterMultiThreaded" From be66f67eb95813dbce5b7a840171c5ccb67fc32d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 15:11:44 +0300 Subject: [PATCH 118/689] Remove LockDomain.Mutexes --- src/analyses/mutexAnalysis.ml | 1 - src/analyses/mutexEventsAnalysis.ml | 3 +-- src/cdomains/lockDomain.ml | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 23246326b2..baeb79c49a 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -7,7 +7,6 @@ module AddrRW = LockDomain.AddrRW module MustLockset = LockDomain.MustLockset module MustLocksetRW = LockDomain.MustLocksetRW module MustMultiplicity = LockDomain.MustMultiplicity -module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open GoblintCil open Analyses diff --git a/src/analyses/mutexEventsAnalysis.ml b/src/analyses/mutexEventsAnalysis.ml index 2252dae8a7..2f31384ab9 100644 --- a/src/analyses/mutexEventsAnalysis.ml +++ b/src/analyses/mutexEventsAnalysis.ml @@ -4,7 +4,6 @@ module M = Messages module Addr = ValueDomain.Addr -module Mutexes = LockDomain.Mutexes module LF = LibraryFunctions open Batteries open GoblintCil @@ -20,7 +19,7 @@ struct let eval_exp_addr (a: Queries.ask) exp = a.f (Queries.MayPointTo exp) let lock ctx rw may_fail nonzero_return_when_aquired a lv_opt arg = - let compute_refine_split (e:Mutexes.elt) = match e with + let compute_refine_split (e: Addr.t) = match e with | Addr a -> let e' = BinOp(Eq, arg, AddrOf ((PreValueDomain.Mval.to_cil a)), intType) in [Events.SplitBranch (e',true)] diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index e492cfe65d..a171700348 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -20,7 +20,6 @@ struct (v, Offset.Poly.map_indices (IndexDomain.of_int (Cilfacade.ptrdiff_ikind ())) o) end -module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) module MustLockset = struct include SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) From dad04cc7f25902a8c7c97527484d9eb1164ca559 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 15:19:28 +0300 Subject: [PATCH 119/689] Rename LockDomain.MustLocksetRW functions --- src/analyses/mutexAnalysis.ml | 20 ++++++++++---------- src/cdomains/lockDomain.ml | 13 +++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index baeb79c49a..20050ecea3 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -123,7 +123,7 @@ struct match Addr.to_mval addr with | Some mv -> let (s, m) = ctx.local in - let s' = MustLocksetRW.add (mv, rw) s in + let s' = MustLocksetRW.add_mval_rw (mv, rw) s in let m' = if MutexTypeAnalysis.must_be_recursive ctx mv then MustMultiplicity.increment mv m @@ -138,19 +138,19 @@ struct | None -> ctx.local | Some mv -> let (s, m) = ctx.local in - if warn && not (MustLocksetRW.mem_rw mv s) then + if warn && not (MustLocksetRW.mem_mval mv s) then M.warn "unlocking mutex (%a) which may not be held" Mval.pretty mv; if MutexTypeAnalysis.must_be_recursive ctx mv then ( let (m', rmed) = MustMultiplicity.decrement mv m in if rmed then (* TODO: don't repeat the same semantic_equal checks *) (* TODO: rmed per lockset element, not aggregated *) - (MustLocksetRW.remove_rw mv s, m') + (MustLocksetRW.remove_mval mv s, m') else (s, m') ) else - (MustLocksetRW.remove_rw mv s, m) (* TODO: should decrement something if may be recursive? *) + (MustLocksetRW.remove_mval mv s, m) (* TODO: should decrement something if may be recursive? *) let remove = remove' ~warn:true @@ -191,7 +191,7 @@ struct match q with | Queries.MayBePublic _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublic {global=v; write; protection} -> - let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in + let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks ctx.local) then @@ -200,7 +200,7 @@ struct MustLockset.disjoint held_locks protecting | Queries.MayBePublicWithout _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> - let held_locks = MustLocksetRW.export_locks @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in + let held_locks = MustLocksetRW.to_must_lockset @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) ctx.local)) then @@ -208,7 +208,7 @@ struct else *) MustLockset.disjoint held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) - let mutex_lockset = MustLocksetRW.export_locks @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) + let mutex_lockset = MustLocksetRW.to_must_lockset @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then @@ -216,10 +216,10 @@ struct else *) MustLockset.subset mutex_lockset protecting (* TODO: some mem? *) | Queries.MustLockset -> - let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in + let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in MustLockset.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) | Queries.MustBeAtomic -> - let held_locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd ls) in + let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in MustLockset.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval m)))) in (* TODO: what if non-definite? *) @@ -280,7 +280,7 @@ struct match var_opt with | Some v -> if not (MustLocksetRW.is_all (fst octx.local)) then - let locks = MustLocksetRW.export_locks (MustLocksetRW.filter snd (fst octx.local)) in + let locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd (fst octx.local)) in let write = match kind with | Write | Free -> true | Read -> false diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index a171700348..aa14834e4a 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -50,6 +50,7 @@ struct ) end +module MvalRW = MakeRW (Mval) module AddrRW = MakeRW (Addr) module MustLockRW = MakeRW (MustLock) @@ -58,13 +59,13 @@ struct include SetDomain.Reverse (SetDomain.ToppedSet (MustLockRW) (struct let topname = "All mutexes" end)) let name () = "lockset" - let add (mv, rw) set = + let add_mval_rw ((mv, rw): MvalRW.t) (set: t) = if Addr.Mval.is_definite mv then add (MustLock.of_mval mv, rw) set else set - let remove (mv, rw) set = + let remove_mval_rw ((mv, rw): MvalRW.t) (set: t) = if Addr.Mval.is_definite mv then remove (MustLock.of_mval mv, rw) set else @@ -73,17 +74,17 @@ struct Mval.semantic_equal mv (MustLock.to_mval mv') = Some false ) set - let mem_rw mv set = + let mem_mval (mv: Mval.t) (set: t) = Mval.is_definite mv && ( mem (MustLock.of_mval mv, true) set || mem (MustLock.of_mval mv, false) set) - let remove_rw mv set = - remove (mv, true) (remove (mv, false) set) + let remove_mval (mv: Mval.t) set = + remove_mval_rw (mv, true) (remove_mval_rw (mv, false) set) let all (): t = `Top let is_all (set: t) = set = `Top - let export_locks ls = + let to_must_lockset (ls: t): MustLockset.t = let f (x,_) set = MustLockset.add x set in fold f ls (MustLockset.empty ()) end From 07165ae724f9ba2627beff3f5a087a459ebc719b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 15:35:03 +0300 Subject: [PATCH 120/689] Add LockDomain.MustLock.semantic_equal_mval --- src/cdomains/lockDomain.ml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index aa14834e4a..c308de6b7a 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -13,6 +13,18 @@ module MustLock = struct include MvalZ + let semantic_equal_mval ((v, o): t) ((v', o'): Mval.t): bool option = + if CilType.Varinfo.equal v v' then ( + let (index1, _) = GoblintCil.bitsOffset v.vtype (Offset.Z.to_cil o) in (* TODO: better way to compute this? as Z.t not int *) + let index2: IndexDomain.t = ValueDomain.Offs.to_index ~typ:v.vtype o' in (* TODO: is this bits or bytes? *) + match IndexDomain.equal_to (Z.of_int index1) index2 with + | `Eq -> Some true + | `Neq -> Some false + | `Top -> None + ) + else + Some false + let of_mval ((v, o): Mval.t): t = (v, Offset.Poly.map_indices (fun i -> IndexDomain.to_int i |> Option.get) o) @@ -70,8 +82,7 @@ struct remove (MustLock.of_mval mv, rw) set else filter (fun (mv', _) -> - (* TODO: avoid conversion: semantic_equal between Mval and Mval *) - Mval.semantic_equal mv (MustLock.to_mval mv') = Some false + MustLock.semantic_equal_mval mv' mv = Some false ) set let mem_mval (mv: Mval.t) (set: t) = @@ -132,8 +143,7 @@ module MustMultiplicity = struct else (* TODO: non-definite should also decrement (to 0)? *) fold (fun mv' _ (m, rmed) -> - (* TODO: avoid conversion: semantic_equal between Mval and Mval *) - if Mval.semantic_equal mv (MustLock.to_mval mv') = Some false then + if MustLock.semantic_equal_mval mv' mv = Some false then (m, rmed) else ( let (m', rmed') = decrement mv' m in From f9cd80a5e3dbad64a5e350c5843e3f0d0a28defc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 15:41:25 +0300 Subject: [PATCH 121/689] Update some variable names in mutex analysis --- src/analyses/mutexAnalysis.ml | 12 ++++++------ src/cdomains/lockDomain.ml | 20 ++++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 20050ecea3..ed1efbc2ef 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -207,8 +207,8 @@ struct false else *) MustLockset.disjoint held_locks protecting - | Queries.MustBeProtectedBy {mutex = Addr mutex; global=v; write; protection} -> (* TODO: non-Addr? *) - let mutex_lockset = MustLocksetRW.to_must_lockset @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex, true) in (* TODO: what if non-definite? *) + | Queries.MustBeProtectedBy {mutex = Addr mutex_mv; global=v; write; protection} -> (* TODO: non-Addr? *) + let mutex_lockset = MustLocksetRW.to_must_lockset @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex_mv, true) in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then @@ -221,8 +221,8 @@ struct | Queries.MustBeAtomic -> let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in MustLockset.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) - | Queries.MustProtectedVars {mutex = Addr m; write} -> (* TODO: non-Addr? *) - let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval m)))) in (* TODO: what if non-definite? *) + | Queries.MustProtectedVars {mutex = Addr mutex_mv; write} -> (* TODO: non-Addr? *) + let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval mutex_mv)))) in (* TODO: what if non-definite? *) VarSet.fold (fun v acc -> Queries.VS.add v acc ) protected (Queries.VS.empty ()) @@ -296,10 +296,10 @@ struct let held_weak = protecting Weak in let vs = VarSet.singleton v in let protected = G.create_protected @@ GProtected.make ~write vs in - MustLockset.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_strong; + MustLockset.iter (fun ml -> ctx.sideg (V.protected ml) protected) held_strong; (* If the mutex set here is top, it is actually not accessed *) if is_recovered_to_st && not @@ MustLockset.is_all held_weak then - MustLockset.iter (fun mv -> ctx.sideg (V.protected mv) protected) held_weak; + MustLockset.iter (fun ml -> ctx.sideg (V.protected ml) protected) held_weak; ) | None -> M.info ~category:Unsound "Write to unknown address: privatization is unsound." in diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index c308de6b7a..e106b204c5 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -81,13 +81,17 @@ struct if Addr.Mval.is_definite mv then remove (MustLock.of_mval mv, rw) set else - filter (fun (mv', _) -> - MustLock.semantic_equal_mval mv' mv = Some false + filter (fun (ml, _) -> + MustLock.semantic_equal_mval ml mv = Some false ) set let mem_mval (mv: Mval.t) (set: t) = - Mval.is_definite mv && ( - mem (MustLock.of_mval mv, true) set || mem (MustLock.of_mval mv, false) set) + if Mval.is_definite mv then ( + let ml = MustLock.of_mval mv in + mem (ml, true) set || mem (ml, false) set + ) + else + false let remove_mval (mv: Mval.t) set = remove_mval_rw (mv, true) (remove_mval_rw (mv, false) set) @@ -96,7 +100,7 @@ struct let is_all (set: t) = set = `Top let to_must_lockset (ls: t): MustLockset.t = - let f (x,_) set = MustLockset.add x set in + let f (ml, _) set = MustLockset.add ml set in fold f ls (MustLockset.empty ()) end @@ -142,11 +146,11 @@ module MustMultiplicity = struct decrement (MustLock.of_mval mv) m else (* TODO: non-definite should also decrement (to 0)? *) - fold (fun mv' _ (m, rmed) -> - if MustLock.semantic_equal_mval mv' mv = Some false then + fold (fun ml _ (m, rmed) -> + if MustLock.semantic_equal_mval ml mv = Some false then (m, rmed) else ( - let (m', rmed') = decrement mv' m in + let (m', rmed') = decrement ml m in (m', rmed || rmed') ) ) m (m, false) From 03f451f2f960710b8e56bf813c50785c70cf216a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 16:07:31 +0300 Subject: [PATCH 122/689] Use mem for MustBeProtectedBy query --- src/analyses/mutexAnalysis.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index ed1efbc2ef..a9253f26e8 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -208,13 +208,13 @@ struct else *) MustLockset.disjoint held_locks protecting | Queries.MustBeProtectedBy {mutex = Addr mutex_mv; global=v; write; protection} -> (* TODO: non-Addr? *) - let mutex_lockset = MustLocksetRW.to_must_lockset @@ MustLocksetRW.singleton (LockDomain.MustLock.of_mval mutex_mv, true) in (* TODO: what if non-definite? *) + let ml = LockDomain.MustLock.of_mval mutex_mv in (* TODO: what if non-definite? *) let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then true else *) - MustLockset.subset mutex_lockset protecting (* TODO: some mem? *) + MustLockset.mem ml protecting | Queries.MustLockset -> let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in MustLockset.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) From ac7ffdfad5efecb767103e3fd9ca9354548969f1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:57:06 +0300 Subject: [PATCH 123/689] Move LockDomain.Symbolic to SymbLocksDomain --- src/analyses/symbLocks.ml | 4 +-- src/cdomains/lockDomain.ml | 53 +-------------------------------- src/cdomains/symbLocksDomain.ml | 51 +++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 6fd18de6ff..b1727ace81 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -23,8 +23,8 @@ struct exception Top - module D = LockDomain.Symbolic - module C = LockDomain.Symbolic + module D = SymbLocksDomain.Symbolic + module C = SymbLocksDomain.Symbolic let name () = "symb_locks" diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index e106b204c5..35d73e5f28 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -1,6 +1,5 @@ (** Lockset domains. *) -open GoblintCil open struct module MvalZ = Mval.Z (* So we can define MustLock using Mval.Z after redefining Mval *) end @@ -52,7 +51,7 @@ struct if write then P.pretty () a else - Pretty.dprintf "read lock %a" P.pretty a + GoblintCil.Pretty.dprintf "read lock %a" P.pretty a include Printable.SimplePretty ( struct @@ -160,53 +159,3 @@ module MayLocksetNoRW = struct include PreValueDomain.AD end - -module Symbolic = -struct - (* TODO: use SetDomain.Reverse *) - module S = SetDomain.ToppedSet (CilType.Exp) (struct let topname = "All mutexes" end) - include Lattice.Reverse (S) - - let rec eq_set (ask: Queries.ask) e = - S.union - (match ask.f (Queries.EqualSet e) with - | es when not (Queries.ES.is_bot es) -> - Queries.ES.fold S.add es (S.empty ()) - | _ -> S.empty ()) - (match e with - | SizeOf _ - | SizeOfE _ - | SizeOfStr _ - | AlignOf _ - | Const _ - | AlignOfE _ - | UnOp _ - | BinOp _ - | Question _ - | Real _ - | Imag _ - | AddrOfLabel _ -> S.empty () - | AddrOf (Var _,_) - | StartOf (Var _,_) - | Lval (Var _,_) -> S.singleton e - | AddrOf (Mem e,ofs) -> S.map (fun e -> AddrOf (Mem e,ofs)) (eq_set ask e) - | StartOf (Mem e,ofs) -> S.map (fun e -> StartOf (Mem e,ofs)) (eq_set ask e) - | Lval (Mem e,ofs) -> S.map (fun e -> Lval (Mem e,ofs)) (eq_set ask e) - | CastE (_,e) -> eq_set ask e - ) - - let add (ask: Queries.ask) e st = - let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in - let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in - S.union addrs st - let remove ask e st = - (* TODO: Removing based on must-equality sets is not sound! *) - let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in - let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in - S.diff st addrs - let remove_var v st = S.filter (fun x -> not (SymbLocksDomain.Exp.contains_var v x)) st - - let filter = S.filter - let fold = S.fold - -end diff --git a/src/cdomains/symbLocksDomain.ml b/src/cdomains/symbLocksDomain.ml index ba2b96e8d0..10ea70da1d 100644 --- a/src/cdomains/symbLocksDomain.ml +++ b/src/cdomains/symbLocksDomain.ml @@ -317,3 +317,54 @@ struct let of_mval (v, o) = of_mval (v, conv_const_offset o) end + + +module Symbolic = +struct + (* TODO: use SetDomain.Reverse *) + module S = SetDomain.ToppedSet (CilType.Exp) (struct let topname = "All mutexes" end) + include Lattice.Reverse (S) + + let rec eq_set (ask: Queries.ask) e = + S.union + (match ask.f (Queries.EqualSet e) with + | es when not (Queries.ES.is_bot es) -> + Queries.ES.fold S.add es (S.empty ()) + | _ -> S.empty ()) + (match e with + | SizeOf _ + | SizeOfE _ + | SizeOfStr _ + | AlignOf _ + | Const _ + | AlignOfE _ + | UnOp _ + | BinOp _ + | Question _ + | Real _ + | Imag _ + | AddrOfLabel _ -> S.empty () + | AddrOf (Var _,_) + | StartOf (Var _,_) + | Lval (Var _,_) -> S.singleton e + | AddrOf (Mem e,ofs) -> S.map (fun e -> AddrOf (Mem e,ofs)) (eq_set ask e) + | StartOf (Mem e,ofs) -> S.map (fun e -> StartOf (Mem e,ofs)) (eq_set ask e) + | Lval (Mem e,ofs) -> S.map (fun e -> Lval (Mem e,ofs)) (eq_set ask e) + | CastE (_,e) -> eq_set ask e + ) + + let add (ask: Queries.ask) e st = + let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in + let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in + S.union addrs st + let remove ask e st = + (* TODO: Removing based on must-equality sets is not sound! *) + let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in + let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in + S.diff st addrs + let remove_var v st = S.filter (fun x -> not (Exp.contains_var v x)) st + + let filter = S.filter + let fold = S.fold + +end From 842b851f3f2fc8b659967cc9eb3148e16c945d6b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 17:55:10 +0300 Subject: [PATCH 124/689] Use LockDomain.MustLockset for MustLockset query --- src/analyses/commonPriv.ml | 8 ++++---- src/analyses/mutexAnalysis.ml | 2 +- src/domains/queries.ml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 6376a6ca11..9f6fc14bd8 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -73,8 +73,8 @@ struct ask.f (Q.MustBeProtectedBy {mutex=m; global=x; write=true; protection}) let protected_vars (ask: Q.ask): varinfo list = - Q.AD.fold (fun m acc -> - Q.VS.join (ask.f (Q.MustProtectedVars {mutex = m; write = true})) acc + LockDomain.MustLockset.fold (fun ml acc -> + Q.VS.join (ask.f (Q.MustProtectedVars {mutex = Addr (LockDomain.MustLock.to_mval ml); write = true})) acc (* TODO: avoid Addr conversion *) ) (ask.f Q.MustLockset) (Q.VS.empty ()) |> Q.VS.elements end @@ -136,8 +136,8 @@ struct if !AnalysisState.global_initialization then Lockset.empty () else - let ad = ask.f Queries.MustLockset in - Q.AD.fold (fun mls acc -> Lockset.add mls acc) ad (Lockset.empty ()) (* TODO: use AD as Lockset *) + let mls = ask.f Queries.MustLockset in + LockDomain.MustLockset.fold (fun ml acc -> Lockset.add (Addr (LockDomain.MustLock.to_mval ml)) acc) mls (Lockset.empty ()) (* TODO: use MustLockset as Lockset *) (* TODO: reversed SetDomain.Hoare *) module MinLocksets = HoareDomain.Set_LiftTop (MustLockset) (struct let topname = "All locksets" end) (* reverse Lockset because Hoare keeps maximal, but we need minimal *) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index a9253f26e8..339856fcc9 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -217,7 +217,7 @@ struct MustLockset.mem ml protecting | Queries.MustLockset -> let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in - MustLockset.fold (fun addr ls -> Queries.AD.add (Addr (LockDomain.MustLock.to_mval addr)) ls) held_locks (Queries.AD.empty ()) (* TODO: Z indices for Queries.MustLockset result? *) + held_locks | Queries.MustBeAtomic -> let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in MustLockset.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index f5d7be21a4..7c6553d1bf 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -74,7 +74,7 @@ type _ t = | MayBePublic: maybepublic -> MayBool.t t (* old behavior with write=false *) | MayBePublicWithout: maybepublicwithout -> MayBool.t t | MustBeProtectedBy: mustbeprotectedby -> MustBool.t t - | MustLockset: AD.t t + | MustLockset: LockDomain.MustLockset.t t | MustBeAtomic: MustBool.t t | MustBeSingleThreaded: {since_start: bool} -> MustBool.t t | MustBeUniqueThread: MustBool.t t @@ -147,7 +147,7 @@ struct | MayPointTo _ -> (module AD) | ReachableFrom _ -> (module AD) | Regions _ -> (module LS) - | MustLockset -> (module AD) + | MustLockset -> (module LockDomain.MustLockset) | EvalFunvar _ -> (module AD) | ReachableUkTypes _ -> (module TS) | MayEscape _ -> (module MayBool) @@ -216,7 +216,7 @@ struct | MayPointTo _ -> AD.top () | ReachableFrom _ -> AD.top () | Regions _ -> LS.top () - | MustLockset -> AD.top () + | MustLockset -> LockDomain.MustLockset.top () | EvalFunvar _ -> AD.top () | ReachableUkTypes _ -> TS.top () | MayEscape _ -> MayBool.top () From 2371033389e8d06f5e8c9e94d0b859ec72002fad Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 17:59:35 +0300 Subject: [PATCH 125/689] Use LockDomain.MustLock for MustProtectedVars query --- src/analyses/commonPriv.ml | 2 +- src/analyses/mutexAnalysis.ml | 4 ++-- src/domains/queries.ml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 9f6fc14bd8..ed236459da 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -74,7 +74,7 @@ struct let protected_vars (ask: Q.ask): varinfo list = LockDomain.MustLockset.fold (fun ml acc -> - Q.VS.join (ask.f (Q.MustProtectedVars {mutex = Addr (LockDomain.MustLock.to_mval ml); write = true})) acc (* TODO: avoid Addr conversion *) + Q.VS.join (ask.f (Q.MustProtectedVars {mutex = ml; write = true})) acc ) (ask.f Q.MustLockset) (Q.VS.empty ()) |> Q.VS.elements end diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 339856fcc9..71b3a7e07e 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -221,8 +221,8 @@ struct | Queries.MustBeAtomic -> let held_locks = MustLocksetRW.to_must_lockset (MustLocksetRW.filter snd ls) in MustLockset.mem (LF.verifier_atomic_var, `NoOffset) held_locks (* TODO: Mval.of_var *) - | Queries.MustProtectedVars {mutex = Addr mutex_mv; write} -> (* TODO: non-Addr? *) - let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected (LockDomain.MustLock.of_mval mutex_mv)))) in (* TODO: what if non-definite? *) + | Queries.MustProtectedVars {mutex; write} -> + let protected = GProtected.get ~write Strong (G.protected (ctx.global (V.protected mutex))) in VarSet.fold (fun v acc -> Queries.VS.add v acc ) protected (Queries.VS.empty ()) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 7c6553d1bf..a904f696eb 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -51,7 +51,7 @@ end type maybepublic = {global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash] type maybepublicwithout = {global: CilType.Varinfo.t; write: bool; without_mutex: PreValueDomain.Addr.t; protection: Protection.t} [@@deriving ord, hash] type mustbeprotectedby = {mutex: PreValueDomain.Addr.t; global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash] -type mustprotectedvars = {mutex: PreValueDomain.Addr.t; write: bool} [@@deriving ord, hash] +type mustprotectedvars = {mutex: LockDomain.MustLock.t; write: bool} [@@deriving ord, hash] type access = | Memory of {exp: CilType.Exp.t; var_opt: CilType.Varinfo.t option; kind: AccessKind.t} (** Memory location access (race). *) | Point (** Program point and state access (MHP), independent of memory location. *) From 02101745fc5654bb3a021bd03328dea04fb0ac91 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 18:17:53 +0300 Subject: [PATCH 126/689] Fix MustBeProtectedBy TODO --- src/analyses/mutexAnalysis.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 71b3a7e07e..4e369d0de2 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -207,8 +207,8 @@ struct false else *) MustLockset.disjoint held_locks protecting - | Queries.MustBeProtectedBy {mutex = Addr mutex_mv; global=v; write; protection} -> (* TODO: non-Addr? *) - let ml = LockDomain.MustLock.of_mval mutex_mv in (* TODO: what if non-definite? *) + | Queries.MustBeProtectedBy {mutex = Addr mutex_mv; global=v; write; protection} when Mval.is_definite mutex_mv -> (* only definite Addrs can be in must-locksets to begin with, anything else cannot protect anything *) + let ml = LockDomain.MustLock.of_mval mutex_mv in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then From 8d5cc1275a71283c88cdd3136715da524cec7b51 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:13:39 +0300 Subject: [PATCH 127/689] Add svcomp-ghost conf --- conf/svcomp-ghost.json | 145 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 conf/svcomp-ghost.json diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json new file mode 100644 index 0000000000..62feb25993 --- /dev/null +++ b/conf/svcomp-ghost.json @@ -0,0 +1,145 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "mutexGhosts", + "pthreadMutexType" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "malloc": { + "wrappers": [ + "kmalloc", + "__kmalloc", + "usb_alloc_urb", + "__builtin_alloca", + "kzalloc", + + "ldv_malloc", + + "kzalloc_node", + "ldv_zalloc", + "kmalloc_array", + "kcalloc", + + "ldv_xmalloc", + "ldv_xzalloc", + "ldv_calloc", + "ldv_kzalloc" + ] + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "flow_insensitive_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": true, + "other": true, + "accessed": true, + "exact": true, + "all-locals": false, + "flow_insensitive-as-location": true, + "exclude-vars": [ + "tmp\\(___[0-9]+\\)?", + "cond", + "RETURN", + "__\\(cil_\\)?tmp_?[0-9]*\\(_[0-9]+\\)?", + ".*____CPAchecker_TMP_[0-9]+", + "__VERIFIER_assert__cond", + "__ksymtab_.*", + "\\(ldv_state_variable\\|ldv_timer_state\\|ldv_timer_list\\|ldv_irq_\\(line_\\|data_\\)?[0-9]+\\|ldv_retval\\)_[0-9]+" + ] + } + }, + "pre": { + "enabled": false + } +} From 96d862e4369df5355f80fcc69a94c7e53de806ac Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:14:19 +0300 Subject: [PATCH 128/689] Use YAML witness format-version 0.1 for svcomp-ghost --- conf/svcomp-ghost.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 62feb25993..229dd9ef46 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -114,7 +114,7 @@ }, "yaml": { "enabled": true, - "format-version": "2.0", + "format-version": "0.1", "entry-types": [ "flow_insensitive_invariant" ] From 257fa8cd374f4b339427eb4c2c52cf67d72aa298 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:24:44 +0300 Subject: [PATCH 129/689] Test witness.invariant.flow_insensitive-as-location with for loop --- .../regression/13-privatized/04-priv_multi.t | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 tests/regression/13-privatized/04-priv_multi.t diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t new file mode 100644 index 0000000000..9bdf8ac5a7 --- /dev/null +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -0,0 +1,309 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 04-priv_multi.c + [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) + [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) + [Warning][Deadcode] Function 'dispose' has dead code: + on line 53 (04-priv_multi.c:53-53) + on line 56 (04-priv_multi.c:56-56) + [Warning][Deadcode] Function 'process' has dead code: + on line 37 (04-priv_multi.c:37-37) + on line 40 (04-priv_multi.c:40-40) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 40 + dead: 4 + total lines: 44 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:25:10-25:11) + [Warning][Deadcode][CWE-571] condition 'A > 0' is always true (04-priv_multi.c:27:9-27:14) + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) + [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) + [Info][Witness] witness generation summary: + total generation entries: 19 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml + - entry_type: ghost_update + variable: mutex_B_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 69 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_B_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 46 + column: 5 + function: dispose + - entry_type: ghost_update + variable: mutex_B_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 29 + column: 7 + function: process + - entry_type: ghost_update + variable: mutex_B_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 73 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_B_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 49 + column: 7 + function: dispose + - entry_type: ghost_update + variable: mutex_B_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 32 + column: 7 + function: process + - entry_type: ghost_update + variable: mutex_A_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 68 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_A_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 26 + column: 5 + function: process + - entry_type: ghost_update + variable: mutex_A_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 15 + column: 5 + function: generate + - entry_type: ghost_update + variable: mutex_A_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 74 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_A_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 34 + column: 7 + function: process + - entry_type: ghost_update + variable: mutex_A_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 18 + column: 5 + function: generate + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 63 + column: 3 + function: main + - entry_type: ghost_variable + variable: mutex_B_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: mutex_A_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (mutex_A_locked || A == 5)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' + type: assertion + format: C + +Flow-insensitive invariants as location invariants. + + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) + [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) + [Warning][Deadcode] Function 'dispose' has dead code: + on line 53 (04-priv_multi.c:53-53) + on line 56 (04-priv_multi.c:56-56) + [Warning][Deadcode] Function 'process' has dead code: + on line 37 (04-priv_multi.c:37-37) + on line 40 (04-priv_multi.c:40-40) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 40 + dead: 4 + total lines: 44 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:25:10-25:11) + [Warning][Deadcode][CWE-571] condition 'A > 0' is always true (04-priv_multi.c:27:9-27:14) + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) + [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) + [Info][Witness] witness generation summary: + total generation entries: 25 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml > witness.location.yml + +Location invariant at `for` loop in `main` should be on column 3, not 7. + + $ diff witness.flow_insensitive.yml witness.location.yml + 133,134c133,140 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 67 + > column: 7 + > function: main + > location_invariant: + 138,139c144,151 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 67 + > column: 7 + > function: main + > location_invariant: + 143,144c155,228 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 67 + > column: 7 + > function: main + > location_invariant: + > string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 65 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 65 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_A_locked || A == 5)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 65 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 64 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 64 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_A_locked || A == 5)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 64 + > column: 3 + > function: main + > location_invariant: + [1] From 10dfba1437956105d7a5a91c3f3bf410ebbc9b36 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:29:53 +0300 Subject: [PATCH 130/689] Fix witness.invariant.flow_insensitive-as-location at loop node --- src/witness/yamlWitness.ml | 18 ++++++++++-------- tests/regression/13-privatized/04-priv_multi.t | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 49fe889c22..b7bf11a31c 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -342,14 +342,16 @@ struct let invs = WitnessUtil.InvariantExp.process_exp inv in Queries.NS.fold (fun n acc -> let fundec = Node.find_fundec n in - let loc = Node.location n in - let location_function = fundec.svar.vname in - let location = Entry.location ~location:loc ~location_function in - List.fold_left (fun acc inv -> - let invariant = Entry.invariant (CilType.Exp.show inv) in - let entry = Entry.location_invariant ~task ~location ~invariant in - entry :: acc - ) acc invs + match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + | Some loc -> + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + let invariant = Entry.invariant (CilType.Exp.show inv) in + let entry = Entry.location_invariant ~task ~location ~invariant in + entry :: acc + ) acc invs + | None -> acc ) ns acc | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index 9bdf8ac5a7..952696a5c4 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -213,7 +213,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > file_name: 04-priv_multi.c > file_hash: $FILE_HASH > line: 67 - > column: 7 + > column: 3 > function: main > location_invariant: 138,139c144,151 @@ -225,7 +225,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > file_name: 04-priv_multi.c > file_hash: $FILE_HASH > line: 67 - > column: 7 + > column: 3 > function: main > location_invariant: 143,144c155,228 @@ -237,7 +237,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > file_name: 04-priv_multi.c > file_hash: $FILE_HASH > line: 67 - > column: 7 + > column: 3 > function: main > location_invariant: > string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' From cdd0dbd068e1e5206258cbac23507ea157b63c72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 12:41:13 +0300 Subject: [PATCH 131/689] Restore NULL mutex unlock warning --- src/analyses/mutexAnalysis.ml | 11 ++++++++--- tests/regression/06-symbeq/21-mult_accs_rc.t | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 4e369d0de2..a624b557c5 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -134,9 +134,14 @@ struct | None -> ctx.local let remove' ctx ~warn (addr: Addr.t): D.t = - match Addr.to_mval addr with - | None -> ctx.local - | Some mv -> + match addr with + | StrPtr _ + | UnknownPtr -> ctx.local + | NullPtr -> + if warn then + M.warn "unlocking NULL mutex"; + ctx.local + | Addr mv -> let (s, m) = ctx.local in if warn && not (MustLocksetRW.mem_mval mv s) then M.warn "unlocking mutex (%a) which may not be held" Mval.pretty mv; diff --git a/tests/regression/06-symbeq/21-mult_accs_rc.t b/tests/regression/06-symbeq/21-mult_accs_rc.t index 711205e38c..f32ca24131 100644 --- a/tests/regression/06-symbeq/21-mult_accs_rc.t +++ b/tests/regression/06-symbeq/21-mult_accs_rc.t @@ -10,6 +10,7 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Race] Memory location (struct s).data (race with conf. 100): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) + [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:13:3-13:14) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:15:3-15:14) @@ -25,6 +26,7 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) [Success][Race] Memory location (struct s).data (safe): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:13:3-13:14) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:15:3-15:14) From eb00ed5df60945f77826b720a582559ae68d3d65 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 12:46:07 +0300 Subject: [PATCH 132/689] Add NULL mutex lock warning --- src/analyses/mutexAnalysis.ml | 10 +++++++--- tests/regression/06-symbeq/21-mult_accs_rc.t | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index a624b557c5..bcf66b7973 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -120,8 +120,8 @@ struct end let add ctx ((addr, rw): AddrRW.t): D.t = - match Addr.to_mval addr with - | Some mv -> + match addr with + | Addr mv -> let (s, m) = ctx.local in let s' = MustLocksetRW.add_mval_rw (mv, rw) s in let m' = @@ -131,7 +131,11 @@ struct m in (s', m') - | None -> ctx.local + | NullPtr -> + M.warn "locking NULL mutex"; + ctx.local + | StrPtr _ + | UnknownPtr -> ctx.local let remove' ctx ~warn (addr: Addr.t): D.t = match addr with diff --git a/tests/regression/06-symbeq/21-mult_accs_rc.t b/tests/regression/06-symbeq/21-mult_accs_rc.t index f32ca24131..ca2e219b05 100644 --- a/tests/regression/06-symbeq/21-mult_accs_rc.t +++ b/tests/regression/06-symbeq/21-mult_accs_rc.t @@ -10,6 +10,9 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Race] Memory location (struct s).data (race with conf. 100): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) + [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:14:3-14:32) + [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:17:3-17:32) + [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:33:3-33:24) [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:13:3-13:14) @@ -26,6 +29,9 @@ Disable info messages because race summary contains (safe) memory location count [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) [Success][Race] Memory location (struct s).data (safe): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) + [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:14:3-14:32) + [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:17:3-17:32) + [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:33:3-33:24) [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) [Error][Imprecise][Unsound] Function definition missing for get_s (21-mult_accs_rc.c:13:3-13:14) From 16c97fde01a00b5ae8892bc8de0dea5c1070e298 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 12:56:37 +0300 Subject: [PATCH 133/689] Add cram test for relational mutex-meet flow-insensitive invariants --- .../regression/36-apron/12-traces-min-rpb1.t | 98 +++++++++++++++++++ tests/regression/36-apron/dune | 3 + 2 files changed, 101 insertions(+) create mode 100644 tests/regression/36-apron/12-traces-min-rpb1.t diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t new file mode 100644 index 0000000000..13cefb9557 --- /dev/null +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -0,0 +1,98 @@ + $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) + [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 18 + dead: 0 + total lines: 18 + [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) + write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) + [Warning][Race] Memory location g (race with conf. 110): (12-traces-min-rpb1.c:7:5-7:10) + write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 2 + total memory locations: 2 + +TODO: emit g == h + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: A_locked + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_update + variable: A_locked + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 18 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: A_locked + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: A_locked + expression: "0" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + - entry_type: ghost_update + variable: A_locked + expression: "0" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: A_locked + expression: "0" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: A_locked + scope: global + type: int + initial: "0" diff --git a/tests/regression/36-apron/dune b/tests/regression/36-apron/dune index 099ec878b2..b14ebdfe64 100644 --- a/tests/regression/36-apron/dune +++ b/tests/regression/36-apron/dune @@ -8,3 +8,6 @@ (glob_files ??-*.c)) (locks /update_suite) (action (chdir ../../.. (run %{update_suite} group apron)))) + +(cram + (deps (glob_files *.c))) From 5650784effc4c077a7f7efed045c201f42b5748b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 13:04:36 +0300 Subject: [PATCH 134/689] Add InvariantGlobal interface to relational privatizations --- src/analyses/apron/relationAnalysis.apron.ml | 13 +++++++++++++ src/analyses/apron/relationPriv.apron.ml | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index f1ea72d0a1..ba5b90525c 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -634,6 +634,16 @@ struct ) |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none + let query_invariant_global ctx g = + (* TODO: option? *) + if ctx.ask (GhostVarAvailable Multithreaded) then ( + let var = WitnessGhost.to_varinfo Multithreaded in + let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) ctx.global g in + Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) + else + Invariant.none + let query ctx (type a) (q: a Queries.t): a Queries.result = let open Queries in let st = ctx.local in @@ -655,6 +665,9 @@ struct let vf' x = vf (Obj.repr x) in Priv.iter_sys_vars ctx.global vq vf' | Queries.Invariant context -> query_invariant ctx context + | Queries.InvariantGlobal g -> + let g: V.t = Obj.obj g in + query_invariant_global ctx g | _ -> Result.top q diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 66548c117c..f286287dbe 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -46,6 +46,9 @@ module type S = val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> relation_components_t -> relation_components_t val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for apron. *) + val invariant_global: Q.ask -> (V.t -> G.t) -> V.t -> Invariant.t + (** Returns flow-insensitive invariant for global unknown. *) + val invariant_vars: Q.ask -> (V.t -> G.t) -> relation_components_t -> varinfo list (** Returns global variables which are privatized. *) @@ -130,6 +133,7 @@ struct {rel = RD.top (); priv = startstate ()} let iter_sys_vars getg vq vf = () + let invariant_global ask getg g = Invariant.none let invariant_vars ask getg st = [] let init () = () @@ -410,6 +414,7 @@ struct {rel = getg (); priv = startstate ()} let iter_sys_vars getg vq vf = () (* TODO: or report singleton global for any Global query? *) + let invariant_global ask getg g = Invariant.none let invariant_vars ask getg st = protected_vars ask (* TODO: is this right? *) let finalize () = () @@ -684,6 +689,8 @@ struct let init () = () let finalize () = () + + let invariant_global ask getg g = Invariant.none (* TODO: implement *) end (** May written variables. *) @@ -1242,6 +1249,8 @@ struct | _ -> () let finalize () = () + + let invariant_global ask getg g = Invariant.none end module TracingPriv = functor (Priv: S) -> functor (RD: RelationDomain.RD) -> From d3565cb8a7903e8604ba89df0867aba8813e4f53 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 13:42:58 +0300 Subject: [PATCH 135/689] Implement relational mutex-meet flow-insensitive invariants --- src/analyses/apron/relationPriv.apron.ml | 19 ++++++++++++++++++- .../regression/36-apron/12-traces-min-rpb1.t | 12 ++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index f286287dbe..a75e2ef113 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -690,7 +690,24 @@ struct let init () = () let finalize () = () - let invariant_global ask getg g = Invariant.none (* TODO: implement *) + let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function + | `Left m' as m -> (* mutex *) + if ask.f (GhostVarAvailable (Locked m')) then ( + let cpa = getg m in + let inv = + RD.invariant cpa + (* TODO: filters like query_invariant? *) + |> List.filter_map RD.cil_exp_of_lincons1 + |> List.fold_left (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none + (* TODO: need to filter for MustBeProtectedBy like base mutex-meet? *) + in + let var = WitnessGhost.to_varinfo (Locked m') in + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) + else + Invariant.none + | g -> (* global *) + Invariant.none (* TODO: ? *) end (** May written variables. *) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 13cefb9557..e05840429b 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,4 +1,4 @@ - $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c + $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) @@ -13,15 +13,13 @@ write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 10 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 unsafe: 2 total memory locations: 2 -TODO: emit g == h - $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded @@ -96,3 +94,9 @@ TODO: emit g == h scope: global type: int initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (A_locked || ((0LL - (long long )g) + (long long )h + >= 0LL && (long long )g - (long long )h >= 0LL))' + type: assertion + format: C From 1aa35d85b74c24e14c471b7d174dc441cccdbd72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 14:46:48 +0300 Subject: [PATCH 136/689] Filter relational mutex-meet ghost invariant with keep_only_protected_globals lock does it too, so let's be safe. --- src/analyses/apron/relationPriv.apron.ml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index a75e2ef113..b73319b4df 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -693,13 +693,12 @@ struct let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function | `Left m' as m -> (* mutex *) if ask.f (GhostVarAvailable (Locked m')) then ( - let cpa = getg m in + let rel = keep_only_protected_globals ask m' (getg m) in let inv = - RD.invariant cpa + RD.invariant rel (* TODO: filters like query_invariant? *) |> List.filter_map RD.cil_exp_of_lincons1 |> List.fold_left (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none - (* TODO: need to filter for MustBeProtectedBy like base mutex-meet? *) in let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) From c4a8936a2bd36d88cdc2909872aa6e6634098653 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 14:53:57 +0300 Subject: [PATCH 137/689] Add filters to relational InvariantGlobal --- src/analyses/apron/relationAnalysis.apron.ml | 3 +-- src/analyses/apron/relationPriv.apron.ml | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index ba5b90525c..397301b7bc 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -635,8 +635,7 @@ struct |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none let query_invariant_global ctx g = - (* TODO: option? *) - if ctx.ask (GhostVarAvailable Multithreaded) then ( + if GobConfig.get_bool "ana.relation.invariant.global" && ctx.ask (GhostVarAvailable Multithreaded) then ( let var = WitnessGhost.to_varinfo Multithreaded in let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) ctx.global g in Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index b73319b4df..dcb3b166c3 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -693,12 +693,24 @@ struct let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function | `Left m' as m -> (* mutex *) if ask.f (GhostVarAvailable (Locked m')) then ( + (* filters like query_invariant *) + let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in + let exact = GobConfig.get_bool "witness.invariant.exact" in + let rel = keep_only_protected_globals ask m' (getg m) in let inv = RD.invariant rel - (* TODO: filters like query_invariant? *) - |> List.filter_map RD.cil_exp_of_lincons1 - |> List.fold_left (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none + |> List.enum + |> Enum.filter_map (fun (lincons1: Apron.Lincons1.t) -> + (* filter one-vars and exact *) + (* TODO: exact filtering doesn't really work with octagon because it returns two SUPEQ constraints instead *) + if (one_var || GobApron.Lincons1.num_vars lincons1 >= 2) && (exact || Apron.Lincons1.get_typ lincons1 <> EQ) then + RD.cil_exp_of_lincons1 lincons1 + |> Option.filter (fun exp -> not (InvariantCil.exp_contains_tmp exp)) + else + None + ) + |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none in let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) From 5739ee1322f0c6912283303f834c159afceed1a0 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 7 May 2024 13:50:27 +0300 Subject: [PATCH 138/689] Convert all remaining libfuns to new format --- src/util/library/libraryFunctions.ml | 163 +++++++++++++++------------ 1 file changed, 94 insertions(+), 69 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 53bf804b1d..edf647c006 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -63,6 +63,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("localeconv", unknown ~attrs:[ThreadUnsafe] []); ("localtime", unknown ~attrs:[ThreadUnsafe] [drop "time" [r]]); ("strlen", special [__ "s" [r]] @@ fun s -> Strlen s); + ("_strlen", special [__ "s" [r]] @@ fun s -> Strlen s); ("__builtin_strlen", special [__ "s" [r]] @@ fun s -> Strlen s); ("strstr", special [__ "haystack" [r]; __ "needle" [r]] @@ fun haystack needle -> Strstr { haystack; needle; }); ("strcmp", special [__ "s1" [r]; __ "s2" [r]] @@ fun s1 s2 -> Strcmp { s1; s2; n = None; }); @@ -108,7 +109,9 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("strtoul", unknown [drop "nptr" [r]; drop "endptr" [w]; drop "base" []]); ("strtoull", unknown [drop "nptr" [r]; drop "endptr" [w]; drop "base" []]); ("tolower", unknown [drop "ch" []]); + ("__tolower", unknown [drop "ch" []]); ("toupper", unknown [drop "ch" []]); + ("__toupper", unknown [drop "ch" []]); ("time", unknown [drop "arg" [w]]); ("tmpnam", unknown ~attrs:[ThreadUnsafe] [drop "filename" [w]]); ("vprintf", unknown [drop "format" [r]; drop "vlist" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) @@ -117,6 +120,8 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("asprintf", unknown (drop "strp" [w] :: drop "format" [r] :: VarArgs (drop' [r_deep]))); (* TODO: glibc section? *) ("vasprintf", unknown [drop "strp" [w]; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) ("vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) + ("__builtin_vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); + ("__builtin___vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: does this actually exist?! *) ("mktime", unknown [drop "tm" [r;w]]); ("ctime", unknown ~attrs:[ThreadUnsafe] [drop "rm" [r]]); ("clearerr", unknown [drop "stream" [w]]); (* TODO: why only w? *) @@ -163,6 +168,13 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("raise", unknown [drop "sig" []]); (* safe-ish, we don't handle signal handlers for now *) ("timespec_get", unknown [drop "ts" [w]; drop "base" []]); ("signal", unknown [drop "signum" []; drop "handler" [s]]); + ("va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); + ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); + ("va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); + ("__builtin_va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); + ("va_end", unknown [drop "ap" [r_deep]]); + ("__builtin_va_end", unknown [drop "ap" [r_deep]]); + ("__builtin_va_arg_pack_len", unknown []); ] [@@coverage off] @@ -312,6 +324,7 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("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]]); + ("__strdup", unknown [drop "s" [r]]); ("strndup", unknown [drop "s" [r]; drop "n" []]); ("__strndup", unknown [drop "s" [r]; drop "n" []]); ("syscall", unknown (drop "number" [] :: VarArgs (drop' [r; w]))); @@ -433,6 +446,11 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("times", unknown [drop "buf" [w]]); ("mmap", unknown [drop "addr" []; drop "length" []; drop "prot" []; drop "flags" []; drop "fd" []; drop "offset" []]); ("munmap", unknown [drop "addr" []; drop "length" []]); + ("getline", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "stream" [r_deep; w_deep]]); + ("getwline", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "stream" [r_deep; w_deep]]); + ("getdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "delimiter" [];drop "stream" [r_deep; w_deep]]); + ("__getdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "delimiter" [];drop "stream" [r_deep; w_deep]]); + ("getwdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "delimiter" [];drop "stream" [r_deep; w_deep]]); ] [@@coverage off] @@ -540,6 +558,13 @@ let gcc_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__assert", special [drop "assertion" [r]; drop "file" [r]; drop "line" []] @@ Abort); (* header says: The following is not at all used here but needed for standard compliance. *) ("__builtin_return_address", unknown [drop "level" []]); ("__builtin___sprintf_chk", unknown (drop "s" [w] :: drop "flag" [] :: drop "os" [] :: drop "fmt" [r] :: VarArgs (drop' [r]))); + ("__builtin___snprintf_chk", unknown [drop "s" [w]; drop "maxlen" []; drop "flag" []; drop "os" []]); + ("__builtin___vsprintf_chk", unknown [drop "s" [w]; drop "flag" []; drop "os" []; drop "fmt" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) + ("__builtin___vsnprintf_chk", unknown [drop "s" [w]; drop "maxlen" []; drop "flag" []; drop "os" []; drop "fmt" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) + ("__builtin___printf_chk", unknown (drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); + ("__builtin___vprintf_chk", unknown [drop "flag" []; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) + ("__builtin___fprintf_chk", unknown (drop "stream" [r_deep; w_deep] :: drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); + ("__builtin___vfprintf_chk", unknown [drop "stream" [r_deep; w_deep]; drop "flag" []; drop "format" [r]; drop "ap" [r_deep]]); ("__builtin_add_overflow", unknown [drop "a" []; drop "b" []; drop "c" [w]]); ("__builtin_sadd_overflow", unknown [drop "a" []; drop "b" []; drop "c" [w]]); ("__builtin_saddl_overflow", unknown [drop "a" []; drop "b" []; drop "c" [w]]); @@ -624,7 +649,9 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__readlink_chk", unknown [drop "path" [r]; drop "buf" [w]; drop "len" []; drop "buflen" []]); ("__readlink_alias", unknown [drop "path" [r]; drop "buf" [w]; drop "len" []]); ("__overflow", unknown [drop "f" [r]; drop "ch" []]); + ("__ctype_b_loc", unknown []); ("__ctype_get_mb_cur_max", unknown []); + ("__maskrune", unknown [drop "c" [w]; drop "f" []]); ("__xmknod", unknown [drop "ver" []; drop "path" [r]; drop "mode" []; drop "dev" [r; w]]); ("yp_get_default_domain", unknown [drop "outdomain" [w]]); ("__nss_configure_lookup", unknown [drop "db" [r]; drop "service_line" [r]]); @@ -657,6 +684,19 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("getdtablesize", unknown []); ("daemon", unknown [drop "nochdir" []; drop "noclose" []]); ("putw", unknown [drop "w" []; drop "stream" [r_deep; w_deep]]); + (* RPC library start *) + ("clntudp_create", unknown [drop "addr" [r]; drop "prognum" []; drop "versnum" []; drop "wait" [r]; drop "sockp" [w]]); + ("clntudp_bufcreate", unknown [drop "addr" [r]; drop "prognum" []; drop "versnum" []; drop "wait" [r]; drop "sockp" [w]; drop "sendsize" []; drop "recosize" []]); + ("svctcp_create", unknown [drop "sock" []; drop "send_buf_size" []; drop "recv_buf_size" []]); + ("authunix_create_default", unknown []); + ("clnt_broadcast", unknown [drop "prognum" []; drop "versnum" []; drop "procnum" []; drop "inproc" [r]; drop "in" [w]; drop "outproc" [r]; drop "out" [w]; drop "eachresult" []]); + ("clnt_sperrno", unknown [drop "stat" []]); + ("pmap_unset", unknown [drop "prognum" []; drop "versnum" []]); + ("svcudp_create", unknown [drop "sock" []]); + ("svc_register", unknown [drop "xprt" [r;w]; drop "prognum" []; drop "versnum" []; drop "dispatch" [r;w]; drop "protocol" []]); + ("svc_run", unknown []); + (* RPC library end *) + ("scandir", unknown [drop "dirp" [r]; drop "namelist" [w_deep]; drop "filter" [r]; drop "compar" [r]]); ] [@@coverage off] @@ -669,7 +709,14 @@ let linux_userspace_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("epoll_create", unknown [drop "size" []]); ("epoll_ctl", unknown [drop "epfd" []; drop "op" []; drop "fd" []; drop "event" [w]]); ("epoll_wait", unknown [drop "epfd" []; drop "events" [w]; drop "maxevents" []; drop "timeout" []]); + ("__error", unknown []); + ("__errno", unknown []); + ("__errno_location", unknown []); + ("__h_errno_location", unknown []); + ("printk", unknown (drop "fmt" [r] :: VarArgs (drop' [r]))); + ("__printf_chk", unknown [drop "flag" []; drop "format" [r]]); ("__fprintf_chk", unknown (drop "stream" [r_deep; w_deep] :: drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); + ("__vfprintf_chk", unknown [drop "stream" [r_deep; w_deep]; drop "flag" []; drop "format" [r]; drop "ap" [r_deep]]); ("sysinfo", unknown [drop "info" [w_deep]]); ("__xpg_basename", unknown [drop "path" [r]]); ("ptrace", unknown (drop "request" [] :: VarArgs (drop' [r_deep; w_deep]))); (* man page has 4 arguments, but header has varargs and real-world programs may call with <4 *) @@ -691,6 +738,11 @@ let linux_userspace_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("process_vm_readv", unknown [drop "pid" []; drop "local_iov" [w_deep]; drop "liovcnt" []; drop "remote_iov" []; drop "riovcnt" []; drop "flags" []]); ("__libc_current_sigrtmax", unknown []); ("__libc_current_sigrtmin", unknown []); + ("__xstat", unknown [drop "ver" []; drop "path" [r]; drop "stat_buf" [w]]); + ("__lxstat", unknown [drop "ver" []; drop "path" [r]; drop "stat_buf" [w]]); + ("__fxstat", unknown [drop "ver" []; drop "fildes" []; drop "stat_buf" [w]]); + ("kmem_cache_create", unknown [drop "name" [r]; drop "size" []; drop "align" []; drop "flags" []; drop "ctor" [r]]); + ("usb_submit_urb", unknown [drop "urb" [r]; drop "mem_flags" []]); (* first argument is written to but according to specification must not be read from anymore *) ] [@@coverage off] @@ -706,11 +758,13 @@ let linux_kernel_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("up_read", special [__ "sem" []] @@ fun sem -> Unlock sem); ("up_write", special [__ "sem" []] @@ fun sem -> Unlock sem); ("mutex_init", unknown [drop "mutex" []]); + ("__mutex_init", unknown [drop "lock" [r]; drop "name" [r]; drop "key" [r]]); ("mutex_lock", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); ("mutex_trylock", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = true; write = true; return_on_success = true }); ("mutex_lock_interruptible", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); ("mutex_unlock", special [__ "lock" []] @@ fun lock -> Unlock lock); ("spin_lock_init", unknown [drop "lock" []]); + ("__spin_lock_init", unknown [drop "lock" []]); ("spin_lock", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); ("_spin_lock", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); ("_spin_lock_bh", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); @@ -770,6 +824,7 @@ let goblint_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__goblint_split_begin", unknown [drop "exp" []]); ("__goblint_split_end", unknown [drop "exp" []]); ("__goblint_bounded", special [__ "exp"[]] @@ fun exp -> Bounded { exp }); + ("__goblint_assume_join", unknown [drop "tid" []]); ] [@@coverage off] @@ -1045,6 +1100,11 @@ let klever_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("rtnl_lock", special [] @@ Lock { lock = rtnl_lock; try_ = false; write = true; return_on_success = true }); ("rtnl_unlock", special [] @@ Unlock rtnl_lock); ("__rtnl_unlock", special [] @@ Unlock rtnl_lock); + (* ldv-benchmarks *) + (* ddverify *) + ("sema_init", unknown [drop "sem" [r]; drop "val" []]); + ("idr_pre_get", unknown [drop "idp" [r]; drop "gfp_mask" []]); + ("dev_driver_string", unknown [drop "dev" [r]]); ] [@@coverage off] @@ -1127,6 +1187,38 @@ let liblzma_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ] [@@coverage off] +let legacy_libs_misc_list: (string * LibraryDesc.t) list = LibraryDsl.[ + (* TODO: was "zil_replay", writes [1;2;3;5]; but couldn't find anything with 5/6 arguments, also not in bench *) + ("zil_replay", unknown [drop "os" [w]; drop "arg" [w]; drop "replay_func" [r]]); + ("_IO_getc", unknown [drop "f" [r_deep; w_deep]]); + ("__open_alias", unknown (drop "path" [r] :: drop "oflag" [] :: VarArgs (drop' [r]))); + ("__open_2", unknown [drop "file" [r]; drop "oflag" []]); + ("__open_too_many_args", unknown []); + (* bzlib *) + ("BZ2_bzBuffToBuffCompress", unknown [drop "dest" []; drop "destLen" []; drop "source" [w]; drop "sourceLen" []; drop "blockSize100k" []; drop "verbosity" []; drop "workFactor" []]); + ("BZ2_bzBuffToBuffDecompress", unknown [drop "dest" []; drop "destLen" []; drop "source" [w]; drop "sourceLen" []; drop "small" []; drop "verbosity" []]); + (* zlib (Zebedee) *) + ("uncompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []]); + ("compress2", unknown [drop "dest" [r]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "level" []]); + (* opensssl blowfish *) + ("BF_cfb64_encrypt", unknown [drop "in" [r]; drop "out" [w]; drop "length" []; drop "schedule" [r]; drop "ivec" [w]; drop "num" [w]; drop "enc" [r]]); + ("BF_set_key", unknown [drop "key" [w]; drop "len" []; drop "data" [r]]); + (* libintl *) + ("textdomain", unknown [drop "domainname" [r]]); + ("bindtextdomain", unknown [drop "domainname" [r]; drop "dirname" [r]]); + ("dcgettext", unknown [drop "domainname" [r]; drop "msgid" [r]; drop "category" []]); + (* TODO: the __extinline suffix was added by CIL in the old times in some cases, but is now switched off for like 10 years *) + ("strtoul__extinline", unknown [drop "nptr" [r]; drop "endptr" [w]; drop "base" []]); + ("atoi__extinline", unknown [drop "nptr" [r]]); + ("stat__extinline", unknown [drop "pathname" [r]; drop "statbuf" [w]]); + ("lstat__extinline", unknown [drop "pathname" [r]; drop "statbuf" [w]]); + ("fstat__extinline", unknown [drop "fd" []; drop "buf" [w]]); + (* only in knot *) + ("PL_NewHashTable", unknown [drop "n" []; drop "keyHash" [r]; drop "keyCompare" [r]; drop "valueCompare" [r]; drop "allocOps" [r]; drop "allocPriv" [r]]); (* TODO: should have call instead of read *) + ("assert_failed", unknown [drop "file" [r]; drop "line" []; drop "func" [r]; drop "exp" [r]]); + ] +[@@coverage off] + let libraries = Hashtbl.of_list [ ("c", c_descs_list @ math_descs_list); ("posix", posix_descs_list); @@ -1143,6 +1235,7 @@ let libraries = Hashtbl.of_list [ ("pcre", pcre_descs_list); ("zlib", zlib_descs_list); ("liblzma", liblzma_descs_list); + ("legacy", legacy_libs_misc_list); ] let libraries = @@ -1282,75 +1375,7 @@ open Invalidate (* Data races: which arguments are read/written? * 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 = [ - "__printf_chk", readsAll;(*safe*) - "printk", readsAll;(*safe*) - "__mutex_init", readsAll;(*safe*) - "__builtin___snprintf_chk", writes [1];(*keep [1]*) - "__vfprintf_chk", writes [1];(*keep [1]*) - "__builtin_va_arg", readsAll;(*safe*) - "__builtin_va_end", readsAll;(*safe*) - "__builtin_va_start", readsAll;(*safe*) - "__ctype_b_loc", readsAll;(*safe*) - "__errno", readsAll;(*safe*) - "__errno_location", readsAll;(*safe*) - "__strdup", readsAll;(*safe*) - "strtoul__extinline", readsAll;(*safe*) - "atoi__extinline", readsAll;(*safe*) - "_IO_getc", writesAll;(*unsafe*) - "_strlen", readsAll;(*safe*) - "stat__extinline", writesAllButFirst 1 readsAll;(*drop 1*) - "lstat__extinline", writesAllButFirst 1 readsAll;(*drop 1*) - "__open_alias", readsAll;(*safe*) - "__open_2", readsAll;(*safe*) - "fstat__extinline", writesAll;(*unsafe*) - "scandir", writes [1;3;4];(*keep [1;3;4]*) - "bindtextdomain", readsAll;(*safe*) - "textdomain", readsAll;(*safe*) - "dcgettext", readsAll;(*safe*) - "__getdelim", writes [3];(*keep [3]*) - "__h_errno_location", readsAll;(*safe*) - "__fxstat", readsAll;(*safe*) - (* RPC library start *) - "clntudp_create", writesAllButFirst 3 readsAll;(*drop 3*) - "svctcp_create", readsAll;(*safe*) - "clntudp_bufcreate", writesAll;(*unsafe*) - "authunix_create_default", readsAll;(*safe*) - "clnt_broadcast", writesAll;(*unsafe*) - "clnt_sperrno", readsAll;(*safe*) - "pmap_unset", writesAll;(*unsafe*) - "svcudp_create", readsAll;(*safe*) - "svc_register", writesAll;(*unsafe*) - "svc_run", writesAll;(*unsafe*) - (* RPC library end *) - "__builtin___vsnprintf", writesAllButFirst 3 readsAll; (*drop 3*) - "__builtin___vsnprintf_chk", writesAllButFirst 3 readsAll; (*drop 3*) - "__error", readsAll; (*safe*) - "__maskrune", writesAll; (*unsafe*) - "__tolower", 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]*) - "__xstat", writes [3]; (*keep [1]*) - "__lxstat", writes [3]; (*keep [1]*) - "BZ2_bzBuffToBuffCompress", writes [3;4]; (*keep [3;4]*) - "compress2", writes [3]; (*keep [3]*) - "__toupper", readsAll; (*safe*) - "BF_set_key", writes [3]; (*keep [3]*) - "PL_NewHashTable", readsAll; (*safe*) - "assert_failed", readsAll; (*safe*) - "__builtin_va_arg_pack_len", readsAll; - "__open_too_many_args", readsAll; - "usb_submit_urb", readsAll; (* first argument is written to but according to specification must not be read from anymore *) - "dev_driver_string", readsAll; - "__spin_lock_init", writes [1]; - "kmem_cache_create", readsAll; - "idr_pre_get", readsAll; - "zil_replay", writes [1;2;3;5]; - (* ddverify *) - "sema_init", readsAll; - "__goblint_assume_join", readsAll; -] +let invalidate_actions = [] let invalidate_actions = let tbl = Hashtbl.create 113 in From 535de765401c7a865c5c44be6b06f4aff85a7b65 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 7 May 2024 15:52:17 +0300 Subject: [PATCH 139/689] Add test with __VERIFIER_atomic_locked ghost variable --- tests/regression/29-svcomp/16-atomic_priv.t | 92 +++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 15425f68dd..d3826d8de3 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -81,3 +81,95 @@ string: '! multithreaded || myglobal == 5' type: assertion format: C + +Non-atomic privatization: + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) + [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) + [Warning][Assert] Assertion "myglobal == 5" is unknown. (16-atomic_priv.c:24:3-24:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:26:3-26:33) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 17 + dead: 0 + total lines: 17 + [Warning][Race] Memory location myglobal (race with conf. 110): (16-atomic_priv.c:8:5-8:17) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) + read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 1 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: __VERIFIER_atomic_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((0 <= myglobal && myglobal <= 127) && myglobal != + 0)' + type: assertion + format: C From 6f3b6fbc6ab0e18560f6cbf5a409b46a6055022d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 7 May 2024 16:13:16 +0300 Subject: [PATCH 140/689] Treat __VERIFIER_atomic_locked as false in witnesses Others cannot observe anything else anyway. But in the atomic section could?! --- src/analyses/apron/relationPriv.apron.ml | 11 ++- src/analyses/basePriv.ml | 15 +++- src/analyses/mutexGhosts.ml | 5 +- src/witness/witnessGhostVar.ml | 2 +- tests/regression/29-svcomp/16-atomic_priv.t | 88 +-------------------- 5 files changed, 26 insertions(+), 95 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index dcb3b166c3..f14700f437 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -692,7 +692,8 @@ struct let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function | `Left m' as m -> (* mutex *) - if ask.f (GhostVarAvailable (Locked m')) then ( + let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in + if atomic || ask.f (GhostVarAvailable (Locked m')) then ( (* filters like query_invariant *) let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in let exact = GobConfig.get_bool "witness.invariant.exact" in @@ -712,8 +713,12 @@ struct ) |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none in - let var = WitnessGhost.to_varinfo (Locked m') in - Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if atomic then + inv + else ( + let var = WitnessGhost.to_varinfo (Locked m') in + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) ) else Invariant.none diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 799290c4fe..af88cfb742 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -333,7 +333,8 @@ struct let invariant_global (ask: Q.ask) getg = function | `Left m' as m -> (* mutex *) - if ask.f (GhostVarAvailable (Locked m')) then ( + let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in + if atomic || ask.f (GhostVarAvailable (Locked m')) then ( let cpa = getg m in let inv = CPA.fold (fun v _ acc -> if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then @@ -343,8 +344,12 @@ struct acc ) cpa Invariant.none in - let var = WitnessGhost.to_varinfo (Locked m') in - Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if atomic then + inv + else ( + let var = WitnessGhost.to_varinfo (Locked m') in + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) ) else Invariant.none @@ -864,7 +869,9 @@ struct else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> - if ask.f (GhostVarAvailable (Locked m)) then ( + if LockDomain.Addr.equal m (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) then + acc + else if ask.f (GhostVarAvailable (Locked m)) then ( let var = WitnessGhost.to_varinfo (Locked m) in Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 75195e4662..eaa15df8e6 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -59,8 +59,9 @@ struct end let event ctx e octx = + let verifier_atomic_addr = LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var in begin match e with - | Events.Lock (l, _) -> + | Events.Lock (l, _) when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); if !AnalysisState.postsolving then ( let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in @@ -70,7 +71,7 @@ struct ) locked ); ) - | Events.Unlock l -> + | Events.Unlock l when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); if !AnalysisState.postsolving then ( let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index cec61b0e2d..7979d23173 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -9,7 +9,7 @@ let name_varinfo = function | Locked (Addr (v, os)) -> let name = if CilType.Varinfo.equal v LibraryFunctions.verifier_atomic_var then - "__VERIFIER_atomic" + invalid_arg "__VERIFIER_atomic" else if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index d3826d8de3..b10265d4e8 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -13,7 +13,7 @@ write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 8 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -30,52 +30,11 @@ line: 23 column: 3 function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 27 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: __VERIFIER_atomic_locked - scope: global - type: int - initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || myglobal == 5' @@ -99,7 +58,7 @@ Non-atomic privatization: write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -116,55 +75,14 @@ Non-atomic privatization: line: 23 column: 3 function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 27 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: __VERIFIER_atomic_locked - scope: global - type: int - initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' + string: '! multithreaded || myglobal == 5' type: assertion format: C - entry_type: flow_insensitive_invariant From 2e6673f72e1e3df8c67b9c0c21aec9f45e1c4ab2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 8 May 2024 11:41:45 +0300 Subject: [PATCH 141/689] Disable 13-privatized/04-priv_multi cram test on OSX OSX has its own weird diff. --- tests/regression/13-privatized/dune | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/regression/13-privatized/dune b/tests/regression/13-privatized/dune index 23c0dd3290..9227128b15 100644 --- a/tests/regression/13-privatized/dune +++ b/tests/regression/13-privatized/dune @@ -1,2 +1,6 @@ (cram (deps (glob_files *.c))) + +(cram + (applies_to 04-priv_multi) + (enabled_if (<> %{system} macosx))) From 05da8b83ee33422f1deb7ed22466fb8b0e1a4adc Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 8 May 2024 12:08:54 +0300 Subject: [PATCH 142/689] Fix `va_arg` and `va_start` libfun defs according to CIL special cases --- src/util/library/libraryFunctions.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 14a04d9518..4db6c32abb 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -169,9 +169,9 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("timespec_get", unknown [drop "ts" [w]; drop "base" []]); ("signal", unknown [drop "signum" []; drop "handler" [s]]); ("va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); - ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); + ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []; drop "lhs" []]); (* cil: "__builtin_va_arg is special: in CIL, the left hand side is stored as the last argument" *) ("va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); - ("__builtin_va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); + ("__builtin_va_start", unknown [drop "ap" [r_deep]]); (* cil: "When we parse builtin_{va,stdarg}_start, we drop the second argument" *) ("va_end", unknown [drop "ap" [r_deep]]); ("__builtin_va_end", unknown [drop "ap" [r_deep]]); ("__builtin_va_arg_pack_len", unknown []); From b7582a4c5495e35a24974228785817b01711a37c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 8 May 2024 11:43:03 +0300 Subject: [PATCH 143/689] Make 36-apron/12-traces-min-rpb1 cram test warnings deterministic Needed for OSX CI to pass. --- .../regression/36-apron/12-traces-min-rpb1.t | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index e05840429b..7aca1dea0b 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,24 +1,24 @@ - $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box - [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) - [Info][Deadcode] Logical lines of code (LLoC) summary: - live: 18 - dead: 0 - total lines: 18 - [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) - write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) - read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) [Warning][Race] Memory location g (race with conf. 110): (12-traces-min-rpb1.c:7:5-7:10) write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) - [Info][Witness] witness generation summary: - total generation entries: 10 + [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) + write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 unsafe: 2 total memory locations: 2 + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 18 + dead: 0 + total lines: 18 + [Info][Witness] witness generation summary: + total generation entries: 10 $ yamlWitnessStrip < witness.yml - entry_type: ghost_update From e6d2f1ba258c55ee9f2fa0e4f4deb8d63b1c14b6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 9 May 2024 16:31:27 +0300 Subject: [PATCH 144/689] Add a test extracted from sv-comp task sqrt1-ll_unwindbound5.c Co-authored-by: Simmo Saan --- tests/regression/29-svcomp/35-nla-sqrt.c | 18 ++++++++++++++++++ tests/regression/29-svcomp/dune | 14 ++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/regression/29-svcomp/35-nla-sqrt.c diff --git a/tests/regression/29-svcomp/35-nla-sqrt.c b/tests/regression/29-svcomp/35-nla-sqrt.c new file mode 100644 index 0000000000..dc382181cc --- /dev/null +++ b/tests/regression/29-svcomp/35-nla-sqrt.c @@ -0,0 +1,18 @@ +// SKIP PARAM: --enable ana.sv-comp.functions --enable ana.autotune.enabled --set ana.autotune.activated[+] octagon +// Extracted from: nla-digbench-scaling/sqrt1-ll_unwindbound5.c +#include +extern int __VERIFIER_nondet_int(void); + +int main() { + int n; + long long s; + n = __VERIFIER_nondet_int(); + + if (!(s <= n)) { + __goblint_check(s > n); + } else { + __goblint_check(s <= 2147483647); + } + + return 0; +} diff --git a/tests/regression/29-svcomp/dune b/tests/regression/29-svcomp/dune index 23c0dd3290..2aede4e50b 100644 --- a/tests/regression/29-svcomp/dune +++ b/tests/regression/29-svcomp/dune @@ -1,2 +1,16 @@ +(rule + (aliases runtest runaprontest) + (enabled_if %{lib-available:apron}) + (deps + (package goblint) + ../../../goblint ; update_suite calls local goblint + (:update_suite ../../../scripts/update_suite.rb) + (glob_files ??-*.c)) + (locks /update_suite) + (action + (chdir ../../.. + (progn + (run %{update_suite} nla-sqrt -q))))) + (cram (deps (glob_files *.c))) From c3385b6804ea5cd094428b1ea1837db961858f78 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 9 May 2024 16:08:43 +0300 Subject: [PATCH 145/689] Handle comparison in LNot in octagon autotune --- src/autoTune.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index e4b03acf84..b5def761b5 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -337,6 +337,7 @@ let isGoblintStub v = List.exists (fun (Attr(s,_)) -> s = "goblint_stub") v.vatt let rec extractVar = function | UnOp (Neg, e, _) -> extractVar e | Lval ((Var info),_) when not (isGoblintStub info) -> Some info + | CastE (_, e) -> extractVar e | _ -> None let extractOctagonVars = function @@ -375,6 +376,15 @@ class octagonVariableVisitor(varMap, globals) = object DoChildren ) | Lval ((Var info),_) when not (isGoblintStub info) -> handle varMap 1 globals (Some (`Right info)) ; SkipChildren + | UnOp (LNot, BinOp (op, e1,e2, (TInt _)),_) when isComparison op -> (* TODO: Should be generalized *) + handle varMap 5 globals ( + match extractVar e1, extractVar e2 with + | Some a, Some b -> Some (`Left (a,b)) + | Some a, None + | None, Some a -> if isConstant e1 then Some (`Right a) else None + | _,_ -> None + ); + DoChildren (*Traverse down only operations fitting for linear equations*) | UnOp (Neg, _,_) | BinOp (PlusA,_,_,_) From d89935558e16f4a48762f60c1e37bde73804fdad Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 9 May 2024 16:10:16 +0300 Subject: [PATCH 146/689] Assert type bounds in relationAnalysis `combine_assign` --- src/analyses/apron/relationAnalysis.apron.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index fa220552f1..f1169c40fc 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -440,8 +440,10 @@ struct if RD.Tracked.type_tracked (Cilfacade.fundec_return_type f) then ( let unify_st' = match r with | Some lv -> - assign_to_global_wrapper (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg unify_st lv (fun st v -> - RD.assign_var st.rel (RV.local v) RV.return + let ask = Analyses.ask_of_ctx ctx in + assign_to_global_wrapper ask ctx.global ctx.sideg unify_st lv (fun st v -> + let rel = RD.assign_var st.rel (RV.local v) RV.return in + assert_type_bounds ask rel v (* TODO: should be done in return instead *) ) | None -> unify_st From 68e8fff09321573026c0f08efde245cfbc496725 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 14 May 2024 16:49:27 +0300 Subject: [PATCH 147/689] Add test 56-witness/54-witness-lifter-abortUnless (issue #1453) --- .../56-witness/54-witness-lifter-abortUnless.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/regression/56-witness/54-witness-lifter-abortUnless.c diff --git a/tests/regression/56-witness/54-witness-lifter-abortUnless.c b/tests/regression/56-witness/54-witness-lifter-abortUnless.c new file mode 100644 index 0000000000..2da7fae6b5 --- /dev/null +++ b/tests/regression/56-witness/54-witness-lifter-abortUnless.c @@ -0,0 +1,17 @@ +// PARAM: --set ana.activated[+] abortUnless --enable exp.arg +// NOCRASH +void printLine() +{ + +} + +void goodB2G1Sink(int data) +{ + printLine(); +} + +int main() +{ + goodB2G1Sink(0); + return 0; +} From 58fecfb36ca0581ee19b38f4ab97e483ad7cf808 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 14 May 2024 16:53:26 +0300 Subject: [PATCH 148/689] Fix witness enter sync map when caller state changes (closes #1453) --- src/witness/witnessConstraints.ml | 10 +++++++++- .../56-witness/54-witness-lifter-abortUnless.c | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index 4af9dd898d..acbe2c13a7 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -278,7 +278,15 @@ struct R.bot () in (* keep left syncs so combine gets them for no-inline case *) - ((Dom.singleton x (R.bot ()), snd ctx.local), (Dom.singleton y yr, Sync.bot ())) + (* must lookup and short-circuit because enter may modify first in pair (e.g. abortUnless) *) + let syncs = + match Sync.find x' (snd ctx.local) with + | syncs -> syncs + | exception Not_found -> + M.debug ~category:Witness ~tags:[Category Analyzer] "PathSensitive3 sync predecessor not found"; + SyncSet.bot () + in + ((Dom.singleton x (R.bot ()), Sync.singleton x syncs), (Dom.singleton y yr, Sync.bot ())) ) ys in ys' @ xs diff --git a/tests/regression/56-witness/54-witness-lifter-abortUnless.c b/tests/regression/56-witness/54-witness-lifter-abortUnless.c index 2da7fae6b5..9c83a8b8c2 100644 --- a/tests/regression/56-witness/54-witness-lifter-abortUnless.c +++ b/tests/regression/56-witness/54-witness-lifter-abortUnless.c @@ -1,5 +1,6 @@ // PARAM: --set ana.activated[+] abortUnless --enable exp.arg // NOCRASH + void printLine() { @@ -7,7 +8,12 @@ void printLine() void goodB2G1Sink(int data) { + // abortUnless=true (one int argument, nothing has ruined it yet) + // sync map: {[abortUnless=true, ...] -> {[abortUnless=true, ...]}} + // enter: (abortUnless=false, ...) (enter ruined it) + // left sync map must be updated to: {[abortUnless=false, ...] -> {[abortUnless=true, ...]}} printLine(); + // left sync map is looked up by abortUnless=false in combine_env } int main() From 9d24ee5bba6dab75b66f3ef328608d6c2150260d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 14 May 2024 17:49:09 +0300 Subject: [PATCH 149/689] Activate abortUnless in svcomp conf --- conf/svcomp.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/svcomp.json b/conf/svcomp.json index 7e30554ceb..467d294bdd 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -30,7 +30,8 @@ "symb_locks", "region", "thread", - "threadJoins" + "threadJoins", + "abortUnless" ], "path_sens": [ "mutex", From 252325bb7446722072d32b24314309d363b33168 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 15 May 2024 11:57:26 +0300 Subject: [PATCH 150/689] Separate (soundness) analyses activated for memSafety specifiactions --- src/autoTune.ml | 16 +--------------- src/autoTuneSvompSpec.ml | 27 +++++++++++++++++++++++++++ src/maingoblint.ml | 4 +++- 3 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 src/autoTuneSvompSpec.ml diff --git a/src/autoTune.ml b/src/autoTune.ml index e4b03acf84..07251f9118 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -214,26 +214,12 @@ let activateLongjmpAnalysesWhenRequired () = let focusOnMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with - | ValidFree -> (* Enable the useAfterFree analysis *) - let uafAna = ["useAfterFree"] in - Logs.info "Specification: ValidFree -> enabling useAfterFree analysis \"%s\"" (String.concat ", " uafAna); - enableAnalyses uafAna - | ValidDeref -> (* Enable the memOutOfBounds analysis *) - let memOobAna = ["memOutOfBounds"] in - set_bool "ana.arrayoob" true; - Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; - set_bool "cil.addNestedScopeAttr" true; - Logs.info "Specification: ValidDeref -> enabling memOutOfBounds analysis \"%s\"" (String.concat ", " memOobAna); - enableAnalyses memOobAna; | ValidMemtrack - | ValidMemcleanup -> (* Enable the memLeak analysis *) - let memLeakAna = ["memLeak"] in + | ValidMemcleanup -> if (get_int "ana.malloc.unique_address_count") < 1 then ( Logs.info "Setting \"ana.malloc.unique_address_count\" to 5"; set_int "ana.malloc.unique_address_count" 5; ); - Logs.info "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"%s\"" (String.concat ", " memLeakAna); - enableAnalyses memLeakAna | _ -> () let focusOnMemSafetySpecification () = diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml new file mode 100644 index 0000000000..5b44dcec0e --- /dev/null +++ b/src/autoTuneSvompSpec.ml @@ -0,0 +1,27 @@ +(** Autotuning of the activated analyses for soundness based on SV-COMP specification. *) + +open GobConfig +open AutoTune + +let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = + match spec with + | ValidFree -> (* Enable the useAfterFree analysis *) + let uafAna = ["useAfterFree"] in + Logs.info "Specification: ValidFree -> enabling useAfterFree analysis \"%s\"" (String.concat ", " uafAna); + enableAnalyses uafAna + | ValidDeref -> (* Enable the memOutOfBounds analysis *) + let memOobAna = ["memOutOfBounds"] in + set_bool "ana.arrayoob" true; + Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; + set_bool "cil.addNestedScopeAttr" true; + Logs.info "Specification: ValidDeref -> enabling memOutOfBounds analysis \"%s\"" (String.concat ", " memOobAna); + enableAnalyses memOobAna; + | ValidMemtrack + | ValidMemcleanup -> (* Enable the memLeak analysis *) + let memLeakAna = ["memLeak"] in + Logs.info "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"%s\"" (String.concat ", " memLeakAna); + enableAnalyses memLeakAna + | _ -> () + +let enableAnalysesForMemSafetySpecification () = + List.iter enableAnalysesForMemSafetySpecification (Svcomp.Specification.of_option ()) diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 10983c2b2b..0f90a163f4 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -201,7 +201,9 @@ let handle_options () = Logs.Level.current := Logs.Level.of_string (get_string "dbg.level"); check_arguments (); 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 "memsafetySpecification" && get_string "ana.specification" <> "" then + if get_string "ana.specification" <> "" then + AutoTuneSvompSpec.enableAnalysesForMemSafetySpecification (); + if AutoTune.isActivated "memsafetySpecification" then AutoTune.focusOnMemSafetySpecification (); AfterConfig.run (); Cilfacade.init_options (); From f4504b6ebd7823619cbccedadd4cf95f043f5e04 Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Wed, 15 May 2024 12:03:55 +0300 Subject: [PATCH 151/689] `w` for `lhs` in `__builtin_va_arg` Co-authored-by: Simmo Saan --- src/util/library/libraryFunctions.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 4db6c32abb..772cc07707 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -169,7 +169,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("timespec_get", unknown [drop "ts" [w]; drop "base" []]); ("signal", unknown [drop "signum" []; drop "handler" [s]]); ("va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); - ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []; drop "lhs" []]); (* cil: "__builtin_va_arg is special: in CIL, the left hand side is stored as the last argument" *) + ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []; drop "lhs" [w]]); (* cil: "__builtin_va_arg is special: in CIL, the left hand side is stored as the last argument" *) ("va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); ("__builtin_va_start", unknown [drop "ap" [r_deep]]); (* cil: "When we parse builtin_{va,stdarg}_start, we drop the second argument" *) ("va_end", unknown [drop "ap" [r_deep]]); From ab35510e231d2bbf214b522b048d603ca1976a83 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 15 May 2024 12:07:16 +0300 Subject: [PATCH 152/689] Move `__builtin_` prefixed functions from c standard lib to GCC builtins --- src/util/library/libraryFunctions.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 772cc07707..82da0fa69f 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -120,8 +120,6 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("asprintf", unknown (drop "strp" [w] :: drop "format" [r] :: VarArgs (drop' [r_deep]))); (* TODO: glibc section? *) ("vasprintf", unknown [drop "strp" [w]; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) ("vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) - ("__builtin_vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); - ("__builtin___vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: does this actually exist?! *) ("mktime", unknown [drop "tm" [r;w]]); ("ctime", unknown ~attrs:[ThreadUnsafe] [drop "rm" [r]]); ("clearerr", unknown [drop "stream" [w]]); (* TODO: why only w? *) @@ -169,12 +167,8 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("timespec_get", unknown [drop "ts" [w]; drop "base" []]); ("signal", unknown [drop "signum" []; drop "handler" [s]]); ("va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); - ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []; drop "lhs" [w]]); (* cil: "__builtin_va_arg is special: in CIL, the left hand side is stored as the last argument" *) ("va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); - ("__builtin_va_start", unknown [drop "ap" [r_deep]]); (* cil: "When we parse builtin_{va,stdarg}_start, we drop the second argument" *) ("va_end", unknown [drop "ap" [r_deep]]); - ("__builtin_va_end", unknown [drop "ap" [r_deep]]); - ("__builtin_va_arg_pack_len", unknown []); ] [@@coverage off] @@ -619,6 +613,12 @@ let gcc_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__builtin_va_copy", unknown [drop "dest" [w]; drop "src" [r]]); ("alloca", special [__ "size" []] @@ fun size -> Alloca size); ("__builtin_alloca", special [__ "size" []] @@ fun size -> Alloca size); + ("__builtin_vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); + ("__builtin___vsnprintf", unknown [drop "str" [w]; drop "size" []; drop "format" [r]; drop "ap" [r_deep]]); (* TODO: does this actually exist?! *) + ("__builtin_va_arg", unknown [drop "ap" [r_deep]; drop "T" []; drop "lhs" [w]]); (* cil: "__builtin_va_arg is special: in CIL, the left hand side is stored as the last argument" *) + ("__builtin_va_start", unknown [drop "ap" [r_deep]]); (* cil: "When we parse builtin_{va,stdarg}_start, we drop the second argument" *) + ("__builtin_va_end", unknown [drop "ap" [r_deep]]); + ("__builtin_va_arg_pack_len", unknown []); ] [@@coverage off] From 6c93ce61e979c57ac55633412204b95136e2588d Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Wed, 15 May 2024 12:12:59 +0300 Subject: [PATCH 153/689] :: for VarArgs instead ; Co-authored-by: Simmo Saan --- src/util/library/libraryFunctions.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 82da0fa69f..a83b917501 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -552,7 +552,7 @@ let gcc_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__assert", special [drop "assertion" [r]; drop "file" [r]; drop "line" []] @@ Abort); (* header says: The following is not at all used here but needed for standard compliance. *) ("__builtin_return_address", unknown [drop "level" []]); ("__builtin___sprintf_chk", unknown (drop "s" [w] :: drop "flag" [] :: drop "os" [] :: drop "fmt" [r] :: VarArgs (drop' [r]))); - ("__builtin___snprintf_chk", unknown [drop "s" [w]; drop "maxlen" []; drop "flag" []; drop "os" []]); + ("__builtin___snprintf_chk", unknown (drop "s" [w] :: drop "maxlen" [] :: drop "flag" [] :: drop "os" [] :: drop "fmt" [r] :: VarArgs (drop' [r]))); ("__builtin___vsprintf_chk", unknown [drop "s" [w]; drop "flag" []; drop "os" []; drop "fmt" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) ("__builtin___vsnprintf_chk", unknown [drop "s" [w]; drop "maxlen" []; drop "flag" []; drop "os" []; drop "fmt" [r]; drop "ap" [r_deep]]); (* TODO: what to do with a va_list type? is r_deep correct? *) ("__builtin___printf_chk", unknown (drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); From ef726e985cc47ae9f92022a5ad19c15bbf25da3c Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Wed, 15 May 2024 12:13:45 +0300 Subject: [PATCH 154/689] Add `w` for `n` in `getline` and `getdelim` Co-authored-by: Simmo Saan --- src/util/library/libraryFunctions.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index a83b917501..e941ddf165 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -440,11 +440,11 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("times", unknown [drop "buf" [w]]); ("mmap", unknown [drop "addr" []; drop "length" []; drop "prot" []; drop "flags" []; drop "fd" []; drop "offset" []]); ("munmap", unknown [drop "addr" []; drop "length" []]); - ("getline", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "stream" [r_deep; w_deep]]); - ("getwline", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "stream" [r_deep; w_deep]]); - ("getdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "delimiter" [];drop "stream" [r_deep; w_deep]]); - ("__getdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "delimiter" [];drop "stream" [r_deep; w_deep]]); - ("getwdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r]; drop "delimiter" [];drop "stream" [r_deep; w_deep]]); + ("getline", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r; w]; drop "stream" [r_deep; w_deep]]); + ("getwline", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r; w]; drop "stream" [r_deep; w_deep]]); + ("getdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r; w]; drop "delimiter" []; drop "stream" [r_deep; w_deep]]); + ("__getdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r; w]; drop "delimiter" []; drop "stream" [r_deep; w_deep]]); + ("getwdelim", unknown [drop "lineptr" [r_deep; w_deep]; drop "n" [r; w]; drop "delimiter" []; drop "stream" [r_deep; w_deep]]); ] [@@coverage off] From 32791111c8569f25b0b543ce6be3254f8163c14e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 15 May 2024 12:59:25 +0300 Subject: [PATCH 155/689] Apply suggested changes Co-authored-by: Simmo Saan --- src/config/options.schema.json | 6 ++++-- src/util/library/libraryFunctions.ml | 27 ++++++++++++--------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 99c887ca53..37e62ebdda 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1344,7 +1344,8 @@ "zstd", "pcre", "zlib", - "liblzma" + "liblzma", + "legacy" ] }, "default": [ @@ -1355,7 +1356,8 @@ "glibc", "linux-userspace", "goblint", - "ncurses" + "ncurses", + "legacy" ] } }, diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index e941ddf165..cdde23fece 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -432,6 +432,7 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("stpcpy", unknown [drop "dest" [w]; drop "src" [r]]); ("dup", unknown [drop "oldfd" []]); ("readdir_r", unknown [drop "dirp" [r_deep]; drop "entry" [r_deep]; drop "result" [w]]); + ("scandir", unknown [drop "dirp" [r]; drop "namelist" [w]; drop "filter" [r]; drop "compar" [r]]); ("pipe", unknown [drop "pipefd" [w_deep]]); ("waitpid", unknown [drop "pid" []; drop "wstatus" [w]; drop "options" []]); ("strerror_r", unknown [drop "errnum" []; drop "buff" [w]; drop "buflen" []]); @@ -649,7 +650,6 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__readlink_chk", unknown [drop "path" [r]; drop "buf" [w]; drop "len" []; drop "buflen" []]); ("__readlink_alias", unknown [drop "path" [r]; drop "buf" [w]; drop "len" []]); ("__overflow", unknown [drop "f" [r]; drop "ch" []]); - ("__ctype_b_loc", unknown []); ("__ctype_get_mb_cur_max", unknown []); ("__maskrune", unknown [drop "c" [w]; drop "f" []]); ("__xmknod", unknown [drop "ver" []; drop "path" [r]; drop "mode" []; drop "dev" [r; w]]); @@ -693,10 +693,9 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("clnt_sperrno", unknown [drop "stat" []]); ("pmap_unset", unknown [drop "prognum" []; drop "versnum" []]); ("svcudp_create", unknown [drop "sock" []]); - ("svc_register", unknown [drop "xprt" [r;w]; drop "prognum" []; drop "versnum" []; drop "dispatch" [r;w]; drop "protocol" []]); + ("svc_register", unknown [drop "xprt" [r_deep; w_deep]; drop "prognum" []; drop "versnum" []; drop "dispatch" [r; w]; drop "protocol" []]); ("svc_run", unknown []); (* RPC library end *) - ("scandir", unknown [drop "dirp" [r]; drop "namelist" [w_deep]; drop "filter" [r]; drop "compar" [r]]); ] [@@coverage off] @@ -713,7 +712,6 @@ let linux_userspace_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__errno", unknown []); ("__errno_location", unknown []); ("__h_errno_location", unknown []); - ("printk", unknown (drop "fmt" [r] :: VarArgs (drop' [r]))); ("__printf_chk", unknown [drop "flag" []; drop "format" [r]]); ("__fprintf_chk", unknown (drop "stream" [r_deep; w_deep] :: drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); ("__vfprintf_chk", unknown [drop "stream" [r_deep; w_deep]; drop "flag" []; drop "format" [r]; drop "ap" [r_deep]]); @@ -741,8 +739,8 @@ let linux_userspace_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__xstat", unknown [drop "ver" []; drop "path" [r]; drop "stat_buf" [w]]); ("__lxstat", unknown [drop "ver" []; drop "path" [r]; drop "stat_buf" [w]]); ("__fxstat", unknown [drop "ver" []; drop "fildes" []; drop "stat_buf" [w]]); - ("kmem_cache_create", unknown [drop "name" [r]; drop "size" []; drop "align" []; drop "flags" []; drop "ctor" [r]]); - ("usb_submit_urb", unknown [drop "urb" [r]; drop "mem_flags" []]); (* first argument is written to but according to specification must not be read from anymore *) + ("__ctype_b_loc", unknown []); + ("_IO_getc", unknown [drop "f" [r_deep; w_deep]]); ] [@@coverage off] @@ -758,7 +756,7 @@ let linux_kernel_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("up_read", special [__ "sem" []] @@ fun sem -> Unlock sem); ("up_write", special [__ "sem" []] @@ fun sem -> Unlock sem); ("mutex_init", unknown [drop "mutex" []]); - ("__mutex_init", unknown [drop "lock" [r]; drop "name" [r]; drop "key" [r]]); + ("__mutex_init", unknown [drop "lock" []; drop "name" [r]; drop "key" [r]]); ("mutex_lock", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); ("mutex_trylock", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = true; write = true; return_on_success = true }); ("mutex_lock_interruptible", special [__ "lock" []] @@ fun lock -> Lock { lock = lock; try_ = get_bool "sem.lock.fail"; write = true; return_on_success = true }); @@ -810,7 +808,12 @@ let linux_kernel_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__kmalloc", special [__ "size" []; drop "flags" []] @@ fun size -> Malloc size); ("kzalloc", special [__ "size" []; drop "flags" []] @@ fun size -> Calloc {count = Cil.one; size}); ("usb_alloc_urb", special [__ "iso_packets" []; drop "mem_flags" []] @@ fun iso_packets -> Malloc MyCFG.unknown_exp); + ("usb_submit_urb", unknown [drop "urb" [r_deep; w_deep]; drop "mem_flags" []]); (* old comment: first argument is written to but according to specification must not be read from anymore *) + ("dev_driver_string", unknown [drop "dev" [r_deep]]); ("ioctl", unknown (drop "fd" [] :: drop "request" [] :: VarArgs (drop' [r_deep; w_deep]))); + ("idr_pre_get", unknown [drop "idp" [r_deep]; drop "gfp_mask" []]); + ("printk", unknown (drop "fmt" [r] :: VarArgs (drop' [r]))); + ("kmem_cache_create", unknown [drop "name" [r]; drop "size" []; drop "align" []; drop "flags" []; drop "ctor" [r]]); ] [@@coverage off] @@ -1100,11 +1103,8 @@ let klever_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("rtnl_lock", special [] @@ Lock { lock = rtnl_lock; try_ = false; write = true; return_on_success = true }); ("rtnl_unlock", special [] @@ Unlock rtnl_lock); ("__rtnl_unlock", special [] @@ Unlock rtnl_lock); - (* ldv-benchmarks *) (* ddverify *) - ("sema_init", unknown [drop "sem" [r]; drop "val" []]); - ("idr_pre_get", unknown [drop "idp" [r]; drop "gfp_mask" []]); - ("dev_driver_string", unknown [drop "dev" [r]]); + ("sema_init", unknown [drop "sem" []; drop "val" []]); ] [@@coverage off] @@ -1188,9 +1188,6 @@ let liblzma_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ [@@coverage off] let legacy_libs_misc_list: (string * LibraryDesc.t) list = LibraryDsl.[ - (* TODO: was "zil_replay", writes [1;2;3;5]; but couldn't find anything with 5/6 arguments, also not in bench *) - ("zil_replay", unknown [drop "os" [w]; drop "arg" [w]; drop "replay_func" [r]]); - ("_IO_getc", unknown [drop "f" [r_deep; w_deep]]); ("__open_alias", unknown (drop "path" [r] :: drop "oflag" [] :: VarArgs (drop' [r]))); ("__open_2", unknown [drop "file" [r]; drop "oflag" []]); ("__open_too_many_args", unknown []); @@ -1201,7 +1198,7 @@ let legacy_libs_misc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("uncompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []]); ("compress2", unknown [drop "dest" [r]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "level" []]); (* opensssl blowfish *) - ("BF_cfb64_encrypt", unknown [drop "in" [r]; drop "out" [w]; drop "length" []; drop "schedule" [r]; drop "ivec" [w]; drop "num" [w]; drop "enc" [r]]); + ("BF_cfb64_encrypt", unknown [drop "in" [r]; drop "out" [w]; drop "length" []; drop "schedule" [r]; drop "ivec" [r; w]; drop "num" [r; w]; drop "enc" []]); ("BF_set_key", unknown [drop "key" [w]; drop "len" []; drop "data" [r]]); (* libintl *) ("textdomain", unknown [drop "domainname" [r]]); From 96f2cf2a8bd45ba4dcf993351ad1f931eda3fc0c Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Wed, 15 May 2024 13:09:08 +0300 Subject: [PATCH 156/689] Apply suggestions from code review Co-authored-by: Simmo Saan --- src/util/library/libraryFunctions.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index cdde23fece..26c3b0a032 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1192,11 +1192,11 @@ let legacy_libs_misc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__open_2", unknown [drop "file" [r]; drop "oflag" []]); ("__open_too_many_args", unknown []); (* bzlib *) - ("BZ2_bzBuffToBuffCompress", unknown [drop "dest" []; drop "destLen" []; drop "source" [w]; drop "sourceLen" []; drop "blockSize100k" []; drop "verbosity" []; drop "workFactor" []]); - ("BZ2_bzBuffToBuffDecompress", unknown [drop "dest" []; drop "destLen" []; drop "source" [w]; drop "sourceLen" []; drop "small" []; drop "verbosity" []]); + ("BZ2_bzBuffToBuffCompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "blockSize100k" []; drop "verbosity" []; drop "workFactor" []]); + ("BZ2_bzBuffToBuffDecompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "small" []; drop "verbosity" []]); (* zlib (Zebedee) *) ("uncompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []]); - ("compress2", unknown [drop "dest" [r]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "level" []]); + ("compress2", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "level" []]); (* opensssl blowfish *) ("BF_cfb64_encrypt", unknown [drop "in" [r]; drop "out" [w]; drop "length" []; drop "schedule" [r]; drop "ivec" [r; w]; drop "num" [r; w]; drop "enc" []]); ("BF_set_key", unknown [drop "key" [w]; drop "len" []; drop "data" [r]]); From c6d19a977d7671354b4daf7bb870b295d69091b0 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 15 May 2024 12:30:01 +0200 Subject: [PATCH 157/689] initial components for coefficients added --- .../apron/linearTwoVarEqualityDomain.apron.ml | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 67bd67f4e5..ebe973536a 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -17,15 +17,20 @@ open VectorMatrix module Mpqf = SharedFunctions.Mpqf module Rhs = struct - (* (Some i, k) represents a sum of a variable with index i and the number k. - (None, k) represents the number k. *) - type t = (int option * GobZ.t) [@@deriving eq, ord, hash] - let var_zero i = (Some i, Z.zero) - let show_formatted formatter = function - | (Some v, o) when Z.equal o Z.zero -> formatter v - | (Some v, o) -> Printf.sprintf "%s%+Ld" (formatter v) (Z.to_int64 o) - | (None, o) -> Printf.sprintf "%Ld" (Z.to_int64 o) - let show rhs = show_formatted (Printf.sprintf "var_%d") rhs + (* (Some i, k,_,_) represents a sum of a variable with index i and the number k. + (None, k,_,_) represents the number k. *) + type t = (int option * GobZ.t * GobZ.t * GobZ.t) [@@deriving eq, ord, hash] + let var_zero i = (Some i, Z.zero, Z.one, Z.one) + let show_coeff c = + if Z.equal c Z.one then "" + else (Z.to_string c) ^"*" + let show_rhs_formatted formatter = function + | (Some v, o,coeff,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) + | (Some v, o,coeff,_) -> Printf.sprintf "%s%s%+Ld" (show_coeff coeff) (formatter v) (Z.to_int64 o) + | (None, o,_,_) -> Printf.sprintf "%Ld" (Z.to_int64 o) + let show (v,o,c,d) = + let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,c,d) in + if not (Z.equal d Z.one) then "(" ^ rhs ^ ")/" ^ (Z.to_string d) else rhs end module EqualitiesConjunction = struct @@ -36,7 +41,7 @@ module EqualitiesConjunction = struct let show_formatted formatter econ = if IntMap.is_empty econ then "{}" else - let str = IntMap.fold (fun i (refvar,off) acc -> Printf.sprintf "%s=%s ∧ %s" (formatter i) (Rhs.show_formatted formatter (refvar,off)) acc) econ "" in + let str = IntMap.fold (fun i (refvar,off,coeff,divi) acc -> Printf.sprintf "%s%s=%s ∧ %s" (Rhs.show_coeff divi) (formatter i) (Rhs.show_rhs_formatted formatter (refvar,off,coeff,divi)) acc) econ "" in "{" ^ String.sub str 0 (String.length str - 4) ^ "}" let show econ = show_formatted (Printf.sprintf "var_%d") econ @@ -86,9 +91,9 @@ module EqualitiesConjunction = struct IntHashtbl.add h x r; r) in - let rec bumpentry k (refvar,offset) = function (* directly bumps lhs-variable during a run through indexes, bumping refvar explicitely with a new lookup in indexes *) - | (tbl,delta,head::rest) when k>=head -> bumpentry k (refvar,offset) (tbl,delta+1,rest) (* rec call even when =, in order to correctly interpret double bumps *) - | (tbl,delta,lyst) (* k (IntMap.add (op k delta) (BatOption.map (memobumpvar) refvar, offset) tbl, delta, lyst) + let rec bumpentry k (refvar,offset,coeff,divi) = function (* directly bumps lhs-variable during a run through indexes, bumping refvar explicitely with a new lookup in indexes *) + | (tbl,delta,head::rest) when k>=head -> bumpentry k (refvar,offset,coeff,divi) (tbl,delta+1,rest) (* rec call even when =, in order to correctly interpret double bumps *) + | (tbl,delta,lyst) (* k (IntMap.add (op k delta) (BatOption.map (memobumpvar) refvar,offset,coeff,divi) tbl, delta, lyst) in let (a,_,_) = IntMap.fold bumpentry map (IntMap.empty,0,offsetlist) in (* Build new map during fold with bumped key/vals *) (op dim (Array.length indexes), a) From d2ce1755e394d15e67f44c7cbc7c877ae55406ea Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 15 May 2024 13:36:49 +0200 Subject: [PATCH 158/689] adaptation of forget_variable to coefficients --- .../apron/linearTwoVarEqualityDomain.apron.ml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index ebe973536a..ffccecb05f 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -116,17 +116,23 @@ module EqualitiesConjunction = struct (* Forget information about variable i *) let forget_variable d var = let res = - (let ref_var_opt = fst (get_rhs d var) in + (let ref_var_opt = Tuple4.first (get_rhs d var) in match ref_var_opt with | Some ref_var when ref_var = var -> (* var is the reference variable of its connected component *) (let cluster = IntMap.fold - (fun i (ref, offset) l -> if ref = ref_var_opt then i::l else l) (snd d) [] in + (fun i (ref,_,_,_) l -> if ref = ref_var_opt then i::l else l) (snd d) [] in (* obtain cluster with common reference variable ref_var*) match cluster with (* new ref_var is taken from head of the cluster *) - | head :: tail -> - let headconst = snd (get_rhs d head) in (* take offset between old and new reference variable *) - List.fold (fun map i -> set_rhs map i Z.(Some head, snd (get_rhs d i) - headconst)) d cluster (* shift offset to match new reference variable *) + | head :: _ -> + (* ax = by + c /\ a'z = b'y + c' *) + (* ==[[ y:=? ]]==> (a'b)z = (b'a)x + c' -(b'c) *) + let (_,c,b,a) = (get_rhs d head) in (* take offset between old and new reference variable *) + List.fold (fun map i -> + let (_,c',b',a') = (get_rhs d i) in + let newrhs = (Some head, Z.(c' - (b' * c)), Z.(b'*a), Z.(a'*b)) in + set_rhs map i newrhs + ) d cluster (* shift offset to match new reference variable *) | [] -> d) (* empty cluster means no work for us *) | _ -> d) (* variable is either a constant or expressed by another refvar *) in let res = (fst res, IntMap.remove var (snd res)) in (* set d(var) to unknown, finally *) From 95bf50fc1f3f9780693f0c5d188f61a51eb18f5f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 15 May 2024 17:23:41 +0300 Subject: [PATCH 159/689] Test basic ARGs --- src/witness/argTools.ml | 2 +- .../basic/for_fun_true-unreach-call.expected | 63 ++++++ .../for_odd_vesal_true-unreach-call.expected | 84 +++++++ .../basic/for_true-unreach-call.expected | 51 +++++ .../global_init_true-unreach-call.expected | 45 ++++ .../basic/if_det_false-unreach-call.expected | 39 ++++ .../if_det_incr_true-unreach-call.expected | 27 +++ .../basic/if_det_true-unreach-call.expected | 21 ++ .../basic/if_mod_false-unreach-call.expected | 63 ++++++ .../basic/if_mod_true-unreach-call.expected | 45 ++++ .../if_nondet_fun_false-unreach-call.expected | 63 ++++++ .../if_nondet_var_false-unreach-call.expected | 33 +++ ...clude_multiple_false-unreach-call.expected | 92 ++++++++ ...xclude_multiple_true-unreach-call.expected | 111 +++++++++ ...f_trier_exclude_true-unreach-call.expected | 81 +++++++ tests/sv-comp/dune | 12 + tests/sv-comp/dune.inc | 211 ++++++++++++++++++ tests/sv-comp/gen/dune | 2 + tests/sv-comp/gen/gen.ml | 26 +++ 19 files changed, 1070 insertions(+), 1 deletion(-) create mode 100644 tests/sv-comp/basic/for_fun_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/for_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/global_init_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_det_false-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_det_incr_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_det_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_mod_false-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_mod_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected create mode 100644 tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected create mode 100644 tests/sv-comp/dune create mode 100644 tests/sv-comp/dune.inc create mode 100644 tests/sv-comp/gen/dune create mode 100644 tests/sv-comp/gen/gen.ml diff --git a/src/witness/argTools.ml b/src/witness/argTools.ml index 8f440247f0..8bfe0124b4 100644 --- a/src/witness/argTools.ml +++ b/src/witness/argTools.ml @@ -25,7 +25,7 @@ struct let dot_node ppf node = let shape = match Arg.Node.cfgnode node with | Statement {skind=If (_,_,_,_,_); _} -> "diamond" - | Statement _ -> "oval" + | Statement _ -> "box" (* TODO: default nothing like CFG *) | Function _ | FunctionEntry _ -> "box" in diff --git a/tests/sv-comp/basic/for_fun_true-unreach-call.expected b/tests/sv-comp/basic/for_fun_true-unreach-call.expected new file mode 100644 index 0000000000..55c3b86d2e --- /dev/null +++ b/tests/sv-comp/basic/for_fun_true-unreach-call.expected @@ -0,0 +1,63 @@ + ┌─────────────────────────────────┐ + │ fun304main(9)[7] │ + └─────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────────────┐ + │ s17(9)[7] │ ─┐ + └─────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌─────────────────────────────────┐ │ + │ fun302fun(9)[7] │ │ + └─────────────────────────────────┘ │ + │ │ + │ Entry fun │ + ▼ │ + ┌─────────────────────────────────┐ │ + │ s5(9)[15] │ │ + └─────────────────────────────────┘ │ + │ │ + │ Assign 'i = 0' │ + ▼ │ + ┌─────────────────────────────────┐ │ ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ + ┌──────────────────▶ │ s9(9)[84] │ ─┼──────────────────────────────────────────▶ │ s15(9)[99] │ ─────────────────▶ │ ret302fun(9)[7] │ + │ └─────────────────────────────────┘ │ └───────────────────────┘ └─────────────────────┘ + │ │ │ Inlined Proc 'fun()' │ + │ │ Test (i < 1000,true) └───────────────────────────────────────────────────────────────────────┐ │ InlineReturn + │ ▼ │ ▼ + │ ┌─────────────────────────────────┐ │ ┌─────────────────────┐ + │ │ s12(9)[66] │ ─┐ └───────────────▶ │ s18(9)[7] │ + │ └─────────────────────────────────┘ │ └─────────────────────┘ + │ │ │ │ + │ │ InlineEntry '(i < 2000)' │ │ Ret (Some 0, main) + │ ▼ │ ▼ + │ ┌─────────────────────────────────┐ │ ┌─────────────────────┐ + │ │ fun299__VERIFIER_assert(72)[69] │ │ │ ret304main(9)[105] │ + │ └─────────────────────────────────┘ │ └─────────────────────┘ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ Assign 'i = i + 1' │ s0(72)[69] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ │ s3(72)[75] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ │ ret299__VERIFIER_assert(72)[7] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + └─────────────────── │ s13(9)[66] │ ◀┘ + └─────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected new file mode 100644 index 0000000000..0905b9b28c --- /dev/null +++ b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected @@ -0,0 +1,84 @@ + + ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌───────────────────────────────────┐ │ + │ │ fun304main(9)[7] │ │ + │ └───────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌───────────────────────────────────┐ │ + │ │ s19(9)[7] │ ─┐ │ + │ └───────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌───────────────────────────────────┐ │ │ + │ │ fun302fun(9)[7] │ │ │ + │ └───────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry fun │ │ + │ ▼ │ │ + │ ┌───────────────────────────────────┐ │ │ + │ │ s5(9)[15] │ │ │ + │ └───────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Assign 'i = 1' │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────┐ InlineEntry '(i < 2000)' ┌────────────┐ Test (i < 1000,true) ┌───────────────────────────────────┐ │ Assign 'i = i + 2' │ + │ │ fun299__VERIFIER_assert(72)[69] │ ◀──────────────────────────────────────────── │ s12(9)[66] │ ◀───────────────────────────────────────────── │ s9(9)[84] │ ◀┼───────────────────────────────────────────────┘ + │ └─────────────────────────────────┘ └────────────┘ └───────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ + │ ▼ │ ▼ │ + │ ┌─────────────────────────────────┐ │ ┌───────────────────────────────────┐ │ + │ │ s0(72)[69] │ │ ┌──────────────────────────────────────────── │ s16(9)[99] │ │ + │ └─────────────────────────────────┘ │ │ └───────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ + │ ▼ │ │ ▼ │ + │ ┌─────────────────────────────────┐ │ │ ┌───────────────────────────────────┐ │ + │ │ s3(72)[75] │ │ │ │ fun299__VERIFIER_assert(105)[102] │ │ + │ └─────────────────────────────────┘ │ │ └───────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ + │ ▼ │ │ ▼ │ + │ ┌─────────────────────────────────┐ │ │ ┌───────────────────────────────────┐ │ Test (! cond,true) ┌──────────────────────────────┐ + │ │ ret299__VERIFIER_assert(72)[7] │ │ │ │ s0(105)[102] │ ─┼──────────────────────────────────────────────────────────────────▶ │ s2(105)[110] │ + │ └─────────────────────────────────┘ │ │ └───────────────────────────────────┘ │ └──────────────────────────────┘ + │ │ │ │ │ │ │ + │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' + │ ▼ │ │ ▼ │ ▼ + │ ┌─────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌───────────────────────────────────┐ │ ┌──────────────────────────────┐ + └─ │ s13(9)[66] │ ◀───────────────────────────────────────────────┘ │ │ s3(105)[108] │ │ │ fun297__VERIFIER_error(9)[7] │ + └─────────────────────────────────┘ │ └───────────────────────────────────┘ │ └──────────────────────────────┘ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error + │ ▼ │ ▼ + │ ┌───────────────────────────────────┐ │ ┌──────────────────────────────┐ + │ │ ret299__VERIFIER_assert(105)[7] │ │ │ s22(9)[7] │ + │ └───────────────────────────────────┘ │ └──────────────────────────────┘ + │ │ │ + │ │ InlineReturn │ Inlined Proc 'fun()' + │ ▼ │ + │ ┌───────────────────────────────────┐ │ + └───────────────────────────────────────────▶ │ s17(9)[99] │ │ + └───────────────────────────────────┘ │ + │ │ + │ Ret (None, fun) │ + ▼ │ + ┌───────────────────────────────────┐ │ + │ ret302fun(9)[7] │ │ + └───────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌───────────────────────────────────┐ │ + │ s20(9)[7] │ ◀┘ + └───────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌───────────────────────────────────┐ + │ ret304main(9)[125] │ + └───────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_true-unreach-call.expected b/tests/sv-comp/basic/for_true-unreach-call.expected new file mode 100644 index 0000000000..9d173bd11d --- /dev/null +++ b/tests/sv-comp/basic/for_true-unreach-call.expected @@ -0,0 +1,51 @@ + ┌─────────────────────────────────┐ + │ fun302main(9)[7] │ + └─────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────────────┐ + │ s5(9)[11] │ + └─────────────────────────────────┘ + │ + │ Assign 'i = 0' + ▼ + ┌─────────────────────────────────┐ Test (i < 1000,false) ┌────────────┐ Ret (Some 0, main) ┌────────────────────┐ + ┌──────────────────▶ │ s9(9)[89] │ ────────────────────────────────────────────▶ │ s15(9)[98] │ ────────────────────▶ │ ret302main(9)[101] │ + │ └─────────────────────────────────┘ └────────────┘ └────────────────────┘ + │ │ + │ │ Test (i < 1000,true) + │ ▼ + │ ┌─────────────────────────────────┐ + │ │ s12(9)[63] │ ─┐ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(i < 2000)' │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ │ fun299__VERIFIER_assert(69)[66] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ Assign 'i = i + 1' │ s0(69)[66] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ │ s3(69)[72] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + │ │ ret299__VERIFIER_assert(69)[7] │ │ + │ └─────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌─────────────────────────────────┐ │ + └─────────────────── │ s13(9)[63] │ ◀┘ + └─────────────────────────────────┘ diff --git a/tests/sv-comp/basic/global_init_true-unreach-call.expected b/tests/sv-comp/basic/global_init_true-unreach-call.expected new file mode 100644 index 0000000000..deb1222b45 --- /dev/null +++ b/tests/sv-comp/basic/global_init_true-unreach-call.expected @@ -0,0 +1,45 @@ +┌─────────────────────────────────┐ +│ fun302main(12)[10] │ +└─────────────────────────────────┘ + │ + │ Entry main + ▼ +┌─────────────────────────────────┐ +│ s5(12)[10] │ ─┐ +└─────────────────────────────────┘ │ + │ │ + │ InlineEntry '(g == 1)' │ + ▼ │ +┌─────────────────────────────────┐ │ +│ fun298__VERIFIER_assert(18)[16] │ │ +└─────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ +┌─────────────────────────────────┐ │ +│ s0(18)[16] │ │ +└─────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(g == 1)' + ▼ │ +┌─────────────────────────────────┐ │ +│ s3(18)[16] │ │ +└─────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ +┌─────────────────────────────────┐ │ +│ ret298__VERIFIER_assert(18)[10] │ │ +└─────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ +┌─────────────────────────────────┐ │ +│ s6(12)[10] │ ◀┘ +└─────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ +┌─────────────────────────────────┐ +│ ret302main(12)[25] │ +└─────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_false-unreach-call.expected b/tests/sv-comp/basic/if_det_false-unreach-call.expected new file mode 100644 index 0000000000..c55b60aacd --- /dev/null +++ b/tests/sv-comp/basic/if_det_false-unreach-call.expected @@ -0,0 +1,39 @@ +┌────────────────────────────────┐ +│ fun298main(9)[7] │ +└────────────────────────────────┘ + │ + │ Entry main + ▼ +┌────────────────────────────────┐ +│ s3(9)[11] │ +└────────────────────────────────┘ + │ + │ Test (1,true) + ▼ +┌────────────────────────────────┐ +│ s6(9)[11] │ +└────────────────────────────────┘ + │ + │ Assign 'x = 1' + ▼ +┌────────────────────────────────┐ +│ s7(9)[16] │ +└────────────────────────────────┘ + │ + │ Test (x,true) + ▼ +┌────────────────────────────────┐ +│ s9(9)[16] │ +└────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ +┌────────────────────────────────┐ +│ fun297__VERIFIER_error(23)[20] │ +└────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ +┌────────────────────────────────┐ +│ s13(23)[20] │ +└────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected new file mode 100644 index 0000000000..ce80d3a4a3 --- /dev/null +++ b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected @@ -0,0 +1,27 @@ +┌─────────────────────┐ +│ fun298main(9)[7] │ +└─────────────────────┘ + │ + │ Entry main + ▼ +┌─────────────────────┐ +│ s3(9)[11] │ ◀┐ +└─────────────────────┘ │ + │ │ + │ Test (1,true) │ + ▼ │ +┌─────────────────────┐ │ +│ s6(9)[11] │ │ +└─────────────────────┘ │ + │ │ + │ Assign 'x = -1' │ Test (x,false) + ▼ │ +┌─────────────────────┐ │ +│ s7(9)[16] │ │ +└─────────────────────┘ │ + │ │ + │ Assign 'x = x + 1' │ + ▼ │ +┌─────────────────────┐ │ +│ s8(9)[19] │ ─┘ +└─────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_true-unreach-call.expected b/tests/sv-comp/basic/if_det_true-unreach-call.expected new file mode 100644 index 0000000000..8e85590c66 --- /dev/null +++ b/tests/sv-comp/basic/if_det_true-unreach-call.expected @@ -0,0 +1,21 @@ +┌──────────────────┐ +│ fun298main(9)[7] │ +└──────────────────┘ + │ + │ Entry main + ▼ +┌──────────────────┐ +│ s3(9)[11] │ ◀┐ +└──────────────────┘ │ + │ │ + │ Test (1,true) │ + ▼ │ +┌──────────────────┐ │ +│ s6(9)[11] │ │ Test (x,false) +└──────────────────┘ │ + │ │ + │ Assign 'x = 0' │ + ▼ │ +┌──────────────────┐ │ +│ s7(9)[16] │ ─┘ +└──────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_false-unreach-call.expected b/tests/sv-comp/basic/if_mod_false-unreach-call.expected new file mode 100644 index 0000000000..ee5fc89921 --- /dev/null +++ b/tests/sv-comp/basic/if_mod_false-unreach-call.expected @@ -0,0 +1,63 @@ + ┌────────────────────────────────────────┐ + │ fun299main(9)[7] │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + ┌────────────────────▶ │ s3(9)[25] │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (1,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ s6(9)[25] │ ─┐ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '()' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ fun298__VERIFIER_nondet_int(37)[34] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_nondet_int │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ Test (x >= 50,false) │ s21(37)[49] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ ret298__VERIFIER_nondet_int(37)[52] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn 'tmp' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ s7(9)[25] │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = tmp 00' + │ ▼ + │ ┌────────────────────────────────────────┐ + └───────────────────── │ s8(9)[28] │ + └────────────────────────────────────────┘ + │ + │ Test (x >= 50,true) + ▼ + ┌────────────────────────────────────────┐ + │ s10(9)[31] │ + └────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌────────────────────────────────────────┐ + │ fun297__VERIFIER_error(37)[34] │ + └────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌────────────────────────────────────────┐ + │ s14(37)[34] │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_true-unreach-call.expected b/tests/sv-comp/basic/if_mod_true-unreach-call.expected new file mode 100644 index 0000000000..ceb8b5b4e3 --- /dev/null +++ b/tests/sv-comp/basic/if_mod_true-unreach-call.expected @@ -0,0 +1,45 @@ + ┌────────────────────────────────────────┐ + │ fun299main(9)[7] │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + ┌─────────────────────▶ │ s3(9)[25] │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (1,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ s6(9)[25] │ ─┐ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '()' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ fun298__VERIFIER_nondet_int(39)[36] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_nondet_int │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ Test (x >= 100,false) │ s21(39)[41] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ ret298__VERIFIER_nondet_int(39)[44] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn 'tmp' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ s7(9)[25] │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = tmp 00' + │ ▼ + │ ┌────────────────────────────────────────┐ + └────────────────────── │ s8(9)[28] │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected new file mode 100644 index 0000000000..e0f45cc4ef --- /dev/null +++ b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected @@ -0,0 +1,63 @@ + ┌────────────────────────────────────────┐ + │ fun299main(9)[7] │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + ┌──────────────▶ │ s3(9)[25] │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (1,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ s6(9)[25] │ ─┐ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '()' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ fun298__VERIFIER_nondet_int(49)[46] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_nondet_int │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ Test (x,false) │ s21(49)[51] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ ret298__VERIFIER_nondet_int(49)[54] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn 'tmp' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ s7(9)[25] │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = tmp' + │ ▼ + │ ┌────────────────────────────────────────┐ + └─────────────── │ s8(9)[28] │ + └────────────────────────────────────────┘ + │ + │ Test (x,true) + ▼ + ┌────────────────────────────────────────┐ + │ s10(9)[31] │ + └────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌────────────────────────────────────────┐ + │ fun297__VERIFIER_error(37)[34] │ + └────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌────────────────────────────────────────┐ + │ s14(37)[34] │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected new file mode 100644 index 0000000000..a9c9006399 --- /dev/null +++ b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected @@ -0,0 +1,33 @@ +┌──────────────────────────────┐ +│ fun298main(9)[7] │ +└──────────────────────────────┘ + │ + │ Entry main + ▼ +┌──────────────────────────────┐ +│ s3(9)[11] │ ◀┐ +└──────────────────────────────┘ │ + │ │ + │ Test (1,true) │ Test (x,false) + ▼ │ +┌──────────────────────────────┐ │ +│ s5(9)[11] │ ─┘ +└──────────────────────────────┘ + │ + │ Test (x,true) + ▼ +┌──────────────────────────────┐ +│ s7(9)[16] │ +└──────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ +┌──────────────────────────────┐ +│ fun297__VERIFIER_error(9)[7] │ +└──────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ +┌──────────────────────────────┐ +│ s11(9)[7] │ +└──────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected new file mode 100644 index 0000000000..195ae9c8ea --- /dev/null +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected @@ -0,0 +1,92 @@ + + ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ fun302main(9)[7] │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┐ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 1)' + │ │ │ ▼ ▼ + │ ┌─────────────────────────────────┐ InlineEntry '(x != 1)' ┌──────────────────────┐ │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ fun299__VERIFIER_assert(40)[37] │ ◀──────────────────────── │ s19(9)[34] │ └────────────────────────────────────────▶ │ │ + │ └─────────────────────────────────┘ └──────────────────────┘ │ │ + │ │ ▲ InlineReturn │ │ InlineReturn + │ │ Entry __VERIFIER_assert ┌──────────────────────────┼────────────────────────────────────────────────────────────────▶ │ s7(9)[25] │ ◀─────────────────┐ + │ ▼ │ │ │ │ │ + │ ┌────────────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────┐ │ │ │ │ │ + │ │ s2(40)[45] │ ◀──────────────────── │ s0(40)[37] │ │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ + │ └────────────────────────────────┘ └─────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ │ + │ │ InlineEntry '()' │ Test (! cond,false) │ │ │ │ Test (1,true) │ │ + │ ▼ ▼ │ │ │ ▼ │ │ + │ ┌────────────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ fun297__VERIFIER_error(51)[48] │ │ s3(40)[43] │ │ │ │ │ s10(9)[25] │ ─┐ │ │ + │ └────────────────────────────────┘ └─────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ │ │ │ InlineEntry '()' │ │ │ + │ ▼ ▼ │ │ │ ▼ │ │ │ + │ ┌────────────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ s23(51)[48] │ │ ret299__VERIFIER_assert(40)[48] │ ─┘ │ │ │ fun298__VERIFIER_nondet_int(91)[88] │ │ │ │ + │ └────────────────────────────────┘ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + └─────────────────────────────────────────────────────────────┐ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ ▼ │ │ │ + │ │ Test (x == 2,false) │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x == 2)' │ s30(91)[93] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ ret298__VERIFIER_nondet_int(91)[96] │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ s11(9)[25] │ ◀┘ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Assign 'x = tmp' │ │ + │ │ │ ▼ │ │ + ┌─────────────────────────────────┐ Test (x == 0,true) │ │ ┌────────────────────────────────────────┐ │ │ + │ s14(9)[73] │ ◀───────────────────────────┼───────────────────────┼───────────────────────────────────────── │ s12(9)[28] │ │ InlineReturn │ + └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Test (x == 0,false) │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────┼───────────────────────────────────────── │ s15(9)[31] │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Test (x == 2,true) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────────────────────── │ s17(9)[59] │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x == 2)' │ │ + │ ▼ │ │ + │ InlineEntry '(x == 0)' ┌────────────────────────────────────────┐ │ │ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ fun299__VERIFIER_assert(65)[62] │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Entry __VERIFIER_assert │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ s0(65)[62] │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Test (! cond,false) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ s3(65)[62] │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ ret299__VERIFIER_assert(65)[48] │ ──────────────────────────────────────────────────┘ │ + └────────────────────────────────────────┘ │ + │ │ + └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected new file mode 100644 index 0000000000..a4e8e9cc8c --- /dev/null +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -0,0 +1,111 @@ + + ┌───────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + ┌──────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ fun302main(9)[7] │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ ┌──────────────────────────────────────────────────────────────┘ │ Entry main │ Inlined Proc '__VERIFIER_assert(x == 0)' │ + │ │ ▼ ▼ │ + │ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ + │ ┌────┼────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ s17(9)[54] │ + │ │ │ │ │ └─────────────────────┘ + │ │ │ InlineReturn │ │ ▲ + │ │ │ ┌─────────────────────────────────────────────────────────────────────▶ │ s7(9)[25] │ │ Test (x == 2,true) + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ + │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Test (1,true) │ InlineReturn │ + │ │ │ │ │ ▼ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ │ │ s10(9)[25] │ ─┐ ┌────┼────────────────────────────────────────────┘ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineEntry '()' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ fun298__VERIFIER_nondet_int(87)[84] │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ InlineEntry '(x == 2)' │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ s37(87)[89] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ ret298__VERIFIER_nondet_int(87)[92] │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ s11(9)[25] │ ◀┘ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Assign 'x = tmp' │ │ + │ │ │ │ │ ▼ │ │ + │ │ ┌─────────────────────────────────┐ │ Test (x == 0,true) │ ┌────────────────────────────────────────┐ │ │ + │ │ │ s14(9)[69] │ ◀┼───────────────────────────┼────────────────────────────────────────── │ s12(9)[28] │ │ │ + │ │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ InlineEntry '(x == 0)' │ │ │ Test (x == 0,false) │ │ + │ │ ▼ │ │ ▼ │ │ + │ │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + └──────────────────────────┼▶ │ fun299__VERIFIER_assert(60)[57] │ │ │ │ s15(9)[31] │ ──────────────────────────────────────────────────┘ │ + │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ │ Test (x == 2,false) │ + │ ▼ │ │ ▼ │ + │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + │ │ s0(60)[57] │ │ │ │ s18(9)[34] │ │ + │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ Test (x != 0,true) │ + │ ▼ │ │ ▼ │ + │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + │ │ s3(60)[57] │ │ │ │ s19(9)[34] │ │ + │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Test (x != 2,true) │ + │ ▼ │ │ ▼ │ + │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + └─ │ ret299__VERIFIER_assert(60)[64] │ ─┘ │ │ s21(9)[34] │ │ + └─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'tmp___0 = 1' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + └────────────────────────────────────────── │ s26(9)[39] │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ fun299__VERIFIER_assert(45)[42] │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ s0(45)[42] │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ s3(45)[42] │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ ret299__VERIFIER_assert(45)[49] │ ───────────────────────────────────────────────────────┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected new file mode 100644 index 0000000000..ff77d25120 --- /dev/null +++ b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected @@ -0,0 +1,81 @@ + + ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ fun302main(9)[7] │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry main │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x != 0)' + │ │ ▼ ▼ ▼ + │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ ┌────────────────────────────────────────▶ │ s7(9)[25] │ ◀┐ + │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ Test (1,true) │ + │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ + │ │ │ │ s10(9)[25] │ ─┐ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ fun298__VERIFIER_nondet_int(66)[63] │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ s27(66)[68] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ ret298__VERIFIER_nondet_int(66)[71] │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ s11(9)[25] │ ◀┘ │ + │ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ Assign 'x = tmp' │ InlineReturn + │ │ │ ▼ │ +┌─────────────────────────────────┐ │ Test (x == 0,false) │ ┌────────────────────────────────────────┐ │ +│ s16(9)[31] │ ◀┼────────────────────────────┼───────────────────────────────────────── │ s12(9)[28] │ │ +└─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ InlineEntry '(x != 0)' │ │ │ Test (x == 0,true) │ + ▼ │ │ ▼ │ +┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ +│ fun299__VERIFIER_assert(37)[34] │ │ └───────────────────────────────────────── │ s14(9)[45] │ │ +└─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Entry __VERIFIER_assert │ │ InlineEntry '(x == 0)' │ + ▼ │ ▼ │ +┌─────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ s0(37)[34] │ │ │ fun299__VERIFIER_assert(51)[48] │ │ +└─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Test (! cond,false) │ │ Entry __VERIFIER_assert │ + ▼ │ ▼ │ +┌─────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ s3(37)[34] │ │ │ s0(51)[48] │ │ +└─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ Test (! cond,false) │ + ▼ │ ▼ │ +┌─────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ ret299__VERIFIER_assert(37)[41] │ ─┘ │ s3(51)[48] │ │ +└─────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ ret299__VERIFIER_assert(51)[41] │ ───────────────────────────────────────────────────────────────────────────────────────────────┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/dune b/tests/sv-comp/dune new file mode 100644 index 0000000000..bb686452c1 --- /dev/null +++ b/tests/sv-comp/dune @@ -0,0 +1,12 @@ +(include dune.inc) + +(rule + (deps (:files (glob_files basic/*.c))) + (action (with-stdout-to + dune.inc.gen + (run gen/gen.exe %{files})))) + +(rule + (alias runtest) + (action + (diff dune.inc dune.inc.gen))) diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc new file mode 100644 index 0000000000..caabea159b --- /dev/null +++ b/tests/sv-comp/dune.inc @@ -0,0 +1,211 @@ + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c for_fun_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target for_fun_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff for_fun_true-unreach-call.expected for_fun_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c for_odd_vesal_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target for_odd_vesal_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff for_odd_vesal_true-unreach-call.expected for_odd_vesal_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c for_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target for_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff for_true-unreach-call.expected for_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c global_init_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target global_init_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff global_init_true-unreach-call.expected global_init_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_det_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_det_false-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_det_false-unreach-call.expected if_det_false-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_det_incr_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_det_incr_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_det_incr_true-unreach-call.expected if_det_incr_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_det_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_det_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_det_true-unreach-call.expected if_det_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_mod_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_mod_false-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_mod_false-unreach-call.expected if_mod_false-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_mod_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_mod_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_mod_true-unreach-call.expected if_mod_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_nondet_fun_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_nondet_fun_false-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_nondet_fun_false-unreach-call.expected if_nondet_fun_false-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_nondet_var_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_nondet_var_false-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_nondet_var_false-unreach-call.expected if_nondet_var_false-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_trier_exclude_multiple_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_trier_exclude_multiple_false-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_trier_exclude_multiple_false-unreach-call.expected if_trier_exclude_multiple_false-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_trier_exclude_multiple_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_trier_exclude_multiple_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_trier_exclude_multiple_true-unreach-call.expected if_trier_exclude_multiple_true-unreach-call.output))) + ) + + (subdir basic + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c if_trier_exclude_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_trier_exclude_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff if_trier_exclude_true-unreach-call.expected if_trier_exclude_true-unreach-call.output))) + ) + \ No newline at end of file diff --git a/tests/sv-comp/gen/dune b/tests/sv-comp/gen/dune new file mode 100644 index 0000000000..9df6b5100e --- /dev/null +++ b/tests/sv-comp/gen/dune @@ -0,0 +1,2 @@ +(executable + (name gen)) diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml new file mode 100644 index 0000000000..565044e809 --- /dev/null +++ b/tests/sv-comp/gen/gen.ml @@ -0,0 +1,26 @@ +let generate_rule file = + let dir = Filename.dirname file in + let file'' = Filename.basename file in + let file' = Filename.chop_extension file'' in + Printf.printf {| + (subdir %s + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c %s) (:prop %%{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target %s.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg)) + (with-stdout-to %%{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff %s.expected %s.output))) + ) + |} dir file'' file' file' file' + +let () = + Sys.argv + |> Array.to_seq + |> Seq.drop 1 + |> Seq.iter generate_rule From 070baba12898d4a2733e95a8ed366a465ee5f243 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 15 May 2024 17:26:03 +0300 Subject: [PATCH 160/689] Automate ARG test promote --- tests/sv-comp/dune | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/sv-comp/dune b/tests/sv-comp/dune index bb686452c1..a2c0e60831 100644 --- a/tests/sv-comp/dune +++ b/tests/sv-comp/dune @@ -1,12 +1,9 @@ (include dune.inc) (rule + (alias runtest) + (mode promote) (deps (:files (glob_files basic/*.c))) (action (with-stdout-to - dune.inc.gen + dune.inc (run gen/gen.exe %{files})))) - -(rule - (alias runtest) - (action - (diff dune.inc dune.inc.gen))) From 8b3e77261f1e0778617be4adb75d984d3b8da791 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 15 May 2024 17:35:57 +0300 Subject: [PATCH 161/689] Enumerate ARG nodes in tests for portability --- src/framework/control.ml | 9 + src/witness/argTools.ml | 17 ++ .../basic/for_fun_true-unreach-call.expected | 120 ++++----- .../for_odd_vesal_true-unreach-call.expected | 172 +++++++------ .../basic/for_true-unreach-call.expected | 84 +++--- .../global_init_true-unreach-call.expected | 78 +++--- .../basic/if_det_false-unreach-call.expected | 42 +-- .../if_det_incr_true-unreach-call.expected | 10 +- .../basic/if_det_true-unreach-call.expected | 36 +-- .../basic/if_mod_false-unreach-call.expected | 22 +- .../basic/if_mod_true-unreach-call.expected | 114 ++++---- .../if_nondet_fun_false-unreach-call.expected | 22 +- .../if_nondet_var_false-unreach-call.expected | 72 +++--- ...clude_multiple_false-unreach-call.expected | 206 ++++++++------- ...xclude_multiple_true-unreach-call.expected | 243 ++++++++++-------- ...f_trier_exclude_true-unreach-call.expected | 168 ++++++------ tests/sv-comp/dune.inc | 28 +- tests/sv-comp/gen/gen.ml | 2 +- 18 files changed, 779 insertions(+), 666 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index 714a83b236..0c54d0d373 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -748,6 +748,15 @@ struct if get_bool "exp.arg" then ( let module ArgTool = ArgTools.Make (R) in let module Arg = (val ArgTool.create entrystates) in + let module Arg = + (val match get_string "witness.graphml.id" with + | "node" -> + (module Arg: ArgTools.BiArg) + | "enumerate" -> + (module ArgTools.Enumerate (Arg)) + | _ -> failwith "witness.graphml.id: illegal value" + ) + in if get_bool "exp.argdot" then ( let module ArgDot = ArgTools.Dot (Arg) in let oc = Batteries.open_out "arg.dot" in diff --git a/src/witness/argTools.ml b/src/witness/argTools.ml index 8bfe0124b4..b67205f8ec 100644 --- a/src/witness/argTools.ml +++ b/src/witness/argTools.ml @@ -39,6 +39,23 @@ struct Format.fprintf ppf "@[digraph arg {%t@]@,}@\n" dot_nodes end +module Enumerate (Arg: BiArg): BiArg = +struct + include Arg + + module Node = + struct + include Node + + module HC = BatHashcons.MakeTable (Node) + let htable = HC.create 113 + + let to_string n = + let hc = HC.hashcons htable n in + string_of_int hc.tag + end +end + let current_arg: (module BiArg) option ref = ref None module Make (R: ResultQuery.SpecSysSol2) = diff --git a/tests/sv-comp/basic/for_fun_true-unreach-call.expected b/tests/sv-comp/basic/for_fun_true-unreach-call.expected index 55c3b86d2e..e9b6bd185d 100644 --- a/tests/sv-comp/basic/for_fun_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_fun_true-unreach-call.expected @@ -1,63 +1,63 @@ - ┌─────────────────────────────────┐ - │ fun304main(9)[7] │ - └─────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 123 │ + └────────────────────────────────┘ │ │ Entry main ▼ - ┌─────────────────────────────────┐ - │ s17(9)[7] │ ─┐ - └─────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌─────────────────────────────────┐ │ - │ fun302fun(9)[7] │ │ - └─────────────────────────────────┘ │ - │ │ - │ Entry fun │ - ▼ │ - ┌─────────────────────────────────┐ │ - │ s5(9)[15] │ │ - └─────────────────────────────────┘ │ - │ │ - │ Assign 'i = 0' │ - ▼ │ - ┌─────────────────────────────────┐ │ ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ - ┌──────────────────▶ │ s9(9)[84] │ ─┼──────────────────────────────────────────▶ │ s15(9)[99] │ ─────────────────▶ │ ret302fun(9)[7] │ - │ └─────────────────────────────────┘ │ └───────────────────────┘ └─────────────────────┘ - │ │ │ Inlined Proc 'fun()' │ - │ │ Test (i < 1000,true) └───────────────────────────────────────────────────────────────────────┐ │ InlineReturn - │ ▼ │ ▼ - │ ┌─────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ s12(9)[66] │ ─┐ └───────────────▶ │ s18(9)[7] │ - │ └─────────────────────────────────┘ │ └─────────────────────┘ - │ │ │ │ - │ │ InlineEntry '(i < 2000)' │ │ Ret (Some 0, main) - │ ▼ │ ▼ - │ ┌─────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ fun299__VERIFIER_assert(72)[69] │ │ │ ret304main(9)[105] │ - │ └─────────────────────────────────┘ │ └─────────────────────┘ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ s0(72)[69] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ │ s3(72)[75] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ │ ret299__VERIFIER_assert(72)[7] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - └─────────────────── │ s13(9)[66] │ ◀┘ - └─────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 124 │ ─┐ + └────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 131 │ │ + └────────────────────────────────┘ │ + │ │ + │ Entry fun │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 132 │ │ + └────────────────────────────────┘ │ + │ │ + │ Assign 'i = 0' │ + ▼ │ + ┌────────────────────────────────┐ │ ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ + ┌──────────────────▶ │ 130 │ ─┼──────────────────────────────────────────▶ │ 136 │ ─────────────────▶ │ 137 │ + │ └────────────────────────────────┘ │ └───────────────────────┘ └─────────────────────┘ + │ │ │ Inlined Proc 'fun()' │ + │ │ Test (i < 1000,true) └───────────────────────────────────────────────────────────────────────┐ │ InlineReturn + │ ▼ │ ▼ + │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ + │ │ 135 │ ─┐ └───────────────▶ │ 133 │ + │ └────────────────────────────────┘ │ └─────────────────────┘ + │ │ │ │ + │ │ InlineEntry '(i < 2000)' │ │ Ret (Some 0, main) + │ ▼ │ ▼ + │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ + │ │ 127 │ │ │ 134 │ + │ └────────────────────────────────┘ │ └─────────────────────┘ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ Assign 'i = i + 1' │ 128 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 125 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 126 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └─────────────────── │ 129 │ ◀┘ + └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected index 0905b9b28c..b05d174ebf 100644 --- a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected @@ -1,84 +1,90 @@ + ┌────────────────────────────────┐ + │ 148 │ + └────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────┐ + │ 149 │ + └────────────────────────────────┘ - ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌───────────────────────────────────┐ │ - │ │ fun304main(9)[7] │ │ - │ └───────────────────────────────────┘ │ - │ │ │ - │ │ Entry main │ - │ ▼ │ - │ ┌───────────────────────────────────┐ │ - │ │ s19(9)[7] │ ─┐ │ - │ └───────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌───────────────────────────────────┐ │ │ - │ │ fun302fun(9)[7] │ │ │ - │ └───────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry fun │ │ - │ ▼ │ │ - │ ┌───────────────────────────────────┐ │ │ - │ │ s5(9)[15] │ │ │ - │ └───────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Assign 'i = 1' │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────┐ InlineEntry '(i < 2000)' ┌────────────┐ Test (i < 1000,true) ┌───────────────────────────────────┐ │ Assign 'i = i + 2' │ - │ │ fun299__VERIFIER_assert(72)[69] │ ◀──────────────────────────────────────────── │ s12(9)[66] │ ◀───────────────────────────────────────────── │ s9(9)[84] │ ◀┼───────────────────────────────────────────────┘ - │ └─────────────────────────────────┘ └────────────┘ └───────────────────────────────────┘ │ - │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ - │ ▼ │ ▼ │ - │ ┌─────────────────────────────────┐ │ ┌───────────────────────────────────┐ │ - │ │ s0(72)[69] │ │ ┌──────────────────────────────────────────── │ s16(9)[99] │ │ - │ └─────────────────────────────────┘ │ │ └───────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ - │ ▼ │ │ ▼ │ - │ ┌─────────────────────────────────┐ │ │ ┌───────────────────────────────────┐ │ - │ │ s3(72)[75] │ │ │ │ fun299__VERIFIER_assert(105)[102] │ │ - │ └─────────────────────────────────┘ │ │ └───────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ - │ ▼ │ │ ▼ │ - │ ┌─────────────────────────────────┐ │ │ ┌───────────────────────────────────┐ │ Test (! cond,true) ┌──────────────────────────────┐ - │ │ ret299__VERIFIER_assert(72)[7] │ │ │ │ s0(105)[102] │ ─┼──────────────────────────────────────────────────────────────────▶ │ s2(105)[110] │ - │ └─────────────────────────────────┘ │ │ └───────────────────────────────────┘ │ └──────────────────────────────┘ - │ │ │ │ │ │ │ - │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' - │ ▼ │ │ ▼ │ ▼ - │ ┌─────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌───────────────────────────────────┐ │ ┌──────────────────────────────┐ - └─ │ s13(9)[66] │ ◀───────────────────────────────────────────────┘ │ │ s3(105)[108] │ │ │ fun297__VERIFIER_error(9)[7] │ - └─────────────────────────────────┘ │ └───────────────────────────────────┘ │ └──────────────────────────────┘ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error - │ ▼ │ ▼ - │ ┌───────────────────────────────────┐ │ ┌──────────────────────────────┐ - │ │ ret299__VERIFIER_assert(105)[7] │ │ │ s22(9)[7] │ - │ └───────────────────────────────────┘ │ └──────────────────────────────┘ - │ │ │ - │ │ InlineReturn │ Inlined Proc 'fun()' - │ ▼ │ - │ ┌───────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ s17(9)[99] │ │ - └───────────────────────────────────┘ │ - │ │ - │ Ret (None, fun) │ - ▼ │ - ┌───────────────────────────────────┐ │ - │ ret302fun(9)[7] │ │ - └───────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌───────────────────────────────────┐ │ - │ s20(9)[7] │ ◀┘ - └───────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌───────────────────────────────────┐ - │ ret304main(9)[125] │ - └───────────────────────────────────┘ + ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────┐ │ + │ │ 171 │ ─┐ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 157 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ Assign 'i = i + 2' + │ │ Entry fun │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 158 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Assign 'i = 1' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌─────┐ Test (i < 1000,true) ┌────────────────────────────────┐ │ │ + │ │ 153 │ ◀──────────────────────────────────────────── │ 162 │ ◀───────────────────────────────────────────── │ 156 │ ◀┼────────────────────────┘ + │ └────────────────────────────────┘ └─────┘ └────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ + │ ▼ │ ▼ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────┐ │ + │ │ 154 │ │ ┌──────────────────────────────────────────── │ 163 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ + │ │ 151 │ │ │ │ 166 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ Test (! cond,true) ┌─────────────────────────┐ + │ │ 152 │ │ │ │ 167 │ ─┼──────────────────────────────────────────────────────────────────▶ │ 172 │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ │ │ │ │ + │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' + │ ▼ │ │ ▼ │ ▼ + │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ + └─ │ 155 │ ◀───────────────────────────────────────────────┘ │ │ 164 │ │ │ 170 │ + └────────────────────────────────┘ │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error + │ ▼ │ ▼ + │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ + │ │ 165 │ │ │ 161 │ + │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ + │ │ InlineReturn │ Inlined Proc 'fun()' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └───────────────────────────────────────────▶ │ 168 │ │ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, fun) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 169 │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 159 │ ◀┘ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ 160 │ + └────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 150 │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_true-unreach-call.expected b/tests/sv-comp/basic/for_true-unreach-call.expected index 9d173bd11d..6a0b812d06 100644 --- a/tests/sv-comp/basic/for_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_true-unreach-call.expected @@ -1,51 +1,51 @@ - ┌─────────────────────────────────┐ - │ fun302main(9)[7] │ - └─────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 116 │ + └────────────────────────────────┘ │ │ Entry main ▼ - ┌─────────────────────────────────┐ - │ s5(9)[11] │ - └─────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 117 │ + └────────────────────────────────┘ │ │ Assign 'i = 0' ▼ - ┌─────────────────────────────────┐ Test (i < 1000,false) ┌────────────┐ Ret (Some 0, main) ┌────────────────────┐ - ┌──────────────────▶ │ s9(9)[89] │ ────────────────────────────────────────────▶ │ s15(9)[98] │ ────────────────────▶ │ ret302main(9)[101] │ - │ └─────────────────────────────────┘ └────────────┘ └────────────────────┘ + ┌────────────────────────────────┐ Test (i < 1000,false) ┌─────┐ Ret (Some 0, main) ┌─────┐ + ┌──────────────────▶ │ 123 │ ────────────────────────────────────────────▶ │ 125 │ ────────────────────▶ │ 126 │ + │ └────────────────────────────────┘ └─────┘ └─────┘ │ │ │ │ Test (i < 1000,true) │ ▼ - │ ┌─────────────────────────────────┐ - │ │ s12(9)[63] │ ─┐ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(i < 2000)' │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ │ fun299__VERIFIER_assert(69)[66] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ s0(69)[66] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ │ s3(69)[72] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - │ │ ret299__VERIFIER_assert(69)[7] │ │ - │ └─────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌─────────────────────────────────┐ │ - └─────────────────── │ s13(9)[63] │ ◀┘ - └─────────────────────────────────┘ + │ ┌────────────────────────────────┐ + │ │ 124 │ ─┐ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(i < 2000)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 120 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ Assign 'i = i + 1' │ 121 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 118 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 119 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └─────────────────── │ 122 │ ◀┘ + └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/global_init_true-unreach-call.expected b/tests/sv-comp/basic/global_init_true-unreach-call.expected index deb1222b45..1a4bb724e4 100644 --- a/tests/sv-comp/basic/global_init_true-unreach-call.expected +++ b/tests/sv-comp/basic/global_init_true-unreach-call.expected @@ -1,45 +1,45 @@ -┌─────────────────────────────────┐ -│ fun302main(12)[10] │ -└─────────────────────────────────┘ +┌────────────────────────────────┐ +│ 34 │ +└────────────────────────────────┘ │ │ Entry main ▼ -┌─────────────────────────────────┐ -│ s5(12)[10] │ ─┐ -└─────────────────────────────────┘ │ - │ │ - │ InlineEntry '(g == 1)' │ - ▼ │ -┌─────────────────────────────────┐ │ -│ fun298__VERIFIER_assert(18)[16] │ │ -└─────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ -┌─────────────────────────────────┐ │ -│ s0(18)[16] │ │ -└─────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(g == 1)' - ▼ │ -┌─────────────────────────────────┐ │ -│ s3(18)[16] │ │ -└─────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ -┌─────────────────────────────────┐ │ -│ ret298__VERIFIER_assert(18)[10] │ │ -└─────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ -┌─────────────────────────────────┐ │ -│ s6(12)[10] │ ◀┘ -└─────────────────────────────────┘ +┌────────────────────────────────┐ +│ 35 │ ─┐ +└────────────────────────────────┘ │ + │ │ + │ InlineEntry '(g == 1)' │ + ▼ │ +┌────────────────────────────────┐ │ +│ 40 │ │ +└────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ +┌────────────────────────────────┐ │ +│ 38 │ │ +└────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(g == 1)' + ▼ │ +┌────────────────────────────────┐ │ +│ 39 │ │ +└────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ +┌────────────────────────────────┐ │ +│ 41 │ │ +└────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ +┌────────────────────────────────┐ │ +│ 37 │ ◀┘ +└────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ -┌─────────────────────────────────┐ -│ ret302main(12)[25] │ -└─────────────────────────────────┘ +┌────────────────────────────────┐ +│ 36 │ +└────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_false-unreach-call.expected b/tests/sv-comp/basic/if_det_false-unreach-call.expected index c55b60aacd..c840d10f89 100644 --- a/tests/sv-comp/basic/if_det_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_false-unreach-call.expected @@ -1,39 +1,39 @@ -┌────────────────────────────────┐ -│ fun298main(9)[7] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 31 │ +└─────────────────────────┘ │ │ Entry main ▼ -┌────────────────────────────────┐ -│ s3(9)[11] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 32 │ +└─────────────────────────┘ │ │ Test (1,true) ▼ -┌────────────────────────────────┐ -│ s6(9)[11] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 33 │ +└─────────────────────────┘ │ │ Assign 'x = 1' ▼ -┌────────────────────────────────┐ -│ s7(9)[16] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 34 │ +└─────────────────────────┘ │ │ Test (x,true) ▼ -┌────────────────────────────────┐ -│ s9(9)[16] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 35 │ +└─────────────────────────┘ │ │ InlineEntry '()' ▼ -┌────────────────────────────────┐ -│ fun297__VERIFIER_error(23)[20] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 36 │ +└─────────────────────────┘ │ │ Entry __VERIFIER_error ▼ -┌────────────────────────────────┐ -│ s13(23)[20] │ -└────────────────────────────────┘ +┌─────────────────────────┐ +│ 37 │ +└─────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected index ce80d3a4a3..d95af858b5 100644 --- a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected @@ -1,27 +1,27 @@ ┌─────────────────────┐ -│ fun298main(9)[7] │ +│ 31 │ └─────────────────────┘ │ │ Entry main ▼ ┌─────────────────────┐ -│ s3(9)[11] │ ◀┐ +│ 32 │ ◀┐ └─────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌─────────────────────┐ │ -│ s6(9)[11] │ │ +│ 33 │ │ └─────────────────────┘ │ │ │ │ Assign 'x = -1' │ Test (x,false) ▼ │ ┌─────────────────────┐ │ -│ s7(9)[16] │ │ +│ 34 │ │ └─────────────────────┘ │ │ │ │ Assign 'x = x + 1' │ ▼ │ ┌─────────────────────┐ │ -│ s8(9)[19] │ ─┘ +│ 35 │ ─┘ └─────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_true-unreach-call.expected b/tests/sv-comp/basic/if_det_true-unreach-call.expected index 8e85590c66..2ad36188ce 100644 --- a/tests/sv-comp/basic/if_det_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_true-unreach-call.expected @@ -1,21 +1,21 @@ -┌──────────────────┐ -│ fun298main(9)[7] │ -└──────────────────┘ +┌─────────────────┐ +│ 27 │ +└─────────────────┘ │ │ Entry main ▼ -┌──────────────────┐ -│ s3(9)[11] │ ◀┐ -└──────────────────┘ │ - │ │ - │ Test (1,true) │ - ▼ │ -┌──────────────────┐ │ -│ s6(9)[11] │ │ Test (x,false) -└──────────────────┘ │ - │ │ - │ Assign 'x = 0' │ - ▼ │ -┌──────────────────┐ │ -│ s7(9)[16] │ ─┘ -└──────────────────┘ +┌─────────────────┐ +│ 28 │ ◀┐ +└─────────────────┘ │ + │ │ + │ Test (1,true) │ + ▼ │ +┌─────────────────┐ │ +│ 29 │ │ Test (x,false) +└─────────────────┘ │ + │ │ + │ Assign 'x = 0' │ + ▼ │ +┌─────────────────┐ │ +│ 30 │ ─┘ +└─────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_false-unreach-call.expected b/tests/sv-comp/basic/if_mod_false-unreach-call.expected index ee5fc89921..93a0a7f1e4 100644 --- a/tests/sv-comp/basic/if_mod_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_false-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────────────┐ - │ fun299main(9)[7] │ + │ 77 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌────────────────────▶ │ s3(9)[25] │ + ┌────────────────────▶ │ 78 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ s6(9)[25] │ ─┐ + │ │ 82 │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ fun298__VERIFIER_nondet_int(37)[34] │ │ + │ │ 83 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 50,false) │ s21(37)[49] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x >= 50,false) │ 79 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ ret298__VERIFIER_nondet_int(37)[52] │ │ + │ │ 80 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ s7(9)[25] │ ◀┘ + │ │ 81 │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp 00' │ ▼ │ ┌────────────────────────────────────────┐ - └───────────────────── │ s8(9)[28] │ + └───────────────────── │ 84 │ └────────────────────────────────────────┘ │ │ Test (x >= 50,true) ▼ ┌────────────────────────────────────────┐ - │ s10(9)[31] │ + │ 85 │ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ fun297__VERIFIER_error(37)[34] │ + │ 86 │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ s14(37)[34] │ + │ 87 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_true-unreach-call.expected b/tests/sv-comp/basic/if_mod_true-unreach-call.expected index ceb8b5b4e3..d73993ebe1 100644 --- a/tests/sv-comp/basic/if_mod_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_true-unreach-call.expected @@ -1,45 +1,69 @@ - ┌────────────────────────────────────────┐ - │ fun299main(9)[7] │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - ┌─────────────────────▶ │ s3(9)[25] │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Test (1,true) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ s6(9)[25] │ ─┐ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '()' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ fun298__VERIFIER_nondet_int(39)[36] │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_nondet_int │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 100,false) │ s21(39)[41] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ ret298__VERIFIER_nondet_int(39)[44] │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn 'tmp' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ s7(9)[25] │ ◀┘ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = tmp 00' - │ ▼ - │ ┌────────────────────────────────────────┐ - └────────────────────── │ s8(9)[28] │ - └────────────────────────────────────────┘ +┌───────────────────────────────────────────────┐ +│ 62 │ +└───────────────────────────────────────────────┘ + │ + │ Entry main + ▼ +┌───────────────────────────────────────────────┐ +│ 63 │ +└───────────────────────────────────────────────┘ + ▲ + │ Test (x >= 100,false) + │ +┌───────────────────────────────────────────────┐ +│ 68 │ +└───────────────────────────────────────────────┘ +┌───────────────────────────────────────────────┐ +│ 69 │ +└───────────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_nondet_int + ▼ +┌───────────────────────────────────────────────┐ +│ 70 │ +└───────────────────────────────────────────────┘ + │ + │ Ret (Some val, __VERIFIER_nondet_int) + ▼ +┌───────────────────────────────────────────────┐ +│ 75 │ +└───────────────────────────────────────────────┘ +┌───────────────────────────────────────────────┐ +│ 64 │ +└───────────────────────────────────────────────┘ + │ + │ InlineReturn 'tmp' + ▼ +┌───────────────────────────────────────────────┐ +│ 65 │ +└───────────────────────────────────────────────┘ + ▲ + │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ +┌───────────────────────────────────────────────┐ +│ 66 │ +└───────────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ +┌───────────────────────────────────────────────┐ +│ 67 │ +└───────────────────────────────────────────────┘ +┌───────────────────────────────────────────────┐ +│ 71 │ +└───────────────────────────────────────────────┘ + │ + │ Test (1,true) + ▼ +┌───────────────────────────────────────────────┐ +│ 72 │ +└───────────────────────────────────────────────┘ +┌───────────────────────────────────────────────┐ +│ 73 │ +└───────────────────────────────────────────────┘ + │ + │ Assign 'x = tmp 00' + ▼ +┌───────────────────────────────────────────────┐ +│ 74 │ +└───────────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected index e0f45cc4ef..0b061b2a64 100644 --- a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────────────┐ - │ fun299main(9)[7] │ + │ 79 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌──────────────▶ │ s3(9)[25] │ + ┌──────────────▶ │ 80 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ s6(9)[25] │ ─┐ + │ │ 84 │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ fun298__VERIFIER_nondet_int(49)[46] │ │ + │ │ 85 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x,false) │ s21(49)[51] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x,false) │ 81 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ ret298__VERIFIER_nondet_int(49)[54] │ │ + │ │ 82 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ s7(9)[25] │ ◀┘ + │ │ 83 │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp' │ ▼ │ ┌────────────────────────────────────────┐ - └─────────────── │ s8(9)[28] │ + └─────────────── │ 86 │ └────────────────────────────────────────┘ │ │ Test (x,true) ▼ ┌────────────────────────────────────────┐ - │ s10(9)[31] │ + │ 87 │ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ fun297__VERIFIER_error(37)[34] │ + │ 88 │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ s14(37)[34] │ + │ 89 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected index a9c9006399..9fd998e281 100644 --- a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected @@ -1,33 +1,39 @@ -┌──────────────────────────────┐ -│ fun298main(9)[7] │ -└──────────────────────────────┘ - │ - │ Entry main - ▼ -┌──────────────────────────────┐ -│ s3(9)[11] │ ◀┐ -└──────────────────────────────┘ │ - │ │ - │ Test (1,true) │ Test (x,false) - ▼ │ -┌──────────────────────────────┐ │ -│ s5(9)[11] │ ─┘ -└──────────────────────────────┘ - │ - │ Test (x,true) - ▼ -┌──────────────────────────────┐ -│ s7(9)[16] │ -└──────────────────────────────┘ - │ - │ InlineEntry '()' - ▼ -┌──────────────────────────────┐ -│ fun297__VERIFIER_error(9)[7] │ -└──────────────────────────────┘ - │ - │ Entry __VERIFIER_error - ▼ -┌──────────────────────────────┐ -│ s11(9)[7] │ -└──────────────────────────────┘ + ┌─────────────────────────┐ + │ 36 │ + └─────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────┐ + │ 37 │ + └─────────────────────────┘ + │ + │ Test (1,true) + ▼ + ┌─────────────────────────┐ + │ 38 │ + └─────────────────────────┘ +┌────┐ Test (x,false) ┌─────────────────────────┐ +│ 42 │ ◀──────────────── │ 41 │ +└────┘ └─────────────────────────┘ + │ + │ Test (x,true) + ▼ + ┌─────────────────────────┐ + │ 43 │ + └─────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌─────────────────────────┐ + │ 44 │ + └─────────────────────────┘ + ┌─────────────────────────┐ + │ 39 │ + └─────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌─────────────────────────┐ + │ 40 │ + └─────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected index 195ae9c8ea..426c2ea3c9 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected @@ -1,92 +1,114 @@ - - ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────────────┐ │ - │ │ fun302main(9)[7] │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┐ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 1)' - │ │ │ ▼ ▼ - │ ┌─────────────────────────────────┐ InlineEntry '(x != 1)' ┌──────────────────────┐ │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ fun299__VERIFIER_assert(40)[37] │ ◀──────────────────────── │ s19(9)[34] │ └────────────────────────────────────────▶ │ │ - │ └─────────────────────────────────┘ └──────────────────────┘ │ │ - │ │ ▲ InlineReturn │ │ InlineReturn - │ │ Entry __VERIFIER_assert ┌──────────────────────────┼────────────────────────────────────────────────────────────────▶ │ s7(9)[25] │ ◀─────────────────┐ - │ ▼ │ │ │ │ │ - │ ┌────────────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────┐ │ │ │ │ │ - │ │ s2(40)[45] │ ◀──────────────────── │ s0(40)[37] │ │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ - │ └────────────────────────────────┘ └─────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ │ - │ │ InlineEntry '()' │ Test (! cond,false) │ │ │ │ Test (1,true) │ │ - │ ▼ ▼ │ │ │ ▼ │ │ - │ ┌────────────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ fun297__VERIFIER_error(51)[48] │ │ s3(40)[43] │ │ │ │ │ s10(9)[25] │ ─┐ │ │ - │ └────────────────────────────────┘ └─────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ │ │ │ InlineEntry '()' │ │ │ - │ ▼ ▼ │ │ │ ▼ │ │ │ - │ ┌────────────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ s23(51)[48] │ │ ret299__VERIFIER_assert(40)[48] │ ─┘ │ │ │ fun298__VERIFIER_nondet_int(91)[88] │ │ │ │ - │ └────────────────────────────────┘ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - └─────────────────────────────────────────────────────────────┐ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ ▼ │ │ │ - │ │ Test (x == 2,false) │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x == 2)' │ s30(91)[93] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ ret298__VERIFIER_nondet_int(91)[96] │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ s11(9)[25] │ ◀┘ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Assign 'x = tmp' │ │ - │ │ │ ▼ │ │ - ┌─────────────────────────────────┐ Test (x == 0,true) │ │ ┌────────────────────────────────────────┐ │ │ - │ s14(9)[73] │ ◀───────────────────────────┼───────────────────────┼───────────────────────────────────────── │ s12(9)[28] │ │ InlineReturn │ - └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Test (x == 0,false) │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ └───────────────────────┼───────────────────────────────────────── │ s15(9)[31] │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Test (x == 2,true) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ └───────────────────────────────────────── │ s17(9)[59] │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x == 2)' │ │ - │ ▼ │ │ - │ InlineEntry '(x == 0)' ┌────────────────────────────────────────┐ │ │ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ fun299__VERIFIER_assert(65)[62] │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Entry __VERIFIER_assert │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ s0(65)[62] │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Test (! cond,false) │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ s3(65)[62] │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Ret (None, __VERIFIER_assert) │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ ret299__VERIFIER_assert(65)[48] │ ──────────────────────────────────────────────────┘ │ - └────────────────────────────────────────┘ │ - │ │ - └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 128 │ + └────────────────────────────────────────┘ + │ InlineReturn + │ Entry main ┌────────────────────────────────────────────────────────────────────────┐ + ▼ ▼ │ + InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 0)' ┌─────────────────────┐ │ + ┌────────────────────────────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ 144 │ ─┼────┐ + │ │ │ └─────────────────────┘ │ │ + │ Inlined Proc '__VERIFIER_assert(x == 2)' │ │ ▲ │ │ + │ ┌───────────────────────────────────────────────────────────────────▶ │ 129 │ │ Test (x == 0,true) │ │ + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ │ │ + │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Test (1,true) │ InlineReturn │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 136 │ ─┐ ┌────┼────────────────────────────────────────────┘ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 137 │ │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 148 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x != 1)' │ 146 │ │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 138 │ ◀┘ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Assign 'x = tmp' │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 142 │ ──────────────────────────────────────────────────┘ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ Test (x == 0,false) │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ 143 │ ─┐ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Test (x == 2,false) │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ └───────────────────────────────────────── │ 149 │ │ Test (x == 2,true) │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ + ┌────┼────┼───────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ └──────────────────────────────────────────────────────────────────── │ 135 │ ◀┘ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ │ InlineEntry '(x == 2)' │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ InlineEntry '(x == 0)' │ │ │ + │ │ │ 133 │ ◀──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼────┘ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 134 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 130 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────────────────────────────────────────────────────── │ 131 │ ───────────────────────────────────────────────────────┘ │ + │ └────────────────────────────────────────┘ │ + │ InlineEntry '(x != 1)' ┌────────────────────────────────────────┐ │ + └─────────────────────────────────────────────────────────────────────────────▶ │ 150 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌─────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ │ + │ 141 │ ◀────────────────────────────────────────── │ 139 │ │ + └─────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ + │ InlineEntry '()' │ Test (! cond,false) │ + ▼ ▼ │ + ┌─────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ 145 │ │ 140 │ │ + └─────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ + ▼ ▼ │ + ┌─────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ 132 │ │ 147 │ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + └─────────────────────────┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index a4e8e9cc8c..715bc56cf8 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -1,111 +1,132 @@ - - ┌───────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - ┌──────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ fun302main(9)[7] │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ ┌──────────────────────────────────────────────────────────────┘ │ Entry main │ Inlined Proc '__VERIFIER_assert(x == 0)' │ - │ │ ▼ ▼ │ - │ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ - │ ┌────┼────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ s17(9)[54] │ - │ │ │ │ │ └─────────────────────┘ - │ │ │ InlineReturn │ │ ▲ - │ │ │ ┌─────────────────────────────────────────────────────────────────────▶ │ s7(9)[25] │ │ Test (x == 2,true) - │ │ │ │ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ - │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Test (1,true) │ InlineReturn │ - │ │ │ │ │ ▼ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ │ │ s10(9)[25] │ ─┐ ┌────┼────────────────────────────────────────────┘ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineEntry '()' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ fun298__VERIFIER_nondet_int(87)[84] │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ InlineEntry '(x == 2)' │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ s37(87)[89] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ ret298__VERIFIER_nondet_int(87)[92] │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ s11(9)[25] │ ◀┘ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Assign 'x = tmp' │ │ - │ │ │ │ │ ▼ │ │ - │ │ ┌─────────────────────────────────┐ │ Test (x == 0,true) │ ┌────────────────────────────────────────┐ │ │ - │ │ │ s14(9)[69] │ ◀┼───────────────────────────┼────────────────────────────────────────── │ s12(9)[28] │ │ │ - │ │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ InlineEntry '(x == 0)' │ │ │ Test (x == 0,false) │ │ - │ │ ▼ │ │ ▼ │ │ - │ │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - └──────────────────────────┼▶ │ fun299__VERIFIER_assert(60)[57] │ │ │ │ s15(9)[31] │ ──────────────────────────────────────────────────┘ │ - │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ │ Test (x == 2,false) │ - │ ▼ │ │ ▼ │ - │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ s0(60)[57] │ │ │ │ s18(9)[34] │ │ - │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ Test (x != 0,true) │ - │ ▼ │ │ ▼ │ - │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ s3(60)[57] │ │ │ │ s19(9)[34] │ │ - │ └─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Test (x != 2,true) │ - │ ▼ │ │ ▼ │ - │ ┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - └─ │ ret299__VERIFIER_assert(60)[64] │ ─┘ │ │ s21(9)[34] │ │ - └─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'tmp___0 = 1' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - └────────────────────────────────────────── │ s26(9)[39] │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ fun299__VERIFIER_assert(45)[42] │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ s0(45)[42] │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ s3(45)[42] │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ ret299__VERIFIER_assert(45)[49] │ ───────────────────────────────────────────────────────┘ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 133 │ + └────────────────────────────────────────┘ + │ InlineReturn + │ Entry main ┌────────────────────────────────────────────────────────────────────────┐ + ▼ ▼ │ + InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 0)' ┌─────────────────────┐ │ + ┌───────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ 143 │ ─┼────┐ + │ │ │ └─────────────────────┘ │ │ + │ Inlined Proc '__VERIFIER_assert(x == 2)' │ │ ▲ │ │ + │ ┌──────────────────────────────────────────────▶ │ 134 │ │ Test (x == 0,true) │ │ + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ │ │ + │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Test (1,true) │ InlineReturn │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 138 │ ─┐ ┌────┼────────────────────────────────────────────┘ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 139 │ │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 149 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 150 │ │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 140 │ ◀┘ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ Assign 'x = tmp' │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 141 │ ──────────────────────────────────────────────────┘ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ Test (x == 0,false) │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ 142 │ ─┐ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Test (x == 2,false) │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 146 │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Test (x != 0,true) │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 147 │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Test (x != 2,true) │ Test (x == 2,true) │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 155 │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Assign 'tmp___0 = 1' │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ └────────────────────────────────────────── │ 151 │ │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ + ┌────┼────┼──────────────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ └─────────────────────────────────────────────── │ 137 │ ◀┘ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ │ InlineEntry '(x == 2)' │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ InlineEntry '(x == 0)' │ │ │ + │ │ │ 135 │ ◀──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼────┘ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 136 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 148 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ └──────────────────────────────────────────────────── │ 154 │ ───────────────────────────────────────────────────────┘ │ + │ └────────────────────────────────────────┘ │ + │ InlineEntry '(tmp___0)' ┌────────────────────────────────────────┐ │ + └────────────────────────────────────────────────────────▶ │ 152 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 144 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 145 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 153 │ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected index ff77d25120..68f5200bc8 100644 --- a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected @@ -1,81 +1,89 @@ - ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ fun302main(9)[7] │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry main │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x != 0)' - │ │ ▼ ▼ ▼ - │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ ┌────────────────────────────────────────▶ │ s7(9)[25] │ ◀┐ - │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ Test (1,true) │ - │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ │ s10(9)[25] │ ─┐ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ fun298__VERIFIER_nondet_int(66)[63] │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ s27(66)[68] │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ ret298__VERIFIER_nondet_int(66)[71] │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ s11(9)[25] │ ◀┘ │ - │ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ Assign 'x = tmp' │ InlineReturn - │ │ │ ▼ │ -┌─────────────────────────────────┐ │ Test (x == 0,false) │ ┌────────────────────────────────────────┐ │ -│ s16(9)[31] │ ◀┼────────────────────────────┼───────────────────────────────────────── │ s12(9)[28] │ │ -└─────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ InlineEntry '(x != 0)' │ │ │ Test (x == 0,true) │ - ▼ │ │ ▼ │ -┌─────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ -│ fun299__VERIFIER_assert(37)[34] │ │ └───────────────────────────────────────── │ s14(9)[45] │ │ -└─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ Entry __VERIFIER_assert │ │ InlineEntry '(x == 0)' │ - ▼ │ ▼ │ -┌─────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ -│ s0(37)[34] │ │ │ fun299__VERIFIER_assert(51)[48] │ │ -└─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ Test (! cond,false) │ │ Entry __VERIFIER_assert │ - ▼ │ ▼ │ -┌─────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ -│ s3(37)[34] │ │ │ s0(51)[48] │ │ -└─────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ Ret (None, __VERIFIER_assert) │ │ Test (! cond,false) │ - ▼ │ ▼ │ -┌─────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ -│ ret299__VERIFIER_assert(37)[41] │ ─┘ │ s3(51)[48] │ │ -└─────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ ret299__VERIFIER_assert(51)[41] │ ───────────────────────────────────────────────────────────────────────────────────────────────┘ - └────────────────────────────────────────┘ + ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + │ ┌───────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 104 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 0)' │ InlineReturn + │ │ ▼ ▼ ▼ + │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ ┌────────────────────────────────────────▶ │ 105 │ ◀┐ + │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ Test (1,true) │ + │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ + │ │ │ │ 110 │ ─┐ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ 111 │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ 106 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ 107 │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ 112 │ ◀┘ │ + │ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ Assign 'x = tmp' │ + │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ + │ │ │ │ 113 │ ─┐ │ InlineReturn + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Test (x == 0,true) │ │ + │ │ │ ▼ │ │ + ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ + ┌──────────────────────▶ │ 119 │ │ │ └───────────────────────────────────────── │ 115 │ ─┼────────────────────────────────────────────────┐ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ │ Test (x == 0,false) │ │ + │ ▼ │ │ │ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 117 │ │ └────────────────────────────────────────────── │ 114 │ ◀┘ │ │ + │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ InlineEntry '(x != 0)' │ │ + │ ▼ │ ▼ │ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ │ 118 │ │ │ 116 │ │ │ + │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ ▼ │ │ + │ InlineEntry '(x == 0)' ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ │ 120 │ ─┘ │ 108 │ │ │ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 109 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 121 │ ──────────────────────────────────────────────────┼────────────────┘ + │ └────────────────────────────────────────┘ │ + │ │ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index caabea159b..c3ea9afdb7 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -6,7 +6,7 @@ (target for_fun_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -21,7 +21,7 @@ (target for_odd_vesal_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -36,7 +36,7 @@ (target for_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -51,7 +51,7 @@ (target global_init_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -66,7 +66,7 @@ (target if_det_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -81,7 +81,7 @@ (target if_det_incr_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -96,7 +96,7 @@ (target if_det_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -111,7 +111,7 @@ (target if_mod_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -126,7 +126,7 @@ (target if_mod_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -141,7 +141,7 @@ (target if_nondet_fun_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -156,7 +156,7 @@ (target if_nondet_var_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -171,7 +171,7 @@ (target if_trier_exclude_multiple_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -186,7 +186,7 @@ (target if_trier_exclude_multiple_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -201,7 +201,7 @@ (target if_trier_exclude_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index 565044e809..7aa6602538 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -10,7 +10,7 @@ let generate_rule file = (target %s.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) (with-stdout-to %%{target} (run graph-easy --as=boxart arg.dot))))) (rule From 44991d3cad8cbf53d4b0cf49692e7de3e31127d3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 15 May 2024 17:41:47 +0300 Subject: [PATCH 162/689] Add other ARG tests --- .../builtin_expect_true-unreach-call.expected | 27 ++ .../cfg/free_spawn_true-unreach-call.expected | 87 ++++ .../free_spawn_ub_true-unreach-call.expected | 30 ++ .../cfg/join_true-unreach-call.expected | 99 +++++ ...ocal_shadow_fun_true-unreach-call.expected | 126 ++++++ ...ll_context_join_true-unreach-call.expected | 105 +++++ ...lticall_context_true-unreach-call.expected | 135 ++++++ .../multicall_join_true-unreach-call.expected | 99 +++++ ...all_nested_join_true-unreach-call.expected | 201 +++++++++ ...ulticall_nested_true-unreach-call.expected | 279 ++++++++++++ ..._return_context_true-unreach-call.expected | 171 ++++++++ .../cfg/multicall_true-unreach-call.expected | 47 ++ ...ion_global_init_true-unreach-call.expected | 99 +++++ .../cfg/uncil/and3_true-unreach-call.expected | 95 ++++ .../uncil/and3dead_true-unreach-call.expected | 95 ++++ .../uncil/and_copy_true-unreach-call.expected | 93 ++++ ..._join_invariant_true-unreach-call.expected | 93 ++++ .../cfg/uncil/and_true-unreach-call.expected | 87 ++++ .../uncil/and_var_false-unreach-call.expected | 81 ++++ .../uncil/and_var_true-unreach-call.expected | 75 ++++ .../cfg/uncil/or3_true-unreach-call.expected | 95 ++++ .../uncil/or3dead_true-unreach-call.expected | 95 ++++ .../cfg/uncil/or_true-unreach-call.expected | 87 ++++ tests/sv-comp/dune | 12 +- tests/sv-comp/dune.inc | 405 ++++++++++++++++++ .../eq/eq_double_true-unreach-call.expected | 141 ++++++ .../eq/eq_single_true-unreach-call.expected | 75 ++++ .../eq/multivar_false-unreach-call1.expected | 90 ++++ .../eq/multivar_true-unreach-call1.expected | 90 ++++ 29 files changed, 3213 insertions(+), 1 deletion(-) create mode 100644 tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/free_spawn_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/join_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_context_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_join_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/multicall_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/region_global_init_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected create mode 100644 tests/sv-comp/cfg/uncil/or_true-unreach-call.expected create mode 100644 tests/sv-comp/eq/eq_double_true-unreach-call.expected create mode 100644 tests/sv-comp/eq/eq_single_true-unreach-call.expected create mode 100644 tests/sv-comp/eq/multivar_false-unreach-call1.expected create mode 100644 tests/sv-comp/eq/multivar_true-unreach-call1.expected diff --git a/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected b/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected new file mode 100644 index 0000000000..5bbfc95f79 --- /dev/null +++ b/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected @@ -0,0 +1,27 @@ +┌───────────────────────────────────────────────┐ +│ 22 │ +└───────────────────────────────────────────────┘ + │ + │ Entry main + ▼ +┌───────────────────────────────────────────────┐ +│ 23 │ +└───────────────────────────────────────────────┘ + │ + │ Assign 'x = 0' + ▼ +┌───────────────────────────────────────────────┐ +│ 24 │ +└───────────────────────────────────────────────┘ + │ + │ Proc '__builtin_expect((long )(x == 0), 1L)' + ▼ +┌───────────────────────────────────────────────┐ +│ 25 │ +└───────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ +┌───────────────────────────────────────────────┐ +│ 26 │ +└───────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected new file mode 100644 index 0000000000..a37a63d9be --- /dev/null +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected @@ -0,0 +1,87 @@ + ┌────────────────────────────────────────┐ + │ 104 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 105 │ + └────────────────────────────────────────┘ + │ + │ Assign 'p = (void *)0' + ▼ + ┌────────────────────────────────────────┐ + │ 112 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 113 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 114 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 106 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 107 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp ' + ▼ + ┌────────────────────────────────────────┐ + │ 115 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x == 0,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌─────────────────── │ 116 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x == 1,false) │ Test (x == 0,true) + │ ▼ │ +┌─────┐ Test (x == -1,false) │ ┌────────────────────────────────────────┐ │ +│ 110 │ ◀─────────────────────────────────┼─────────────────── │ 118 │ │ +└─────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Test (x == 1,true) │ Test (x == -1,true) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ └──────────────────▶ │ 117 │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Proc 'tmp___0 = malloc(1)' + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 108 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'p = (void *)tmp___0' + │ ▼ + │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────┐ + └──────────────────────────────────────────────────────────▶ │ 109 │ + └────────────────────────────────────────┘ + │ + │ Proc 'free(p)' + ▼ + ┌────────────────────────────────────────┐ + │ 111 │ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 119 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected new file mode 100644 index 0000000000..3218aae4bc --- /dev/null +++ b/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected @@ -0,0 +1,30 @@ +┌───────────────────────────────────┐ +│ 22 │ +└───────────────────────────────────┘ + │ + │ Entry main + ▼ +┌───────────────────────────────────┐ +│ 23 │ +└───────────────────────────────────┘ + │ + │ Assign 'p = (void (*)())(& foo)' + ▼ +┌───────────────────────────────────┐ +│ 24 │ +└───────────────────────────────────┘ + │ + │ Proc 'free(p)' + ▼ +┌───────────────────────────────────┐ +│ 25 │ +└───────────────────────────────────┘ +┌───────────────────────────────────┐ +│ 26 │ +└───────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ +┌───────────────────────────────────┐ +│ 27 │ +└───────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected new file mode 100644 index 0000000000..eb7f3c2029 --- /dev/null +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -0,0 +1,99 @@ + ┌────────────────────────────────────────┐ + │ 76 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 77 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 78 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 79 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 92 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ +┌────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ +│ 82 │ ◀────────────────── │ 80 │ ◀┘ +└────┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 81 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 1' + │ ▼ + │ Assign 'x = 2' ┌────────────────────────────────────────┐ + └──────────────────────▶ │ 83 │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ 87 │ + └────────────────────────────────────────┘ + │ + │ Test (x <= 2,true) + ▼ + ┌────────────────────────────────────────┐ + │ 88 │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1' + ▼ + ┌────────────────────────────────────────┐ + │ 89 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 93 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 85 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 86 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 91 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 90 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 84 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected new file mode 100644 index 0000000000..a65f2f2886 --- /dev/null +++ b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected @@ -0,0 +1,126 @@ + + ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 159 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 160 │ ─┐ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 161 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_nondet_int │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 162 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 174 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn 'tmp' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ Assign 'i = i + 1' + │ │ 165 │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'n = tmp' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 172 │ ─┐ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(n)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 168 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry sum │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 169 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Assign 'sum___0 = 0' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 170 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Assign 'i = 0' │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ │ │ + │ │ 163 │ ◀──────────────────── │ 171 │ ◀┼────────────────────────────────────────────────┘ + │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) │ + │ ▼ ▼ │ + │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + └─ │ 164 │ │ 183 │ │ + └─────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some sum___0, sum) │ Inlined Proc 'tmp___0 = sum(n)' + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 182 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp___0' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 173 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 's = tmp___0' + ▼ + ┌────────────────────────────────────────┐ + │ 178 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(s >= 0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 176 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌─────────────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ │ + │ 184 │ ◀──────────────────── │ 177 │ │ + └─────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ + │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(s >= 0)' + ▼ ▼ │ + ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ 179 │ │ 175 │ │ + └─────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ + ▼ ▼ │ + ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ 180 │ │ 166 │ │ + └─────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 167 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 181 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected new file mode 100644 index 0000000000..f46cd151fa --- /dev/null +++ b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected @@ -0,0 +1,105 @@ + ┌────────────────────────────────────────┐ + │ 106 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 107 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 115 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 116 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 131 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌──────────────────────────────────────────── │ 117 │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,true) + │ ▼ +┌────────────────────────────────┐ InlineEntry '(1)' │ ┌────────────────────────────────────────┐ +│ 124 │ ◀────────────────────────────────────────────────┼──────────────────────────────────────────── │ 129 │ ──────────────────────────────────────────────────┐ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ + │ Entry foo │ Test (tmp,false) │ + ▼ │ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ 125 │ ─┐ └───────────────────────────────────────────▶ │ 110 │ ─┐ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ InlineEntry '(x - 1 < x)' │ │ InlineEntry '(2)' │ │ + ▼ │ ▼ │ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ +│ 130 │ │ │ 111 │ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ Entry __VERIFIER_assert │ │ Entry foo │ │ + ▼ │ ▼ │ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ +│ 121 │ │ ┌──────────────────────────────────────────── │ 127 │ │ │ +└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ │ InlineEntry '(x - 1 < x)' │ │ + ▼ │ │ ▼ │ │ +┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ +│ 122 │ │ │ │ 113 │ │ │ +└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ │ + ▼ │ │ ▼ │ │ +┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ +│ 128 │ │ │ │ 114 │ │ │ +└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ │ + ▼ │ │ ▼ │ │ +┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ +│ 120 │ ◀┘ │ │ 108 │ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ Ret (None, foo) │ │ Ret (None, __VERIFIER_assert) │ │ + ▼ │ ▼ │ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ +│ 119 │ │ │ 109 │ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineReturn │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────────────────────────▶ │ 126 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, foo) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 118 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ Inlined Proc 'foo(2)' │ Inlined Proc 'foo(1)' + │ ▼ ▼ ▼ + │ InlineReturn ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ 112 │ + └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 123 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected new file mode 100644 index 0000000000..ad86510bcd --- /dev/null +++ b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected @@ -0,0 +1,135 @@ + ┌────────────────────────────────┐ + │ 70 │ + └────────────────────────────────┘ + │ + │ Entry main + ▼ +┌────┐ Inlined Proc 'foo(1)' ┌────────────────────────────────┐ +│ 73 │ ◀───────────────────────────────────────────── │ 71 │ +└────┘ └────────────────────────────────┘ + │ + │ InlineEntry '(1)' + ▼ + ┌────────────────────────────────┐ + │ 72 │ + └────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 81 │ + └────────────────────────────────┘ + │ + │ Entry foo + ▼ + ┌────────────────────────────────┐ + │ 82 │ ─┐ + └────────────────────────────────┘ │ + │ │ + │ InlineEntry '(x - 1 < x)' │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 92 │ │ + └────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 77 │ │ + └────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' + ▼ │ + ┌────────────────────────────────┐ │ + │ 78 │ │ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 89 │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 79 │ ◀┘ + └────────────────────────────────┘ + │ + │ Ret (None, foo) + ▼ + ┌────────────────────────────────┐ + │ 80 │ + └────────────────────────────────┘ + │ + │ InlineReturn + ▼ + ┌────────────────────────────────┐ + │ 90 │ ─┐ + └────────────────────────────────┘ │ + │ │ + │ InlineEntry '(2)' │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 87 │ │ + └────────────────────────────────┘ │ + │ │ + │ Entry foo │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌──────────────────────────────────────────── │ 88 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(x - 1 < x)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 95 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 83 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(2)' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 84 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 93 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └───────────────────────────────────────────▶ │ 85 │ │ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, foo) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 86 │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 91 │ ◀┘ + └────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 74 │ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ 75 │ + └────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 76 │ + └────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 94 │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected new file mode 100644 index 0000000000..c01d4adf7b --- /dev/null +++ b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected @@ -0,0 +1,99 @@ + ┌────────────────────────────────────────┐ + │ 87 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 88 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 92 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 93 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 104 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ + ┌─ │ 89 │ ◀───────────────────────────────────────────── │ 94 │ ◀┘ + │ └────┘ └────────────────────────────────────────┘ + │ │ │ + │ │ │ Test (tmp,true) + │ │ ▼ + │ │ ┌────────────────────────────────────────┐ + │ │ │ 102 │ ─┐ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineEntry '(1)' │ + │ │ ▼ │ + │ │ InlineEntry '(1)' ┌────────────────────────────────────────┐ │ + │ └─────────────────────────────────────────────────▶ │ 90 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry foo │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ ┌──────────────────────────────────────────── │ 100 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineEntry '(x - 1 < x)' │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 103 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 97 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 98 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 101 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineReturn │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ └───────────────────────────────────────────▶ │ 96 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, foo) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 95 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ Inlined Proc 'foo(1)' ┌────────────────────────────────────────┐ │ + └──────────────────────────────────────────────────────▶ │ 91 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 99 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected new file mode 100644 index 0000000000..35502817fd --- /dev/null +++ b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected @@ -0,0 +1,201 @@ + + ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + ┌───────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ │ + │ │ Inlined Proc 'foo(x, 3)' │ │ + │ ┌─────────┼──────────────────────────────────────────────────────────────┐ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ ▼ ▼ │ │ │ + │ │ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ │ ┌────┼──────────────────────────────────────────────────────────▶ │ 269 │ │ │ 265 │ │ │ + │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ ▲ │ │ │ │ + │ │ │ └─────────────────────────────────┐ │ Ret (None, bar) │ Inlined Proc 'foo(x, 4)' │ │ Entry main │ │ + │ │ │ │ ▼ │ │ ▼ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ │ 296 │ ──────────────────────────────────────────────────┼────────────────────────────┘ │ 266 │ ─┐ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineEntry '()' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ InlineEntry '(x, 4)' │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ ┌───────────────────────────────────────────┼────┼──────────────────────────────────────┼────────────────────────▶ │ 299 │ │ │ 283 │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry foo │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ │ │ ▼ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ └───────────────────────── │ 292 │ │ │ 284 │ │ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ InlineEntry '(x < y)' │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ │ ▼ │ ▼ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ 293 │ │ │ 326 │ │ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ Entry __VERIFIER_assert │ │ InlineReturn 'tmp' │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ │ ▼ │ ▼ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ ┌─────────────────────────────────────────────────────────── │ 300 │ │ ┌───────────────────────────────────────────── │ 294 │ ◀┘ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ Test (tmp,true) │ │ + │ │ │ │ │ │ │ ▼ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ InlineEntry '(1)' │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ │ │ 325 │ ◀─────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 323 │ ────────────────────────────────────────────────────────────────────────────────────┐ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry bar │ │ Test (tmp,false) │ │ │ + │ │ │ │ │ ▼ │ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ 301 │ ─┐ │ └────────────────────────────────────────────▶ │ 315 │ ─┐ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineEntry '()' │ │ │ InlineEntry '(2)' │ │ │ │ + │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ │ 302 │ │ │ │ 313 │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ Entry bar │ │ │ │ + │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ │ 281 │ │ │ ┌───────────────────────────────────────────── │ 314 │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineEntry '()' │ │ │ │ + │ │ │ │ │ ▼ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ │ 282 │ │ │ │ │ 272 │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineReturn 'tmp' │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ + │ │ │ │ │ ▼ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ ┌───────────────────────── │ 289 │ ◀┘ │ │ │ 273 │ │ │ │ │ + │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ Test (tmp,false) │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ + │ │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ + │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ └───────────────────────────────────────────┼────┼────┼─────────────────────────────────┼───────────────────────── │ 298 │ ──────────────────────────────────────────────────┘ │ │ 322 │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ Test (tmp,true) │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ InlineReturn 'tmp' │ │ │ │ + │ │ │ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ └────────────────────────▶ │ 267 │ ─┐ └────────────────────────────────────────────▶ │ 317 │ ─┼────────────────────────────────────────────────┐ │ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ + │ ┌────────────────────────────────────────────────┼────┼────┘ │ InlineEntry '(x, 3)' │ │ Test (tmp,false) │ │ │ │ │ + │ │ │ │ ▼ │ ▼ │ │ │ │ │ + │ │ │ │ ┌────────────────────────────────┐ Entry foo ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ ┌───────────────────────────────────────────┼────┼─ │ 316 │ ◀────────────────────────── │ 268 │ │ ┌────────────────────────────────────────────────────────────────────────── │ 319 │ │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineEntry '(x < y)' ┌──────────────────────────────────────────────────────────────────────┘ │ ┌──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ ▼ │ │ │ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ Test (tmp,true) │ │ │ │ + │ │ │ │ │ │ 274 │ │ ┌────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 318 │ ◀─────────────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ │ InlineEntry '(x, 3)' │ │ │ + │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ 275 │ │ │ │ │ │ 290 │ │ │ │ + │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Test (! cond,false) │ │ │ │ │ Entry foo │ │ │ + │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ 270 │ │ │ │ │ │ 291 │ ─┐ │ │ │ + │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ │ InlineEntry '(x < y)' │ │ │ │ + │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ │ 271 │ │ │ │ │ │ 320 │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ InlineReturn │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ + │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ └───────────────────────────────────────────┼────┼▶ │ 311 │ │ │ │ │ │ 286 │ │ │ │ │ + │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ Ret (None, foo) │ │ │ │ │ Test (! cond,false) │ │ │ │ + │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ │ + │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ └─ │ 310 │ │ │ │ │ │ 287 │ │ │ │ │ + │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ └───────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ + │ │ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ │ 312 │ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ + │ │ │ │ │ ▼ │ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ │ │ 285 │ ◀┘ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Ret (None, foo) │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ 280 │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ InlineReturn │ │ + │ │ │ │ Inlined Proc 'foo(x, 4)' │ │ InlineReturn ┌─────────────────────────────────┼────────────────────────────────────────────────────────────────────────┼────┼────┐ + │ │ │ │ │ ▼ ▼ │ │ │ │ + │ │ │ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ + │ │ │ └────────────────────────────┼────────────────────────────────────────────▶ │ 279 │ ◀┼───────────────────────────────────────────┐ │ │ │ + │ │ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ Ret (None, bar) │ │ Inlined Proc 'foo(x, 3)' │ │ │ + │ │ │ │ ▼ │ │ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ │ 288 │ │ │ │ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ Inlined Proc 'bar(2)' │ InlineReturn │ Inlined Proc 'bar(1)' │ │ │ │ + │ │ │ │ ▼ │ │ │ │ │ + │ │ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ └────────────────────────────────────────────▶ │ 295 │ ◀┘ │ │ │ │ + │ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ ▲ InlineReturn │ │ │ │ + │ │ │ │ Ret (Some 0, main) └─────────────────────────────────────────────────────────────────────────────┼────────────────────────────┘ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ 306 │ │ ┌────┼────┘ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ │ + │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌────────────────────────────┘ │ + │ │ │ ▼ │ │ + │ │ Test (! cond,false) ┌────────────────────────────────────────┐ ┌───────────────────────────┐ │ ┌────────────────────────────────────────┐ ┌────────────────────────────────┐ ┌───────────────────────────┐ │ + │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ 297 │ │ 304 │ ─┘ │ 307 │ │ 305 │ │ 278 │ │ + │ └────────────────────────────────────────┘ └───────────────────────────┘ └────────────────────────────────────────┘ └────────────────────────────────┘ └───────────────────────────┘ │ + │ │ ▲ │ │ ▲ │ + │ │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ Entry foo │ Ret (None, __VERIFIER_assert) │ Ret (None, foo) │ + │ ▼ │ ▼ ▼ │ │ + │ ┌────────────────────────────────────────┐ ┌───────────────────────────┐ InlineEntry '(x < y)' ┌────────────────────────────────────────┐ ┌────────────────────────────────┐ InlineReturn ┌───────────────────────────┐ │ + │ │ 276 │ │ 324 │ ◀────────────────────────────────────────────── │ 308 │ ─┐ │ 321 │ ─────────────────────────────────────────▶ │ 303 │ │ + │ └────────────────────────────────────────┘ └───────────────────────────┘ └────────────────────────────────────────┘ │ └────────────────────────────────┘ └───────────────────────────┘ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x < y)' ▲ │ + │ │ InlineReturn └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x < y)' │ + │ │ 277 │ ◀──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Ret (None, foo) + │ ▼ + │ ┌────────────────────────────────────────┐ + └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ 309 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected new file mode 100644 index 0000000000..d0630b0424 --- /dev/null +++ b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected @@ -0,0 +1,279 @@ + ┌────────────────────────────────┐ + │ 156 │ + └────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────┐ + │ 157 │ ─┐ + └────────────────────────────────┘ │ + │ │ + │ InlineEntry '(1)' │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 170 │ │ + └────────────────────────────────┘ │ + │ │ + │ Entry bar │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌──────────────────────────────────────── │ 176 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(x, 3)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 177 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry foo │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 185 │ ─┼───────────────────────────────────────────┐ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x < y)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 200 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 183 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ Inlined Proc 'foo(x, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 184 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 198 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 182 │ ◀┼───────────────────────────────────────────┘ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, foo) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 168 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └───────────────────────────────────────▶ │ 169 │ ─┼───────────────────────────────────────────┐ + └────────────────────────────────┘ │ │ + │ │ │ + │ InlineEntry '(x, 4)' │ │ + ▼ │ │ + ┌────────────────────────────────┐ │ │ + │ 193 │ │ │ + └────────────────────────────────┘ │ │ + │ │ │ + │ Entry foo │ │ + ▼ │ │ + ┌────────────────────────────────┐ │ │ + ┌──────────────────────────────────────── │ 194 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x < y)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 202 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 190 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ Inlined Proc 'foo(x, 4)' + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 191 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 201 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + └───────────────────────────────────────▶ │ 192 │ │ │ + └────────────────────────────────┘ │ │ + │ │ │ + │ Ret (None, foo) │ │ + ▼ │ │ + ┌────────────────────────────────┐ │ │ + │ 166 │ │ │ + └────────────────────────────────┘ │ │ + │ │ │ + │ InlineReturn │ │ + ▼ │ │ + ┌────────────────────────────────┐ │ │ + │ 167 │ ◀┼───────────────────────────────────────────┘ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, bar) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 181 │ │ Inlined Proc 'bar(1)' + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌──────────────────────────────────────── │ 171 │ ◀┘ + │ └────────────────────────────────┘ + │ │ + │ │ InlineEntry '(2)' + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 174 │ + │ └────────────────────────────────┘ + │ │ + │ │ Entry bar + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 175 │ ─┐ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(x, 3)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 199 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry foo │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 161 │ ─┼───────────────────────────────────────────┐ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x < y)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 162 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 180 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 164 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 165 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 163 │ ◀┼───────────────────────────────────────────┘ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, foo) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 197 │ │ Inlined Proc 'foo(x, 3)' + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + ┌────────────────────────────┼──────────────────────────────────────── │ 158 │ ◀┘ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ │ InlineEntry '(x, 4)' + │ │ ▼ + │ │ ┌────────────────────────────────┐ + │ │ │ 159 │ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ │ Entry foo + │ │ ▼ + │ │ ┌────────────────────────────────┐ + │ │ │ 186 │ ─┐ + │ │ └────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineEntry '(x < y)' │ + │ │ ▼ │ + │ │ ┌────────────────────────────────┐ │ + │ │ │ 187 │ │ + │ │ └────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ + │ │ ▼ │ + │ │ ┌────────────────────────────────┐ │ + │ │ │ 189 │ │ + │ │ └────────────────────────────────┘ │ + │ │ │ │ + │ Inlined Proc 'foo(x, 4)' │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' + │ │ ▼ │ + │ │ ┌────────────────────────────────┐ │ + │ │ │ 188 │ │ + │ │ └────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────┐ │ + │ │ │ 172 │ │ + │ │ └────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineReturn │ + │ │ ▼ │ + │ │ ┌────────────────────────────────┐ │ + │ │ │ 173 │ ◀┘ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ │ Ret (None, foo) + │ │ ▼ + │ │ ┌────────────────────────────────┐ + │ │ │ 196 │ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ │ InlineReturn + │ │ ▼ + │ │ ┌────────────────────────────────┐ + └────────────────────────────┼───────────────────────────────────────▶ │ 160 │ + │ └────────────────────────────────┘ + │ │ + │ │ Ret (None, bar) + │ ▼ + │ ┌────────────────────────────────┐ + │ Inlined Proc 'bar(2)' │ 195 │ + │ └────────────────────────────────┘ + │ │ + │ │ InlineReturn + │ ▼ + │ ┌────────────────────────────────┐ + └───────────────────────────────────────▶ │ 178 │ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ 179 │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected new file mode 100644 index 0000000000..aef127c365 --- /dev/null +++ b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected @@ -0,0 +1,171 @@ + ┌────────────────────────────────┐ + │ 98 │ + └────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────┐ + │ 99 │ ─┐ + └────────────────────────────────┘ │ + │ │ + │ InlineEntry '(1)' │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 124 │ │ + └────────────────────────────────┘ │ + │ │ + │ Entry bar │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌───────────────────────── │ 107 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(1, 3)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 108 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry foo │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 112 │ ─┼────────────────────────────┐ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x < y)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 125 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 110 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ Inlined Proc 'foo(1, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 111 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 123 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 109 │ ◀┼────────────────────────────┘ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, foo) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 102 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └────────────────────────▶ │ 103 │ │ Inlined Proc 'bar(1)' + └────────────────────────────────┘ │ + │ │ + │ Ret (None, bar) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 120 │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌───────────────────────── │ 104 │ ◀┘ + │ └────────────────────────────────┘ + │ │ + │ │ InlineEntry '(2)' + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 105 │ + │ └────────────────────────────────┘ + │ │ + │ │ Entry bar + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 115 │ ─┐ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(1, 3)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 116 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry foo │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 121 │ ─┼────────────────────────────┐ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x < y)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 100 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 101 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ Inlined Proc 'bar(2)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 118 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 126 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 117 │ ◀┼────────────────────────────┘ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, foo) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 113 │ │ Inlined Proc 'foo(1, 3)' + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 114 │ ◀┘ + │ └────────────────────────────────┘ + │ │ + │ │ Ret (None, bar) + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 119 │ + │ └────────────────────────────────┘ + │ │ + │ │ InlineReturn + │ ▼ + │ ┌────────────────────────────────┐ + └────────────────────────▶ │ 106 │ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ 122 │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_true-unreach-call.expected new file mode 100644 index 0000000000..ad8c1df4e0 --- /dev/null +++ b/tests/sv-comp/cfg/multicall_true-unreach-call.expected @@ -0,0 +1,47 @@ + ┌────────────────────────────────┐ + │ 52 │ + └────────────────────────────────┘ + │ + ┌──────────────────────────────────────────────────┐ │ Entry main + │ │ ▼ + │ ┌──────────────────┐ InlineReturn ┌─────────────────────┐ Inlined Proc 'foo(1)' ┌────────────────────────────────┐ + │ │ 61 │ ───────────────────────▶ │ 55 │ ◀───────────────────────────────────────────── │ 53 │ + │ └──────────────────┘ └─────────────────────┘ └────────────────────────────────┘ + │ ▲ │ │ + │ │ Ret (None, foo) └──────────────────────┐ │ InlineEntry '(1)' + │ │ │ ▼ + │ │ Inlined Proc 'foo(1)' ┌─────────────────────┐ │ ┌────────────────────────────────┐ + └────┼─────────────────────────────────────────▶ │ 56 │ └───────────────────────────────────────────▶ │ 54 │ + │ └─────────────────────┘ └────────────────────────────────┘ + │ │ │ + │ │ Ret (Some 0, main) │ Entry foo + │ ▼ ▼ + │ ┌─────────────────────┐ ┌────────────────────────────────┐ InlineEntry '(x - 1 < x)' ┌────┐ + │ │ 57 │ │ 62 │ ───────────────────────────▶ │ 64 │ + │ └─────────────────────┘ └────────────────────────────────┘ └────┘ + │ │ │ + │ ┌───────────────────────────────────────────────┘ │ + │ │ │ + │ │ ┌────────────────────────────────┐ Entry __VERIFIER_assert │ + │ │ │ 58 │ ◀──────────────────────────────┘ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ │ Test (! cond,false) + │ │ ▼ + │ │ ┌────────────────────────────────┐ + │ │ │ 59 │ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) + │ │ ▼ + │ │ ┌────────────────────────────────┐ + │ │ │ 63 │ + │ │ └────────────────────────────────┘ + │ │ │ + │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ InlineReturn + │ │ ▼ + │ │ ┌────────────────────────────────┐ + │ └───────────────────────────────────────────▶ │ 60 │ + │ └────────────────────────────────┘ + │ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected new file mode 100644 index 0000000000..131d47879c --- /dev/null +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -0,0 +1,99 @@ + ┌────────────────────────────────────────┐ + │ 87 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 88 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 94 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 95 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 89 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ +┌────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ +│ 97 │ ◀────────────────── │ 90 │ ◀┘ +└────┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 96 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 1' + │ ▼ + │ Assign 'x = 2' ┌────────────────────────────────────────┐ + └──────────────────────▶ │ 98 │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ 102 │ + └────────────────────────────────────────┘ + │ + │ Test (x <= 2,true) + ▼ + ┌────────────────────────────────────────┐ + │ 103 │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1' + ▼ + ┌────────────────────────────────────────┐ + │ 91 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 92 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 100 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 101 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 104 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 93 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 99 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected new file mode 100644 index 0000000000..e2b68f50eb --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected @@ -0,0 +1,95 @@ + ┌────────────────────────────────────────┐ + │ 85 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 86 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 87 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 88 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 94 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 89 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 90 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0,true) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌─────────────────── │ 91 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x < 3,true) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 93 │ ─┼────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (x < 2,true) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + ┌────┼─────────────────── │ 99 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineEntry '(x == 1)' │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 100 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 96 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Test (x < 3,false) │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 97 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 98 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x < 2,false) + │ │ ▼ ▼ ▼ + │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ └──────────────────▶ │ 92 │ + │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ │ ▲ + │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 95 │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └─────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected new file mode 100644 index 0000000000..3dd83faf20 --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected @@ -0,0 +1,95 @@ + ┌────────────────────────────────────────┐ + │ 82 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 83 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 84 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 85 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 91 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 86 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 87 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0,true) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌─────────────────── │ 88 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x < 3,true) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 90 │ ─┼────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (x == 1,true) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + ┌────┼─────────────────── │ 96 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineEntry '(x == 1)' │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 97 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 93 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Test (x < 3,false) │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 94 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 95 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x == 1,false) + │ │ ▼ ▼ ▼ + │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ └──────────────────▶ │ 89 │ + │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ │ ▲ + │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 92 │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └─────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected new file mode 100644 index 0000000000..f953de97ab --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected @@ -0,0 +1,93 @@ + + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 99 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry main │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 100 │ ─┐ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ │ InlineEntry '()' │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 107 │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ Test (x < 2,false) │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 108 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 117 │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ │ InlineReturn 'tmp' │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 109 │ ◀┘ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Test (x > 0,false) │ Assign 'x = tmp' │ │ + │ ▼ ▼ │ │ + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ + └──────────────────▶ │ 113 │ ─┐ │ 110 │ ──────────────────────────────────────────────────┘ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ InlineEntry '(1)' │ │ Test (x > 0,true) │ + ▼ │ ▼ │ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ 119 │ │ │ 111 │ ───────────────────────────────────────────────────────┘ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ + │ │ │ + │ Entry __VERIFIER_assert │ │ Test (x < 2,true) + ▼ │ ▼ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ + │ 114 │ │ │ 112 │ ─┐ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(1)' │ InlineEntry '(x == 1)' │ + ▼ │ ▼ │ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ 115 │ │ │ 103 │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ + ▼ │ ▼ │ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ 118 │ │ │ 104 │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ InlineReturn │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' + ▼ │ ▼ │ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ 116 │ ◀┘ │ 101 │ │ + └────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 102 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 105 │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Ret (Some 0, main) + │ ▼ + │ Ret (Some 1, main) ┌────────────────────────────────────────┐ + └─────────────────────────────────────────────────────────────────────▶ │ 106 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected new file mode 100644 index 0000000000..e7f993a79e --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected @@ -0,0 +1,93 @@ + ┌────────────────────────────────────────┐ + │ 94 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 95 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 98 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 99 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 113 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 100 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 101 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0,true) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌────────────────── │ 104 │ │ Test (x > 0,false) + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x < 2,false) │ + │ ▼ │ +┌────────────────────────────────┐ InlineEntry '(1)' │ ┌────────────────────────────────────────┐ │ +│ 96 │ ◀──────────────────────┼────────────────── │ 106 │ ◀┘ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ + │ │ │ + │ Entry __VERIFIER_assert │ Test (x < 2,true) └─────────────────────────────────────────┐ + ▼ │ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ 97 │ └─────────────────▶ │ 105 │ ─┼────────────────────────────────────────────────┐ +└────────────────────────────────┘ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ Test (! cond,false) │ InlineEntry '(x == 1)' │ │ + ▼ ▼ │ │ +┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ +│ 110 │ │ 109 │ │ │ +└────────────────────────────────┘ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ │ + ▼ ▼ │ │ +┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ +│ 111 │ ───────────────────────┐ │ 102 │ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 103 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ InlineReturn │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 112 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(1)' │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ ▼ ▼ + │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + └─────────────────▶ │ 107 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 108 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected new file mode 100644 index 0000000000..a938376e1b --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected @@ -0,0 +1,87 @@ + ┌────────────────────────────────────────┐ + │ 75 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 76 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 77 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 78 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 85 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 79 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 80 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0,true) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌─────────────────── │ 82 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x < 2,true) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 83 │ ─┼────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x == 1)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 88 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ Test (x < 2,false) │ 86 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 87 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 89 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ Test (x > 0,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ ▼ ▼ + │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + └──────────────────▶ │ 84 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 81 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected new file mode 100644 index 0000000000..c3731e3731 --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -0,0 +1,81 @@ + ┌────────────────────────────────────────┐ + │ 96 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 97 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 102 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 103 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 110 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 104 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌─────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ + ┌──────────────────▶ │ 108 │ ◀────────────────────── │ 105 │ + │ └─────────────────────┘ └────────────────────────────────────────┘ + │ │ │ + │ Test (x < 2,false) │ │ Test (x > 0,true) + │ │ ▼ + │ │ ┌────────────────────────────────────────┐ + └──────────────────────┼──────────────────────────────────────────── │ 106 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (x < 2,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 107 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'tmp___0 = 1' + │ ▼ + │ Assign 'tmp___0 = 0' ┌────────────────────────────────────────┐ + └───────────────────────────────────────────▶ │ 109 │ + └────────────────────────────────────────┘ + │ + │ Assign 'y = tmp___0' + ▼ + ┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ + │ 100 │ ◀────────────────────── │ 111 │ + └─────────────────────┘ └────────────────────────────────────────┘ + │ │ + │ Ret (Some 0, main) │ Test (y,true) + ▼ ▼ + ┌─────────────────────┐ ┌────────────────────────────────────────┐ + │ 101 │ │ 112 │ + └─────────────────────┘ └────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌────────────────────────────────────────┐ + │ 98 │ + └────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌────────────────────────────────────────┐ + │ 99 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected new file mode 100644 index 0000000000..a30c746881 --- /dev/null +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -0,0 +1,75 @@ +┌────────────────────────────────────────┐ +│ 67 │ +└────────────────────────────────────────┘ + │ + │ Entry main + ▼ +┌────────────────────────────────────────┐ +│ 68 │ ─┐ +└────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ +┌────────────────────────────────────────┐ │ +│ 69 │ │ +└────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ +┌────────────────────────────────────────┐ │ +│ 70 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' +└────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ +┌────────────────────────────────────────┐ │ +│ 76 │ │ +└────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ +┌────────────────────────────────────────┐ │ +│ 72 │ ◀┘ +└────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ +┌────────────────────────────────────────┐ +│ 73 │ ─┐ +└────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0,true) │ + ▼ │ +┌────────────────────────────────────────┐ │ +│ 74 │ │ Test (x > 0,false) +└────────────────────────────────────────┘ │ + │ │ + │ Test (x < 0,false) │ + ▼ │ +┌────────────────────────────────────────┐ │ +│ 75 │ ◀┘ +└────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 0' + ▼ +┌────────────────────────────────────────┐ +│ 79 │ +└────────────────────────────────────────┘ + │ + │ Assign 'y = tmp___0' + ▼ +┌────────────────────────────────────────┐ +│ 77 │ +└────────────────────────────────────────┘ + │ + │ Test (y,false) + ▼ +┌────────────────────────────────────────┐ +│ 78 │ +└────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ +┌────────────────────────────────────────┐ +│ 71 │ +└────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected new file mode 100644 index 0000000000..f0b2b8a75e --- /dev/null +++ b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected @@ -0,0 +1,95 @@ + ┌────────────────────────────────────────┐ + │ 85 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 86 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 87 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 88 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 91 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 89 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 90 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌────────────────── │ 99 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x > 2,false) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 100 │ ─┼────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (x > 1,false) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + ┌────┼────────────────── │ 95 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineEntry '(x == 1)' │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 96 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 93 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Test (x > 2,true) │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 94 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 98 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x > 1,true) + │ │ ▼ ▼ ▼ + │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ └─────────────────▶ │ 97 │ + │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ │ ▲ + │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 92 │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected new file mode 100644 index 0000000000..9caf2c8722 --- /dev/null +++ b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected @@ -0,0 +1,95 @@ + ┌────────────────────────────────────────┐ + │ 82 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 83 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 84 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 85 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 88 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 86 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 87 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌────────────────── │ 96 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x > 2,false) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 97 │ ─┼────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (x != 1,false) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + ┌────┼────────────────── │ 92 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineEntry '(x == 1)' │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 93 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 90 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Test (x > 2,true) │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 91 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 95 │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x != 1,true) + │ │ ▼ ▼ ▼ + │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ └─────────────────▶ │ 94 │ + │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ │ ▲ + │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 89 │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected new file mode 100644 index 0000000000..936c7325ad --- /dev/null +++ b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected @@ -0,0 +1,87 @@ + ┌────────────────────────────────────────┐ + │ 75 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 76 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 77 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 78 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 82 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 79 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ 80 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌────────────────── │ 89 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x > 1,false) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 85 │ ─┼────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x == 1)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 86 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ Test (x > 1,true) │ 83 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 84 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 88 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ Test (x < 1,true) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ ▼ ▼ ▼ + │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + └─────────────────▶ │ 87 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 81 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/dune b/tests/sv-comp/dune index a2c0e60831..07a9f75d62 100644 --- a/tests/sv-comp/dune +++ b/tests/sv-comp/dune @@ -3,7 +3,17 @@ (rule (alias runtest) (mode promote) - (deps (:files (glob_files basic/*.c))) + (deps (:files + (glob_files basic/*.c) +(glob_files eq/*.c) +(glob_files cfg/multicall_*.c) +(glob_files cfg/join_true-unreach-call.c) +(glob_files cfg/builtin_expect_true-unreach-call.c) +(glob_files cfg/region_global_init_true-unreach-call.c) +(glob_files cfg/local_shadow_fun_true-unreach-call.c) +(glob_files cfg/free_spawn_*.c) +(glob_files cfg/uncil/*.c) + )) (action (with-stdout-to dune.inc (run gen/gen.exe %{files})))) diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index c3ea9afdb7..058f0115b4 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -208,4 +208,409 @@ (alias runtest) (action (diff if_trier_exclude_true-unreach-call.expected if_trier_exclude_true-unreach-call.output))) ) + + (subdir eq + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c eq_double_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target eq_double_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff eq_double_true-unreach-call.expected eq_double_true-unreach-call.output))) + ) + + (subdir eq + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c eq_single_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target eq_single_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff eq_single_true-unreach-call.expected eq_single_true-unreach-call.output))) + ) + + (subdir eq + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multivar_false-unreach-call1.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multivar_false-unreach-call1.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multivar_false-unreach-call1.expected multivar_false-unreach-call1.output))) + ) + + (subdir eq + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multivar_true-unreach-call1.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multivar_true-unreach-call1.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multivar_true-unreach-call1.expected multivar_true-unreach-call1.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_context_join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_context_join_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_context_join_true-unreach-call.expected multicall_context_join_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_context_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_context_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_context_true-unreach-call.expected multicall_context_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_join_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_join_true-unreach-call.expected multicall_join_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_nested_join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_nested_join_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_nested_join_true-unreach-call.expected multicall_nested_join_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_nested_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_nested_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_nested_true-unreach-call.expected multicall_nested_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_return_context_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_return_context_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_return_context_true-unreach-call.expected multicall_return_context_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c multicall_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff multicall_true-unreach-call.expected multicall_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target join_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff join_true-unreach-call.expected join_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c builtin_expect_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target builtin_expect_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff builtin_expect_true-unreach-call.expected builtin_expect_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c region_global_init_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target region_global_init_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff region_global_init_true-unreach-call.expected region_global_init_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c local_shadow_fun_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target local_shadow_fun_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff local_shadow_fun_true-unreach-call.expected local_shadow_fun_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c free_spawn_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target free_spawn_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff free_spawn_true-unreach-call.expected free_spawn_true-unreach-call.output))) + ) + + (subdir cfg + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c free_spawn_ub_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target free_spawn_ub_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff free_spawn_ub_true-unreach-call.expected free_spawn_ub_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and3_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and3_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and3_true-unreach-call.expected and3_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and3dead_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and3dead_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and3dead_true-unreach-call.expected and3dead_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and_copy_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_copy_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and_copy_true-unreach-call.expected and_copy_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and_join_invariant_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_join_invariant_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and_join_invariant_true-unreach-call.expected and_join_invariant_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and_true-unreach-call.expected and_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and_var_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_var_false-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and_var_false-unreach-call.expected and_var_false-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c and_var_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_var_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff and_var_true-unreach-call.expected and_var_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c or3_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target or3_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff or3_true-unreach-call.expected or3_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c or3dead_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target or3dead_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff or3dead_true-unreach-call.expected or3dead_true-unreach-call.output))) + ) + + (subdir cfg/uncil + (rule + (alias runtest) + (deps (sandbox always) (package goblint) (:c or_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target or_true-unreach-call.output) + (action + (progn + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (action (diff or_true-unreach-call.expected or_true-unreach-call.output))) + ) \ No newline at end of file diff --git a/tests/sv-comp/eq/eq_double_true-unreach-call.expected b/tests/sv-comp/eq/eq_double_true-unreach-call.expected new file mode 100644 index 0000000000..aa592b3eda --- /dev/null +++ b/tests/sv-comp/eq/eq_double_true-unreach-call.expected @@ -0,0 +1,141 @@ + ┌────────────────────────────────────────┐ + │ 143 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + InlineReturn ┌────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(a == b)' + ┌─────────────────────────────────────────────────────▶ │ 144 │ ◀─────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (1,true) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 157 │ ─┐ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 165 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_nondet_int │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 166 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 163 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn 'tmp' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 159 │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'x = tmp' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 160 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'y = x' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 147 │ ─┐ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x == y)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 148 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 162 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 161 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 158 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ ┌───────────────────────────────────────────────── │ 149 │ ◀┘ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineEntry '()' ┌────────────────────────────────────────────────┘ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 164 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Entry __VERIFIER_nondet_int │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ 154 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 155 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineReturn 'tmp___0' │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ └────────────────────────────────────────────────▶ │ 150 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + └────┐ │ Assign 'a = tmp___0' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 151 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'b = a' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 156 │ ─┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ InlineEntry '(a == b)' + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 152 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Entry __VERIFIER_assert + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 153 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (! cond,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 145 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Ret (None, __VERIFIER_assert) + │ ▼ + │ ┌────────────────────────────────────────┐ + └───────────────────────────────────────────────── │ 146 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/eq_single_true-unreach-call.expected b/tests/sv-comp/eq/eq_single_true-unreach-call.expected new file mode 100644 index 0000000000..f2a329738d --- /dev/null +++ b/tests/sv-comp/eq/eq_single_true-unreach-call.expected @@ -0,0 +1,75 @@ + ┌────────────────────────────────────────┐ + │ 80 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ InlineReturn + ┌────────────────────────────────────────▶ │ 81 │ ◀─────────────────────────────────────────────────┐ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (1,true) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 86 │ ─┐ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 87 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_nondet_int │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 90 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ Inlined Proc '__VERIFIER_assert(x == y)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 82 │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn 'tmp' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ 83 │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'x = tmp' ┌────────────────────────────────────────────────┘ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 88 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'y = x' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + └───────────────────────────────────────── │ 89 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(x == y)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 92 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 84 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 85 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 91 │ ─┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/multivar_false-unreach-call1.expected b/tests/sv-comp/eq/multivar_false-unreach-call1.expected new file mode 100644 index 0000000000..c01f6bfbc5 --- /dev/null +++ b/tests/sv-comp/eq/multivar_false-unreach-call1.expected @@ -0,0 +1,90 @@ + + ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌─────────────────────────────────────────┐ │ + │ │ 110 │ │ + │ └─────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌─────────────────────────────────────────┐ │ + │ │ 111 │ ─┐ │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 118 │ │ │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_nondet_uint │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 119 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 126 │ │ │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn 'tmp' │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 122 │ ◀┘ │ + │ └─────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'x = tmp' │ + │ ▼ │ + │ ┌─────────────────────────────────────────┐ │ + │ │ 123 │ │ + │ └─────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'y = x' │ + │ ▼ │ + │ ┌─────────────────────────┐ Test (x < 1024U,true) ┌─────────────────────────────────────────┐ Assign 'y = y + 1U' │ + │ │ 124 │ ◀─────────────────────── │ 129 │ ◀──────────────────────────────────────────────────┘ + │ └─────────────────────────┘ └─────────────────────────────────────────┘ + │ │ │ + │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) + │ ▼ ▼ + │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ + └─ │ 125 │ │ 128 │ ─┐ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(x < y)' │ + ▼ │ + ┌─────────────────────────────────────────┐ │ + │ 114 │ │ + └─────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ + │ 127 │ ◀─────────────────────── │ 115 │ │ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ │ + │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' + ▼ ▼ │ + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ + │ 120 │ │ 112 │ │ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ │ + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ + ▼ ▼ │ + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ + │ 121 │ │ 113 │ │ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌─────────────────────────────────────────┐ │ + │ 116 │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌─────────────────────────────────────────┐ + │ 117 │ + └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/multivar_true-unreach-call1.expected b/tests/sv-comp/eq/multivar_true-unreach-call1.expected new file mode 100644 index 0000000000..bfd9aa576f --- /dev/null +++ b/tests/sv-comp/eq/multivar_true-unreach-call1.expected @@ -0,0 +1,90 @@ + + ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌─────────────────────────────────────────┐ │ + │ │ 110 │ │ + │ └─────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌─────────────────────────────────────────┐ │ + │ │ 111 │ ─┐ │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 118 │ │ │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_nondet_uint │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 119 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 126 │ │ │ + │ └─────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn 'tmp' │ │ + │ ▼ │ │ + │ ┌─────────────────────────────────────────┐ │ │ + │ │ 122 │ ◀┘ │ + │ └─────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'x = tmp' │ + │ ▼ │ + │ ┌─────────────────────────────────────────┐ │ + │ │ 123 │ │ + │ └─────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'y = x' │ + │ ▼ │ + │ ┌─────────────────────────┐ Test (x < 1024U,true) ┌─────────────────────────────────────────┐ Assign 'y = y + 1U' │ + │ │ 124 │ ◀─────────────────────── │ 129 │ ◀──────────────────────────────────────────────────┘ + │ └─────────────────────────┘ └─────────────────────────────────────────┘ + │ │ │ + │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) + │ ▼ ▼ + │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ + └─ │ 125 │ │ 128 │ ─┐ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(x == y)' │ + ▼ │ + ┌─────────────────────────────────────────┐ │ + │ 114 │ │ + └─────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ + │ 127 │ ◀─────────────────────── │ 115 │ │ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ │ + │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' + ▼ ▼ │ + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ + │ 120 │ │ 112 │ │ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ │ + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ + ▼ ▼ │ + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ + │ 121 │ │ 113 │ │ + └─────────────────────────┘ └─────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌─────────────────────────────────────────┐ │ + │ 116 │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌─────────────────────────────────────────┐ + │ 117 │ + └─────────────────────────────────────────┘ From 889161995918736447ff54803286b26d040d88cb Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Wed, 15 May 2024 17:20:55 +0200 Subject: [PATCH 163/689] more accurate representation and canonicalization --- .../apron/linearTwoVarEqualityDomain.apron.ml | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index ffccecb05f..8fb799804f 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -17,20 +17,30 @@ open VectorMatrix module Mpqf = SharedFunctions.Mpqf module Rhs = struct - (* (Some i, k,_,_) represents a sum of a variable with index i and the number k. - (None, k,_,_) represents the number k. *) - type t = (int option * GobZ.t * GobZ.t * GobZ.t) [@@deriving eq, ord, hash] - let var_zero i = (Some i, Z.zero, Z.one, Z.one) + (* Rhs represents coefficient*var_i + offset / divisor + depending on whether coefficient is 0, the monomial term may disappear completely, not refering to any var_i, thus: + (Some (coefficient, i), offset, divisor ) with coefficient != 0 , or + (None , offset, divisor ) *) + type t = ((GobZ.t * int) option * GobZ.t * GobZ.t) [@@deriving eq, ord, hash] + let var_zero i = (Some (Z.one,i), Z.zero, Z.one) let show_coeff c = if Z.equal c Z.one then "" else (Z.to_string c) ^"*" let show_rhs_formatted formatter = function - | (Some v, o,coeff,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) - | (Some v, o,coeff,_) -> Printf.sprintf "%s%s%+Ld" (show_coeff coeff) (formatter v) (Z.to_int64 o) - | (None, o,_,_) -> Printf.sprintf "%Ld" (Z.to_int64 o) - let show (v,o,c,d) = - let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,c,d) in + | (Some (coeff,v), o,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) + | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s%+Ld" (show_coeff coeff) (formatter v) (Z.to_int64 o) + | (None, o,_) -> Printf.sprintf "%Ld" (Z.to_int64 o) + let show (v,o,d) = + let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,d) in if not (Z.equal d Z.one) then "(" ^ rhs ^ ")/" ^ (Z.to_string d) else rhs + + (** factor out gcd from all terms, i.e. ax=by+c is the canonical form for adx+bdy+cd *) + let canonicalize (v,o,d) = + let gcd = Z.gcd o d in + let gcd = match v with + | Some (c,_) -> Z.gcd c gcd + | None -> gcd + in (BatOption.map (fun (coeff,i) -> (Z.div coeff gcd,i)) v,Z.div o gcd, Z.div d gcd) end module EqualitiesConjunction = struct @@ -41,7 +51,7 @@ module EqualitiesConjunction = struct let show_formatted formatter econ = if IntMap.is_empty econ then "{}" else - let str = IntMap.fold (fun i (refvar,off,coeff,divi) acc -> Printf.sprintf "%s%s=%s ∧ %s" (Rhs.show_coeff divi) (formatter i) (Rhs.show_rhs_formatted formatter (refvar,off,coeff,divi)) acc) econ "" in + let str = IntMap.fold (fun i (ref,off,divi) acc -> Printf.sprintf "%s%s=%s ∧ %s" (Rhs.show_coeff divi) (formatter i) (Rhs.show_rhs_formatted formatter (ref,off,divi)) acc) econ "" in "{" ^ String.sub str 0 (String.length str - 4) ^ "}" let show econ = show_formatted (Printf.sprintf "var_%d") econ @@ -60,13 +70,18 @@ module EqualitiesConjunction = struct (** sparse implementation of get rhs for lhs, but will default to no mapping for sparse entries *) let get_rhs (_,econmap) lhs = IntMap.find_default (Rhs.var_zero lhs) lhs econmap - (** set_rhs, staying loyal to immutable, sparse map underneath *) + (** set_rhs, staying loyal to immutable, sparse map underneath; do not attempt any normalization *) let set_rhs (dim,map) lhs rhs = (dim, if Rhs.equal rhs Rhs.(var_zero lhs) then IntMap.remove lhs map else IntMap.add lhs rhs map ) + + (** canonicalize equation, and set_rhs, staying loyal to immutable, sparse map underneath,*) + let canonicalize_and_set (dim,map) lhs rhs = set_rhs (dim,map) lhs (Rhs.canonicalize rhs) + + (** add a new equality to the domain *) let copy = identity @@ -91,9 +106,9 @@ module EqualitiesConjunction = struct IntHashtbl.add h x r; r) in - let rec bumpentry k (refvar,offset,coeff,divi) = function (* directly bumps lhs-variable during a run through indexes, bumping refvar explicitely with a new lookup in indexes *) - | (tbl,delta,head::rest) when k>=head -> bumpentry k (refvar,offset,coeff,divi) (tbl,delta+1,rest) (* rec call even when =, in order to correctly interpret double bumps *) - | (tbl,delta,lyst) (* k (IntMap.add (op k delta) (BatOption.map (memobumpvar) refvar,offset,coeff,divi) tbl, delta, lyst) + let rec bumpentry k (refvar,offset,divi) = function (* directly bumps lhs-variable during a run through indexes, bumping refvar explicitely with a new lookup in indexes *) + | (tbl,delta,head::rest) when k>=head -> bumpentry k (refvar,offset,divi) (tbl,delta+1,rest) (* rec call even when =, in order to correctly interpret double bumps *) + | (tbl,delta,lyst) (* k (IntMap.add (op k delta) (BatOption.map (fun (c,v) -> (c,memobumpvar v)) refvar,offset,divi) tbl, delta, lyst) in let (a,_,_) = IntMap.fold bumpentry map (IntMap.empty,0,offsetlist) in (* Build new map during fold with bumped key/vals *) (op dim (Array.length indexes), a) @@ -116,22 +131,24 @@ module EqualitiesConjunction = struct (* Forget information about variable i *) let forget_variable d var = let res = - (let ref_var_opt = Tuple4.first (get_rhs d var) in + (let ref_var_opt = Tuple3.first (get_rhs d var) in match ref_var_opt with - | Some ref_var when ref_var = var -> + | Some (_,ref_var) when ref_var = var -> (* var is the reference variable of its connected component *) (let cluster = IntMap.fold - (fun i (ref,_,_,_) l -> if ref = ref_var_opt then i::l else l) (snd d) [] in + (fun i (ref,_,_) l -> if ref = ref_var_opt then i::l else l) (snd d) [] in (* obtain cluster with common reference variable ref_var*) match cluster with (* new ref_var is taken from head of the cluster *) | head :: _ -> (* ax = by + c /\ a'z = b'y + c' *) (* ==[[ y:=? ]]==> (a'b)z = (b'a)x + c' -(b'c) *) - let (_,c,b,a) = (get_rhs d head) in (* take offset between old and new reference variable *) + let (newref,c,a) = (get_rhs d head) in (* take offset between old and new reference variable *) + let (b,_) = BatOption.get newref in List.fold (fun map i -> - let (_,c',b',a') = (get_rhs d i) in - let newrhs = (Some head, Z.(c' - (b' * c)), Z.(b'*a), Z.(a'*b)) in - set_rhs map i newrhs + let (oldref,c',a') = (get_rhs d i) in + let (b',_) = BatOption.get oldref in + let newrhs = (Some (Z.(b'*a),head), Z.(c' - (b' * c)), Z.(a'*b)) in + canonicalize_and_set map i newrhs ) d cluster (* shift offset to match new reference variable *) | [] -> d) (* empty cluster means no work for us *) | _ -> d) (* variable is either a constant or expressed by another refvar *) in From 19c43f6f7e9b78cfe7fd0015f25b86e60743739e Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Wed, 15 May 2024 17:55:37 +0200 Subject: [PATCH 164/689] conversion to lincons --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 8fb799804f..6fa7d9423d 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -725,14 +725,14 @@ struct lincons in let get_const acc i = function - | (None, o) -> + | (None, o, d) -> let xi = Environment.var_of_dim t.env i in - of_coeff xi [(Coeff.s_of_int (-1), xi)] o :: acc - | (Some r, _) when r = i -> acc - | (Some r, o) -> + of_coeff xi [(Coeff.s_of_int (- (Z.to_int d)), xi)] o :: acc + | (Some (c,r), _,_) when r = i -> acc + | (Some (c,r), o, d) -> let xi = Environment.var_of_dim t.env i in let ri = Environment.var_of_dim t.env r in - of_coeff xi [(Coeff.s_of_int (-1), xi); (Coeff.s_of_int 1, ri)] o :: acc + of_coeff xi [(Coeff.s_of_int (- (Z.to_int d)), xi); (Coeff.s_of_int @@ Z.to_int c, ri)] o :: acc in BatOption.get t.d |> fun (_,map) -> EConj.IntMap.fold (fun lhs rhs list -> get_const list lhs rhs) map [] From 1d33e47df0728a252d28a2ba8c7049b1f65d01e7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 15 May 2024 18:38:44 +0200 Subject: [PATCH 165/689] Introduce `startcontext` --- src/analyses/abortUnless.ml | 1 + src/analyses/accessAnalysis.ml | 3 +++ src/analyses/activeSetjmp.ml | 1 + src/analyses/apron/relationAnalysis.apron.ml | 1 + src/analyses/base.ml | 2 ++ src/analyses/callstring.ml | 9 +++------ src/analyses/condVars.ml | 2 ++ src/analyses/expsplit.ml | 1 + src/analyses/extractPthread.ml | 2 ++ src/analyses/locksetAnalysis.ml | 1 + src/analyses/loopTermination.ml | 1 + src/analyses/loopfreeCallstring.ml | 9 ++------- src/analyses/mCP.ml | 8 ++++++++ src/analyses/mallocFresh.ml | 1 + src/analyses/malloc_null.ml | 1 + src/analyses/memLeak.ml | 1 + src/analyses/memOutOfBounds.ml | 2 ++ src/analyses/pthreadSignals.ml | 2 ++ src/analyses/region.ml | 2 ++ src/analyses/stackTrace.ml | 3 ++- src/analyses/symbLocks.ml | 1 + src/analyses/threadAnalysis.ml | 2 ++ src/analyses/threadEscape.ml | 1 + src/analyses/threadFlag.ml | 2 ++ src/analyses/threadId.ml | 2 ++ src/analyses/threadJoins.ml | 2 ++ src/analyses/threadReturn.ml | 2 ++ src/analyses/tutorials/signs.ml | 1 + src/analyses/tutorials/taint.ml | 5 +++++ src/analyses/tutorials/unitAnalysis.ml | 1 + src/analyses/uninit.ml | 1 + src/analyses/varEq.ml | 1 + src/analyses/wrapperFunctionAnalysis.ml | 1 + src/framework/analyses.ml | 7 +++---- src/framework/constraints.ml | 9 +++++++++ src/framework/control.ml | 8 ++++---- src/util/wideningTokens.ml | 1 + src/witness/observerAnalysis.ml | 2 ++ src/witness/witnessConstraints.ml | 4 +++- 39 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/analyses/abortUnless.ml b/src/analyses/abortUnless.ml index c3d91d2668..fb072a171a 100644 --- a/src/analyses/abortUnless.ml +++ b/src/analyses/abortUnless.ml @@ -64,6 +64,7 @@ struct let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = false + let startcontext () = () let startstate v = false let threadenter ctx ~multiple lval f args = [false] let threadspawn ctx ~multiple lval f args fctx = false diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index 5be31f0b0a..e2ea0a4aaa 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -52,6 +52,9 @@ struct ); if M.tracing then M.traceu "access" "access_one_top" + + let startcontext () = () + (** We just lift start state, global and dependency functions: *) let startstate v = () let threadenter ctx ~multiple lval f args = [()] diff --git a/src/analyses/activeSetjmp.ml b/src/analyses/activeSetjmp.ml index be13489993..47e7093e6b 100644 --- a/src/analyses/activeSetjmp.ml +++ b/src/analyses/activeSetjmp.ml @@ -24,6 +24,7 @@ struct D.add (Target entry) ctx.local | _ -> ctx.local + let startcontext () = D.top () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 10a721a0dc..3f569b1b08 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -46,6 +46,7 @@ struct else D.top () + let startcontext () = D.top () let exitstate _ = { rel = RD.top (); priv = Priv.startstate () } let startstate _ = { rel = RD.top (); priv = Priv.startstate () } diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 6fb9ffa25f..d69353ba44 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -79,6 +79,8 @@ struct type glob_diff = (V.t * G.t) list let name () = "base" + + let startcontext () = D.top () let startstate v: store = { cpa = CPA.bot (); deps = Dep.bot (); weak = WeakUpdates.bot (); priv = Priv.startstate ()} let exitstate v: store = { cpa = CPA.bot (); deps = Dep.bot (); weak = WeakUpdates.bot (); priv = Priv.startstate ()} diff --git a/src/analyses/callstring.ml b/src/analyses/callstring.ml index cb65011860..391f5f6657 100644 --- a/src/analyses/callstring.ml +++ b/src/analyses/callstring.ml @@ -47,14 +47,11 @@ struct let name () = "call_"^ CT.ana_name + let startcontext () = CallString.empty + let context ctx fd _ = - let curr_context = - try - ctx.context () - with Enter_func_has_no_context -> CallString.empty - in let elem = CT.new_ele fd ctx in (* receive element that should be added to call string *) - CallString.push curr_context elem + CallString.push (ctx.context ()) elem end (* implementations of CallstringTypes*) diff --git a/src/analyses/condVars.ml b/src/analyses/condVars.ml index 393be0a857..008fe074ef 100644 --- a/src/analyses/condVars.ml +++ b/src/analyses/condVars.ml @@ -60,6 +60,8 @@ struct module D = Domain module C = Domain + let startcontext () = D.top () + (* >? is >>=, |? is >> *) let (>?) = Option.bind diff --git a/src/analyses/expsplit.ml b/src/analyses/expsplit.ml index fef3d9ff9f..2f98052aa9 100644 --- a/src/analyses/expsplit.ml +++ b/src/analyses/expsplit.ml @@ -15,6 +15,7 @@ struct module D = MapDomain.MapBot (Basetype.CilExp) (ID) module C = D + let startcontext () = D.top () let startstate v = D.bot () let exitstate = startstate diff --git a/src/analyses/extractPthread.ml b/src/analyses/extractPthread.ml index 6cc347d511..5e61e823d5 100644 --- a/src/analyses/extractPthread.ml +++ b/src/analyses/extractPthread.ml @@ -1230,6 +1230,8 @@ module Spec : Analyses.MCPSpec = struct @@ List.cartesian_product cond_vars mutex_vars | _ -> ctx.local + + let startcontext () = D.top () let startstate v = let open D in make diff --git a/src/analyses/locksetAnalysis.ml b/src/analyses/locksetAnalysis.ml index 6a816b9e6c..59b97c3399 100644 --- a/src/analyses/locksetAnalysis.ml +++ b/src/analyses/locksetAnalysis.ml @@ -17,6 +17,7 @@ struct module D = D module C = D + let startcontext () = D.top () let startstate v = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] let exitstate v = D.empty () diff --git a/src/analyses/loopTermination.ml b/src/analyses/loopTermination.ml index ab768e235d..4f9987a705 100644 --- a/src/analyses/loopTermination.ml +++ b/src/analyses/loopTermination.ml @@ -37,6 +37,7 @@ struct end module G = MapDomain.MapBot (Statements) (BoolDomain.MustBool) + let startcontext () = () let startstate _ = () let exitstate = startstate diff --git a/src/analyses/loopfreeCallstring.ml b/src/analyses/loopfreeCallstring.ml index f5c9867e1f..d9760e58a0 100644 --- a/src/analyses/loopfreeCallstring.ml +++ b/src/analyses/loopfreeCallstring.ml @@ -42,13 +42,8 @@ struct in append fd (FundecSet.empty ()) [] current - let context ctx fd x = - let curr_context = - try - ctx.context () - with Enter_func_has_no_context -> [] - in - append fd curr_context + let startcontext () = [] + let context ctx fd x = append fd (ctx.context ()) end let _ = MCP.register_analysis (module Spec : MCPSpec) diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 5637b0b1cd..71c887dda5 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -117,6 +117,14 @@ struct let startstate v = map (fun (n,{spec=(module S:MCPSpec); _}) -> n, Obj.repr @@ S.startstate v) !activated let morphstate v x = map (fun (n,(module S:MCPSpec),d) -> n, Obj.repr @@ S.morphstate v (Obj.obj d)) (spec_list x) + let startcontext () = + filter_map (fun (n,{spec=(module S:MCPSpec); _}) -> + if Set.is_empty !act_cont_sens || not (Set.mem n !act_cont_sens) then (*n is insensitive*) + None + else + Some (n, Obj.repr @@ S.startcontext ()) + ) !activated + let rec assoc_replace (n,c) = function | [] -> failwith "assoc_replace" | (n',c')::xs -> if n=n' then (n,c)::xs else (n',c') :: assoc_replace (n,c) xs diff --git a/src/analyses/mallocFresh.ml b/src/analyses/mallocFresh.ml index ca14de0a3c..d3b141252c 100644 --- a/src/analyses/mallocFresh.ml +++ b/src/analyses/mallocFresh.ml @@ -14,6 +14,7 @@ struct let name () = "mallocFresh" + let startcontext () = D.top () let startstate _ = D.empty () let exitstate _ = D.empty () diff --git a/src/analyses/malloc_null.ml b/src/analyses/malloc_null.ml index f993db0c6e..30a76ba105 100644 --- a/src/analyses/malloc_null.ml +++ b/src/analyses/malloc_null.ml @@ -214,6 +214,7 @@ struct let name () = "malloc_null" + let startcontext () = D.top () let startstate v = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index 7c7cc7b16c..c76129c054 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -252,6 +252,7 @@ struct state | _ -> state + let startcontext () = D.top () let startstate v = D.bot () let exitstate v = D.top () diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index 3a763cdba3..e3c4a95c39 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -502,6 +502,8 @@ struct Option.iter (fun x -> check_lval_for_oob_access ctx x) lval; ctx.local + + let startcontext () = D.top () let startstate v = () let exitstate v = () end diff --git a/src/analyses/pthreadSignals.ml b/src/analyses/pthreadSignals.ml index 70f1624922..ec589a3eb7 100644 --- a/src/analyses/pthreadSignals.ml +++ b/src/analyses/pthreadSignals.ml @@ -72,6 +72,8 @@ struct ctx.local | _ -> ctx.local + + let startcontext () = D.top () let startstate v = Signals.empty () let threadenter ctx ~multiple lval f args = [ctx.local] let exitstate v = Signals.empty () diff --git a/src/analyses/region.ml b/src/analyses/region.ml index c2b40ff12f..1d62b6a71f 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -173,6 +173,8 @@ struct let startstate v = `Lifted (RegMap.bot ()) + let startcontext () = D.top () + let threadenter ctx ~multiple lval f args = [`Lifted (RegMap.bot ())] let threadspawn ctx ~multiple lval f args fctx = diff --git a/src/analyses/stackTrace.ml b/src/analyses/stackTrace.ml index dd2cedf871..70ca4bafb5 100644 --- a/src/analyses/stackTrace.ml +++ b/src/analyses/stackTrace.ml @@ -20,6 +20,7 @@ struct let combine_env ctx lval fexp f args fc au f_ask = ctx.local (* keep local as opposed to IdentitySpec *) + let startcontext () = D.top () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () @@ -41,7 +42,7 @@ struct let combine_env ctx lval fexp f args fc au f_ask = ctx.local (* keep local as opposed to IdentitySpec *) - + let startcontext () = D.top () let startstate v = D.bot () let exitstate v = D.top () diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 6fd18de6ff..ab7f877dc8 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -28,6 +28,7 @@ struct let name () = "symb_locks" + let startcontext () = D.top () let startstate v = D.top () let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index ed30e3633e..a7625c50f0 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -92,6 +92,8 @@ struct end | _ -> Queries.Result.top q + + let startcontext () = D.top () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = diff --git a/src/analyses/threadEscape.ml b/src/analyses/threadEscape.ml index fd7c564f2f..4a9a68c49e 100644 --- a/src/analyses/threadEscape.ml +++ b/src/analyses/threadEscape.ml @@ -161,6 +161,7 @@ struct D.join ctx.local escaped | _ -> ctx.local + let startcontext () = D.top () let startstate v = D.bot () let exitstate v = D.bot () diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index a751ae074a..8f7b3dad79 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -26,6 +26,8 @@ struct let name () = "threadflag" + + let startcontext () = D.top () let startstate v = Flag.bot () let exitstate v = Flag.get_multi () diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index ae9c8f5357..181d91ae78 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -60,6 +60,8 @@ struct let name () = "threadid" + let startcontext () = D.top () + let context ctx fd ((n,current,td) as d) = if GobConfig.get_bool "ana.thread.context.create-edges" then d diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index 160b123e78..848b988471 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -105,6 +105,8 @@ struct let (callee_joined, callee_clean) = au in (MustTIDs.union caller_joined callee_joined, local_clean && callee_clean) + + let startcontext () = D.top () let startstate v = (MustTIDs.empty (), true) let exitstate v = (MustTIDs.empty (), true) end diff --git a/src/analyses/threadReturn.ml b/src/analyses/threadReturn.ml index 0aed06851a..5987d43ab4 100644 --- a/src/analyses/threadReturn.ml +++ b/src/analyses/threadReturn.ml @@ -27,6 +27,8 @@ struct let combine_env ctx lval fexp f args fc au f_ask = ctx.local (* keep local as opposed to IdentitySpec *) + + let startcontext () = D.top () let startstate v = true let threadenter ctx ~multiple lval f args = [true] let exitstate v = D.top () diff --git a/src/analyses/tutorials/signs.ml b/src/analyses/tutorials/signs.ml index 2c26ad33b6..a6b3eafb41 100644 --- a/src/analyses/tutorials/signs.ml +++ b/src/analyses/tutorials/signs.ml @@ -53,6 +53,7 @@ struct module C = D let startstate v = D.bot () + let startcontext () = D.top () let exitstate = startstate include Analyses.IdentitySpec diff --git a/src/analyses/tutorials/taint.ml b/src/analyses/tutorials/taint.ml index 0193a423df..13ce92c62c 100644 --- a/src/analyses/tutorials/taint.ml +++ b/src/analyses/tutorials/taint.ml @@ -29,6 +29,11 @@ struct (* We are context insensitive in this analysis *) let context ctx _ _ = () + let startcontext () = () + + (* Queries *) + + (** Determines whether a variable [v] is tainted, given a [state]. *) (** Determines whether an expression [e] is tainted, given a [state]. *) let rec is_exp_tainted (state:D.t) (e:Cil.exp) = match e with diff --git a/src/analyses/tutorials/unitAnalysis.ml b/src/analyses/tutorials/unitAnalysis.ml index 319d0039ba..225767f010 100644 --- a/src/analyses/tutorials/unitAnalysis.ml +++ b/src/analyses/tutorials/unitAnalysis.ml @@ -38,6 +38,7 @@ struct let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = ctx.local + let startcontext () = () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/uninit.ml b/src/analyses/uninit.ml index 8693599a4d..ceaa946564 100644 --- a/src/analyses/uninit.ml +++ b/src/analyses/uninit.ml @@ -24,6 +24,7 @@ struct let name () = "uninit" + let startcontext () = D.top () let startstate v : D.t = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index f56d3487bb..e1061f7786 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -43,6 +43,7 @@ struct let name () = "var_eq" let startstate v = D.top () + let startcontext () = D.top () let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index 9510304e56..339f83f871 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -58,6 +58,7 @@ struct module D = Lattice.Prod (NodeFlatLattice) (UniqueCallCounter) module C = D + let startcontext () = D.top () let wrappers = Hashtbl.create 13 diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index ae93d863c1..835c5c2aac 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -171,11 +171,8 @@ type ('d,'g,'c,'v) ctx = exception Ctx_failure of string (** Failure from ctx, e.g. global initializer *) -exception Enter_func_has_no_context -(** Tried to call ctx() on enter_func. Caught by callstring-based approaches and turned into an initial context *) let ctx_failwith s = raise (Ctx_failure s) (* TODO: use everywhere in ctx *) -let enter_func_has_no_context () = raise Enter_func_has_no_context (** Convert [ctx] to [Queries.ask]. *) let ask_of_ctx ctx: Queries.ask = { Queries.f = ctx.ask } @@ -209,7 +206,8 @@ sig val morphstate : varinfo -> D.t -> D.t val exitstate : varinfo -> D.t - val context : (D.t, G.t, C.t, V.t) ctx -> fundec -> D.t -> C.t + val context: (D.t, G.t, C.t, V.t) ctx -> fundec -> D.t -> C.t + val startcontext: unit -> C.t val sync : (D.t, G.t, C.t, V.t) ctx -> [`Normal | `Join | `Return] -> D.t val query : (D.t, G.t, C.t, V.t) ctx -> 'a Queries.t -> 'a Queries.result @@ -424,6 +422,7 @@ module IdentityUnitContextsSpec = struct module C = Printable.Unit let context ctx _ _ = () + let startcontext () = () end module type SpecSys = diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 32b2eaa98f..07180d54dd 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -49,6 +49,7 @@ struct } let context ctx fd = S.context (conv ctx) fd % D.unlift + let startcontext () = S.startcontext () let sync ctx reason = D.lift @@ S.sync (conv ctx) reason @@ -129,6 +130,7 @@ struct { ctx with context = (fun () -> C.unlift (ctx.context ())) } let context ctx fd = C.lift % S.context (conv ctx) fd + let startcontext () = C.lift @@ S.startcontext () let sync ctx reason = S.sync (conv ctx) reason @@ -230,6 +232,7 @@ struct } let context ctx fd (d,_) = S.context (conv ctx) fd d + let startcontext () = S.startcontext () let lift_fun ctx f g h = f @@ h (g (conv ctx)) @@ -375,6 +378,7 @@ struct let inj f x = f x, M.bot () + let startcontext () = S.startcontext () let startstate = inj S.startstate let exitstate = inj S.exitstate let morphstate v (d,m) = S.morphstate v d, m @@ -455,6 +459,8 @@ struct let init = S.init let finalize = S.finalize + + let startcontext () = S.startcontext () let startstate v = `Lifted (S.startstate v) let exitstate v = `Lifted (S.exitstate v) let morphstate v d = try `Lifted (S.morphstate v (D.unlift d)) with Deadcode -> d @@ -540,6 +546,8 @@ struct let init = S.init let finalize = S.finalize + + let startcontext () = Some (S.startcontext ()) let name () = S.name ()^" with context gas" let startstate v = S.startstate v, get_int "ana.context.gas_value" let exitstate v = S.exitstate v, get_int "ana.context.gas_value" @@ -1149,6 +1157,7 @@ struct let init = Spec.init let finalize = Spec.finalize + let startcontext () = Spec.startcontext () let exitstate v = D.singleton (Spec.exitstate v) let startstate v = D.singleton (Spec.startstate v) let morphstate v d = D.map (Spec.morphstate v) d diff --git a/src/framework/control.ml b/src/framework/control.ml index 2054a750d4..de849749bc 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -404,8 +404,8 @@ struct ; emit = (fun _ -> failwith "Cannot \"emit\" in enter_with context.") ; node = MyCFG.dummy_node ; prev_node = MyCFG.dummy_node - ; control_context = enter_func_has_no_context - ; context = enter_func_has_no_context + ; control_context = (fun () -> ctx_failwith "enter_with has no control_context.") + ; context = Spec.startcontext ; edge = MyCFG.Skip ; local = st ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) @@ -463,8 +463,8 @@ struct ; emit = (fun _ -> failwith "Cannot \"emit\" in enter_with context.") ; node = MyCFG.dummy_node ; prev_node = MyCFG.dummy_node - ; control_context = enter_func_has_no_context - ; context = enter_func_has_no_context + ; control_context = (fun () -> ctx_failwith "enter_with has no control_context.") + ; context = Spec.startcontext ; edge = MyCFG.Skip ; local = e ; global = (fun g -> EQSys.G.spec (getg (EQSys.GVar.spec g))) diff --git a/src/util/wideningTokens.ml b/src/util/wideningTokens.ml index f8c508d411..41bb5d8477 100644 --- a/src/util/wideningTokens.ml +++ b/src/util/wideningTokens.ml @@ -134,6 +134,7 @@ struct } let context ctx fd = S.context (conv ctx) fd % D.unlift + let startcontext () = S.startcontext () let lift_fun ctx f g h = let new_tokens = ref (snd ctx.local) in (* New tokens not yet used during this transfer function, such that it is deterministic. *) diff --git a/src/witness/observerAnalysis.ml b/src/witness/observerAnalysis.ml index 58b5b31fe4..ec9f376b3c 100644 --- a/src/witness/observerAnalysis.ml +++ b/src/witness/observerAnalysis.ml @@ -33,6 +33,8 @@ struct module C = D module P = IdentityP (D) (* fully path-sensitive *) + let startcontext () = C.top () + let step d prev_node node = match d with | `Lifted q -> begin diff --git a/src/witness/witnessConstraints.ml b/src/witness/witnessConstraints.ml index 5e8e97d380..667562ef15 100644 --- a/src/witness/witnessConstraints.ml +++ b/src/witness/witnessConstraints.ml @@ -120,7 +120,7 @@ struct let step_ctx ctx x e = try step ctx.prev_node (ctx.context ()) x e (snd ctx.local) - with Ctx_failure _ | Enter_func_has_no_context -> + with Ctx_failure _ -> R.bot () let step_ctx_edge ctx x = step_ctx ctx x (CFGEdge ctx.edge) let step_ctx_inlined_edge ctx x = step_ctx ctx x (InlinedEdge ctx.edge) @@ -147,6 +147,8 @@ struct let x = Dom.choose_key l in Spec.context (conv ctx x) fd @@ x + let startcontext = Spec.startcontext + let map ctx f g = (* we now use Sync for every tf such that threadspawn after tf could look up state before tf *) let h x (xs, sync) = From 820391d33293d79ce6bfdab095f0203771b36d96 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 15 May 2024 18:54:18 +0200 Subject: [PATCH 166/689] Introduce `ValueContext` as helper --- src/analyses/abortUnless.ml | 2 +- src/analyses/accessAnalysis.ml | 4 +--- src/analyses/activeSetjmp.ml | 3 +-- src/analyses/apron/relationAnalysis.apron.ml | 3 +-- src/analyses/base.ml | 3 +-- src/analyses/condVars.ml | 4 +--- src/analyses/expsplit.ml | 3 +-- src/analyses/extractPthread.ml | 4 +--- src/analyses/locksetAnalysis.ml | 3 +-- src/analyses/loopTermination.ml | 4 ++-- src/analyses/mallocFresh.ml | 3 +-- src/analyses/malloc_null.ml | 3 +-- src/analyses/memLeak.ml | 3 +-- src/analyses/memOutOfBounds.ml | 4 +--- src/analyses/pthreadSignals.ml | 4 +--- src/analyses/region.ml | 5 ++--- src/analyses/stackTrace.ml | 7 ++----- src/analyses/symbLocks.ml | 3 +-- src/analyses/threadAnalysis.ml | 4 +--- src/analyses/threadEscape.ml | 3 +-- src/analyses/threadFlag.ml | 3 +-- src/analyses/threadId.ml | 4 +--- src/analyses/threadJoins.ml | 3 +-- src/analyses/threadReturn.ml | 4 +--- src/analyses/tutorials/signs.ml | 3 +-- src/analyses/uninit.ml | 3 +-- src/analyses/varEq.ml | 3 +-- src/analyses/wrapperFunctionAnalysis.ml | 3 +-- src/framework/analyses.ml | 5 +++++ src/witness/observerAnalysis.ml | 4 +--- 30 files changed, 37 insertions(+), 70 deletions(-) diff --git a/src/analyses/abortUnless.ml b/src/analyses/abortUnless.ml index fb072a171a..34d5b1a89b 100644 --- a/src/analyses/abortUnless.ml +++ b/src/analyses/abortUnless.ml @@ -14,6 +14,7 @@ struct module C = Printable.Unit let context ctx _ _ = () + let startcontext () = () (* transfer functions *) let assign ctx (lval:lval) (rval:exp) : D.t = @@ -64,7 +65,6 @@ struct let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t = false - let startcontext () = () let startstate v = false let threadenter ctx ~multiple lval f args = [false] let threadspawn ctx ~multiple lval f args fctx = false diff --git a/src/analyses/accessAnalysis.ml b/src/analyses/accessAnalysis.ml index e2ea0a4aaa..bf1892fdf0 100644 --- a/src/analyses/accessAnalysis.ml +++ b/src/analyses/accessAnalysis.ml @@ -14,7 +14,7 @@ struct let name () = "access" module D = Lattice.Unit - module C = Printable.Unit + include Analyses.ValueContexts(D) module V = struct @@ -53,8 +53,6 @@ struct if M.tracing then M.traceu "access" "access_one_top" - let startcontext () = () - (** We just lift start state, global and dependency functions: *) let startstate v = () let threadenter ctx ~multiple lval f args = [()] diff --git a/src/analyses/activeSetjmp.ml b/src/analyses/activeSetjmp.ml index 47e7093e6b..69db900d4c 100644 --- a/src/analyses/activeSetjmp.ml +++ b/src/analyses/activeSetjmp.ml @@ -10,7 +10,7 @@ struct let name () = "activeSetjmp" module D = JmpBufDomain.JmpBufSet - module C = JmpBufDomain.JmpBufSet + include Analyses.ValueContexts(D) module P = IdentityP (D) let combine_env ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask:Queries.ask): D.t = @@ -24,7 +24,6 @@ struct D.add (Target entry) ctx.local | _ -> ctx.local - let startcontext () = D.top () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 3f569b1b08..e9c21ae1a3 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -20,7 +20,7 @@ struct module Priv = Priv (RD) module D = RelationDomain.RelComponents (RD) (Priv.D) module G = Priv.G - module C = D + include Analyses.ValueContexts(D) module V = struct include Priv.V @@ -46,7 +46,6 @@ struct else D.top () - let startcontext () = D.top () let exitstate _ = { rel = RD.top (); priv = Priv.startstate () } let startstate _ = { rel = RD.top (); priv = Priv.startstate () } diff --git a/src/analyses/base.ml b/src/analyses/base.ml index d69353ba44..67e6276239 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -38,7 +38,7 @@ struct module Dom = BaseDomain.DomFunctor (Priv.D) (RVEval) type t = Dom.t module D = Dom - module C = Dom + include Analyses.ValueContexts(D) (* Two global invariants: 1. Priv.V -> Priv.G -- used for Priv @@ -80,7 +80,6 @@ struct let name () = "base" - let startcontext () = D.top () let startstate v: store = { cpa = CPA.bot (); deps = Dep.bot (); weak = WeakUpdates.bot (); priv = Priv.startstate ()} let exitstate v: store = { cpa = CPA.bot (); deps = Dep.bot (); weak = WeakUpdates.bot (); priv = Priv.startstate ()} diff --git a/src/analyses/condVars.ml b/src/analyses/condVars.ml index 008fe074ef..22b9db1cd4 100644 --- a/src/analyses/condVars.ml +++ b/src/analyses/condVars.ml @@ -58,9 +58,7 @@ struct let name () = "condvars" module D = Domain - module C = Domain - - let startcontext () = D.top () + include Analyses.ValueContexts(D) (* >? is >>=, |? is >> *) let (>?) = Option.bind diff --git a/src/analyses/expsplit.ml b/src/analyses/expsplit.ml index 2f98052aa9..46ec4774e5 100644 --- a/src/analyses/expsplit.ml +++ b/src/analyses/expsplit.ml @@ -13,9 +13,8 @@ struct let name () = "expsplit" module D = MapDomain.MapBot (Basetype.CilExp) (ID) - module C = D + include Analyses.ValueContexts(D) - let startcontext () = D.top () let startstate v = D.bot () let exitstate = startstate diff --git a/src/analyses/extractPthread.ml b/src/analyses/extractPthread.ml index 5e61e823d5..a61c54ab96 100644 --- a/src/analyses/extractPthread.ml +++ b/src/analyses/extractPthread.ml @@ -866,7 +866,7 @@ module Spec : Analyses.MCPSpec = struct (** Domains *) module D = PthreadDomain.D - module C = D + include Analyses.ValueContexts(D) (** Set of created tasks to spawn when going multithreaded *) module G = Tasks @@ -1230,8 +1230,6 @@ module Spec : Analyses.MCPSpec = struct @@ List.cartesian_product cond_vars mutex_vars | _ -> ctx.local - - let startcontext () = D.top () let startstate v = let open D in make diff --git a/src/analyses/locksetAnalysis.ml b/src/analyses/locksetAnalysis.ml index 59b97c3399..aad8e0119a 100644 --- a/src/analyses/locksetAnalysis.ml +++ b/src/analyses/locksetAnalysis.ml @@ -15,9 +15,8 @@ struct let name () = "lockset" module D = D - module C = D + include Analyses.ValueContexts(D) - let startcontext () = D.top () let startstate v = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] let exitstate v = D.empty () diff --git a/src/analyses/loopTermination.ml b/src/analyses/loopTermination.ml index 4f9987a705..66a50c17b7 100644 --- a/src/analyses/loopTermination.ml +++ b/src/analyses/loopTermination.ml @@ -30,14 +30,14 @@ struct let name () = "termination" module D = Lattice.Unit - module C = D + include Analyses.ValueContexts(D) + module V = struct include UnitV let is_write_only _ = true end module G = MapDomain.MapBot (Statements) (BoolDomain.MustBool) - let startcontext () = () let startstate _ = () let exitstate = startstate diff --git a/src/analyses/mallocFresh.ml b/src/analyses/mallocFresh.ml index d3b141252c..020046c678 100644 --- a/src/analyses/mallocFresh.ml +++ b/src/analyses/mallocFresh.ml @@ -10,11 +10,10 @@ struct (* must fresh variables *) module D = SetDomain.Reverse (SetDomain.ToppedSet (CilType.Varinfo) (struct let topname = "All variables" end)) (* need bot (top) for hoare widen *) - module C = D + include Analyses.ValueContexts(D) let name () = "mallocFresh" - let startcontext () = D.top () let startstate _ = D.empty () let exitstate _ = D.empty () diff --git a/src/analyses/malloc_null.ml b/src/analyses/malloc_null.ml index 30a76ba105..5e6225caac 100644 --- a/src/analyses/malloc_null.ml +++ b/src/analyses/malloc_null.ml @@ -13,7 +13,7 @@ struct module Addr = ValueDomain.Addr module D = ValueDomain.AddrSetDomain - module C = ValueDomain.AddrSetDomain + include Analyses.ValueContexts(D) module P = IdentityP (D) (* @@ -214,7 +214,6 @@ struct let name () = "malloc_null" - let startcontext () = D.top () let startstate v = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/memLeak.ml b/src/analyses/memLeak.ml index c76129c054..362800b7b4 100644 --- a/src/analyses/memLeak.ml +++ b/src/analyses/memLeak.ml @@ -14,7 +14,7 @@ struct let name () = "memLeak" module D = ToppedVarInfoSet - module C = D + include Analyses.ValueContexts(D) module P = IdentityP (D) module V = UnitV @@ -252,7 +252,6 @@ struct state | _ -> state - let startcontext () = D.top () let startstate v = D.bot () let exitstate v = D.top () diff --git a/src/analyses/memOutOfBounds.ml b/src/analyses/memOutOfBounds.ml index e3c4a95c39..914644a86e 100644 --- a/src/analyses/memOutOfBounds.ml +++ b/src/analyses/memOutOfBounds.ml @@ -20,7 +20,7 @@ struct include Analyses.IdentitySpec module D = Lattice.Unit - module C = D + include Analyses.ValueContexts(D) let context ctx _ _ = () @@ -502,8 +502,6 @@ struct Option.iter (fun x -> check_lval_for_oob_access ctx x) lval; ctx.local - - let startcontext () = D.top () let startstate v = () let exitstate v = () end diff --git a/src/analyses/pthreadSignals.ml b/src/analyses/pthreadSignals.ml index ec589a3eb7..68c2bf4f34 100644 --- a/src/analyses/pthreadSignals.ml +++ b/src/analyses/pthreadSignals.ml @@ -14,7 +14,7 @@ struct let name () = "pthreadSignals" module D = MustSignals - module C = MustSignals + include Analyses.ValueContexts(D) module G = SetDomain.ToppedSet (MHP) (struct let topname = "All Threads" end) let possible_vinfos (a: Queries.ask) cv_arg = @@ -72,8 +72,6 @@ struct ctx.local | _ -> ctx.local - - let startcontext () = D.top () let startstate v = Signals.empty () let threadenter ctx ~multiple lval f args = [ctx.local] let exitstate v = Signals.empty () diff --git a/src/analyses/region.ml b/src/analyses/region.ml index 1d62b6a71f..e53dded304 100644 --- a/src/analyses/region.ml +++ b/src/analyses/region.ml @@ -16,7 +16,8 @@ struct module D = RegionDomain.RegionDom module G = RegPart - module C = D + include Analyses.ValueContexts(D) + module V = struct include Printable.UnitConf (struct let name = "partitions" end) @@ -173,8 +174,6 @@ struct let startstate v = `Lifted (RegMap.bot ()) - let startcontext () = D.top () - let threadenter ctx ~multiple lval f args = [`Lifted (RegMap.bot ())] let threadspawn ctx ~multiple lval f args fctx = diff --git a/src/analyses/stackTrace.ml b/src/analyses/stackTrace.ml index 70ca4bafb5..56656c0639 100644 --- a/src/analyses/stackTrace.ml +++ b/src/analyses/stackTrace.ml @@ -2,7 +2,6 @@ open GoblintCil open Analyses -module LF = LibraryFunctions module Spec (D: StackDomain.S) (N: sig val name : string end)= struct @@ -10,7 +9,7 @@ struct let name () = N.name module D = D - module C = D + include Analyses.ValueContexts(D) (* transfer functions *) @@ -20,7 +19,6 @@ struct let combine_env ctx lval fexp f args fc au f_ask = ctx.local (* keep local as opposed to IdentitySpec *) - let startcontext () = D.top () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = [D.bot ()] let exitstate v = D.top () @@ -32,7 +30,7 @@ struct let name () = "stack_loc" module D = StackDomain.Dom3 - module C = StackDomain.Dom3 + include Analyses.ValueContexts(D) (* transfer functions *) @@ -42,7 +40,6 @@ struct let combine_env ctx lval fexp f args fc au f_ask = ctx.local (* keep local as opposed to IdentitySpec *) - let startcontext () = D.top () let startstate v = D.bot () let exitstate v = D.top () diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index ab7f877dc8..cafb8f5376 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -24,11 +24,10 @@ struct exception Top module D = LockDomain.Symbolic - module C = LockDomain.Symbolic + include Analyses.ValueContexts(D) let name () = "symb_locks" - let startcontext () = D.top () let startstate v = D.top () let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index a7625c50f0..07f46e915d 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -12,7 +12,7 @@ struct let name () = "thread" module D = ConcDomain.CreatedThreadSet - module C = D + include Analyses.ValueContexts(D) module G = ConcDomain.ThreadCreation module V = struct @@ -92,8 +92,6 @@ struct end | _ -> Queries.Result.top q - - let startcontext () = D.top () let startstate v = D.bot () let threadenter ctx ~multiple lval f args = diff --git a/src/analyses/threadEscape.ml b/src/analyses/threadEscape.ml index 4a9a68c49e..4311e72558 100644 --- a/src/analyses/threadEscape.ml +++ b/src/analyses/threadEscape.ml @@ -21,7 +21,7 @@ struct let name () = "escape" module D = EscapeDomain.EscapedVars - module C = EscapeDomain.EscapedVars + include Analyses.ValueContexts(D) module V = VarinfoV module G = ThreadIdSet @@ -161,7 +161,6 @@ struct D.join ctx.local escaped | _ -> ctx.local - let startcontext () = D.top () let startstate v = D.bot () let exitstate v = D.bot () diff --git a/src/analyses/threadFlag.ml b/src/analyses/threadFlag.ml index 8f7b3dad79..e1efcaaba5 100644 --- a/src/analyses/threadFlag.ml +++ b/src/analyses/threadFlag.ml @@ -19,7 +19,7 @@ struct module Flag = ThreadFlagDomain.Simple module D = Flag - module C = Flag + include Analyses.ValueContexts(D) module P = IdentityP (D) module V = UnitV module G = BoolDomain.MayBool @@ -27,7 +27,6 @@ struct let name () = "threadflag" - let startcontext () = D.top () let startstate v = Flag.bot () let exitstate v = Flag.get_multi () diff --git a/src/analyses/threadId.ml b/src/analyses/threadId.ml index 181d91ae78..80bab1ebf9 100644 --- a/src/analyses/threadId.ml +++ b/src/analyses/threadId.ml @@ -53,15 +53,13 @@ struct (** 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) (Created) - module C = D + include Analyses.ValueContexts(D) module P = IdentityP (D) let tids = ref (Hashtbl.create 20) let name () = "threadid" - let startcontext () = D.top () - let context ctx fd ((n,current,td) as d) = if GobConfig.get_bool "ana.thread.context.create-edges" then d diff --git a/src/analyses/threadJoins.ml b/src/analyses/threadJoins.ml index 848b988471..eddbe184da 100644 --- a/src/analyses/threadJoins.ml +++ b/src/analyses/threadJoins.ml @@ -19,7 +19,7 @@ struct (* The first component is the set of must-joined TIDs, the second component tracks whether all TIDs recorded in MustTIDs have been exited cleanly, *) (* i.e., all created subthreads have also been joined. This is helpful as there is no set of all transitively created threads available. *) module D = Lattice.Prod(MustTIDs)(CleanExit) - module C = D + include Analyses.ValueContexts(D) module G = D module V = struct @@ -106,7 +106,6 @@ struct (MustTIDs.union caller_joined callee_joined, local_clean && callee_clean) - let startcontext () = D.top () let startstate v = (MustTIDs.empty (), true) let exitstate v = (MustTIDs.empty (), true) end diff --git a/src/analyses/threadReturn.ml b/src/analyses/threadReturn.ml index 5987d43ab4..f3b9622b00 100644 --- a/src/analyses/threadReturn.ml +++ b/src/analyses/threadReturn.ml @@ -13,7 +13,7 @@ struct let name () = "threadreturn" module D = IntDomain.Booleans - module C = D + include Analyses.ValueContexts(D) (* transfer functions *) @@ -27,8 +27,6 @@ struct let combine_env ctx lval fexp f args fc au f_ask = ctx.local (* keep local as opposed to IdentitySpec *) - - let startcontext () = D.top () let startstate v = true let threadenter ctx ~multiple lval f args = [true] let exitstate v = D.top () diff --git a/src/analyses/tutorials/signs.ml b/src/analyses/tutorials/signs.ml index a6b3eafb41..28f7e0acdc 100644 --- a/src/analyses/tutorials/signs.ml +++ b/src/analyses/tutorials/signs.ml @@ -50,10 +50,9 @@ struct (* Map of integers variables to our signs lattice. *) module D = MapDomain.MapBot (Basetype.Variables) (SL) - module C = D + include Analyses.ValueContexts(D) let startstate v = D.bot () - let startcontext () = D.top () let exitstate = startstate include Analyses.IdentitySpec diff --git a/src/analyses/uninit.ml b/src/analyses/uninit.ml index ceaa946564..a385d0a1cd 100644 --- a/src/analyses/uninit.ml +++ b/src/analyses/uninit.ml @@ -15,7 +15,7 @@ struct module Addr = ValueDomain.Addr module D = ValueDomain.AddrSetDomain - module C = ValueDomain.AddrSetDomain + include Analyses.ValueContexts(D) module P = IdentityP (D) type trans_in = D.t @@ -24,7 +24,6 @@ struct let name () = "uninit" - let startcontext () = D.top () let startstate v : D.t = D.empty () let threadenter ctx ~multiple lval f args = [D.empty ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index e1061f7786..8ece99d6e8 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -38,12 +38,11 @@ struct ) ss (Invariant.top ()) end - module C = D + include Analyses.ValueContexts(D) let name () = "var_eq" let startstate v = D.top () - let startcontext () = D.top () let threadenter ctx ~multiple lval f args = [D.top ()] let threadspawn ctx ~multiple lval f args fctx = ctx.local let exitstate v = D.top () diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index 339f83f871..eb9ec6ce02 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -57,8 +57,7 @@ struct else remove unique_call counter |> add unique_call (count + 1) module D = Lattice.Prod (NodeFlatLattice) (UniqueCallCounter) - module C = D - let startcontext () = D.top () + include Analyses.ValueContexts(D) let wrappers = Hashtbl.create 13 diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 835c5c2aac..930793b60f 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -425,6 +425,11 @@ module IdentityUnitContextsSpec = struct let startcontext () = () end +module ValueContexts (D:Lattice.S) = struct + module C = D + let startcontext () = D.top () +end + module type SpecSys = sig module Spec: Spec diff --git a/src/witness/observerAnalysis.ml b/src/witness/observerAnalysis.ml index ec9f376b3c..490a51021a 100644 --- a/src/witness/observerAnalysis.ml +++ b/src/witness/observerAnalysis.ml @@ -30,11 +30,9 @@ struct let names x = "state " ^ string_of_int x end module D = Lattice.Flat (Printable.Chain (ChainParams)) - module C = D + include Analyses.ValueContexts(D) module P = IdentityP (D) (* fully path-sensitive *) - let startcontext () = C.top () - let step d prev_node node = match d with | `Lifted q -> begin From 5c2e7410da4d996ecdb255cdc0a00c5b4063242d Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Thu, 16 May 2024 09:25:08 +0200 Subject: [PATCH 167/689] [skip ci] generate coefficient-carrying monomials from texp --- .../apron/linearTwoVarEqualityDomain.apron.ml | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 6fa7d9423d..620dd307b2 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -223,14 +223,17 @@ struct let open Apron.Texpr1 in let exception NotLinearExpr in let exception ScalarIsInfinity in - let negate coeff_var_list = List.map (fun (coeff, var) -> (Z.(-coeff), var)) coeff_var_list in - let multiply_with_Z number coeff_var_list = - List.map (fun (coeff, var) -> (Z.(number * coeff, var))) coeff_var_list in + let negate coeff_var_list = List.map (function + | (Some(coeff,i),offs,divi) -> (Some(Z.neg coeff,i),Z.neg offs,divi) + | (None ,offs,divi) -> (None ,Z.neg offs,divi)) coeff_var_list in + let multiply_with_Z number divisor coeff_var_list = List.map (function + | (Some (coeff, var),offs,divi) -> Rhs.canonicalize (Some(Z.mul number coeff,var),Z.(number * offs),Z.mul divi divisor) + | (None,offs,divi) -> Rhs.canonicalize (None,Z.mul number offs,Z.mul divi divisor)) coeff_var_list in let multiply a b = (* if one of them is a constant, then multiply. Otherwise, the expression is not linear *) match a, b with - | [(a_coeff, None)], b -> multiply_with_Z a_coeff b - | a, [(b_coeff, None)] -> multiply_with_Z b_coeff a + | [(None,a_coeff, divi)], b -> multiply_with_Z a_coeff divi b + | a, [(None,b_coeff, divi)] -> multiply_with_Z b_coeff divi a | _ -> raise NotLinearExpr in let rec convert_texpr texp = @@ -239,16 +242,16 @@ struct | Cst (Interval _) -> failwith "constant was an interval; this is not supported" | Cst (Scalar x) -> begin match SharedFunctions.int_of_scalar ?round:None x with - | Some x -> [(x, None)] + | Some x -> [(None,x,Z.one)] | None -> raise ScalarIsInfinity end | Var x -> let var_dim = Environment.dim_of_var t.env x in begin match t.d with - | None -> [(Z.one, Some var_dim)] + | None -> [(Some (Z.one,var_dim),Z.zero,Z.one)] | Some d -> (match (EConj.get_rhs d var_dim) with - | (Some i, k) -> [(Z.one, Some i); (k, None)] - | (None, k) -> [(k, None)]) + | (Some (coeff,i), k,divi) -> [(Some (coeff,i),Z.zero,Z.one); (None,k,Z.one)] + | (None, k,divi) -> [ (None,k,Z.one)]) end | Unop (Neg, e, _, _) -> negate (convert_texpr e) | Unop (Cast, e, _, _) -> convert_texpr e (* Ignore since casts in apron are used for floating point nums and rounding in contrast to CIL casts *) From bedfb35f020372b1fb23d5adbf374037b0e3f340 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 12:38:43 +0300 Subject: [PATCH 168/689] Make arguments of function pointer type spawn --- src/util/library/libraryDsl.ml | 2 ++ src/util/library/libraryDsl.mli | 6 ++++++ src/util/library/libraryFunctions.ml | 19 +++++++++---------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/util/library/libraryDsl.ml b/src/util/library/libraryDsl.ml index 49aac8ce9b..64684fb1ce 100644 --- a/src/util/library/libraryDsl.ml +++ b/src/util/library/libraryDsl.ml @@ -102,3 +102,5 @@ let f = Access.{ kind = Free; deep = false; } let f_deep = Access.{ kind = Free; deep = true; } let s = Access.{ kind = Spawn; deep = false; } let s_deep = Access.{ kind = Spawn; deep = true; } +let c = Access.{ kind = Spawn; deep = false; } (* TODO: Sound, but very imprecise hack for calls to function pointers given as arguments. *) +let c_deep = Access.{ kind = Spawn; deep = true; } diff --git a/src/util/library/libraryDsl.mli b/src/util/library/libraryDsl.mli index fd0bc45c26..052f92c593 100644 --- a/src/util/library/libraryDsl.mli +++ b/src/util/library/libraryDsl.mli @@ -71,3 +71,9 @@ val s: LibraryDesc.Access.t (** Deep {!AccessKind.Spawn} access. Rarely needed. *) val s_deep: LibraryDesc.Access.t + +(** Shallow {!AccessKind.Spawn} access, substituting function pointer calls for now (TODO). *) +val c: LibraryDesc.Access.t + +(** Deep {!AccessKind.Spawn} access, substituting deep function pointer calls for now (TODO) *) +val c_deep: LibraryDesc.Access.t \ No newline at end of file diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index cdde23fece..71d34ead88 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -166,7 +166,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("raise", unknown [drop "sig" []]); (* safe-ish, we don't handle signal handlers for now *) ("timespec_get", unknown [drop "ts" [w]; drop "base" []]); ("signal", unknown [drop "signum" []; drop "handler" [s]]); - ("va_arg", unknown [drop "ap" [r_deep]; drop "T" []]); + ("va_arg", unknown [drop "ap" [r]; drop "T" []]); ("va_start", unknown [drop "ap" [r_deep]; drop "parmN" []]); ("va_end", unknown [drop "ap" [r_deep]]); ] @@ -432,7 +432,7 @@ let posix_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("stpcpy", unknown [drop "dest" [w]; drop "src" [r]]); ("dup", unknown [drop "oldfd" []]); ("readdir_r", unknown [drop "dirp" [r_deep]; drop "entry" [r_deep]; drop "result" [w]]); - ("scandir", unknown [drop "dirp" [r]; drop "namelist" [w]; drop "filter" [r]; drop "compar" [r]]); + ("scandir", unknown [drop "dirp" [r]; drop "namelist" [w]; drop "filter" [r; c]; drop "compar" [r; c]]); ("pipe", unknown [drop "pipefd" [w_deep]]); ("waitpid", unknown [drop "pid" []; drop "wstatus" [w]; drop "options" []]); ("strerror_r", unknown [drop "errnum" []; drop "buff" [w]; drop "buflen" []]); @@ -689,12 +689,12 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("clntudp_bufcreate", unknown [drop "addr" [r]; drop "prognum" []; drop "versnum" []; drop "wait" [r]; drop "sockp" [w]; drop "sendsize" []; drop "recosize" []]); ("svctcp_create", unknown [drop "sock" []; drop "send_buf_size" []; drop "recv_buf_size" []]); ("authunix_create_default", unknown []); - ("clnt_broadcast", unknown [drop "prognum" []; drop "versnum" []; drop "procnum" []; drop "inproc" [r]; drop "in" [w]; drop "outproc" [r]; drop "out" [w]; drop "eachresult" []]); + ("clnt_broadcast", unknown [drop "prognum" []; drop "versnum" []; drop "procnum" []; drop "inproc" [r; c]; drop "in" [w]; drop "outproc" [r; c]; drop "out" [w]; drop "eachresult" [c]]); ("clnt_sperrno", unknown [drop "stat" []]); ("pmap_unset", unknown [drop "prognum" []; drop "versnum" []]); ("svcudp_create", unknown [drop "sock" []]); - ("svc_register", unknown [drop "xprt" [r_deep; w_deep]; drop "prognum" []; drop "versnum" []; drop "dispatch" [r; w]; drop "protocol" []]); - ("svc_run", unknown []); + ("svc_register", unknown [drop "xprt" [r_deep; w_deep]; drop "prognum" []; drop "versnum" []; drop "dispatch" [r; w; c]; drop "protocol" []]); + ("svc_run", special [] Abort); (* RPC library end *) ] [@@coverage off] @@ -808,12 +808,12 @@ let linux_kernel_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__kmalloc", special [__ "size" []; drop "flags" []] @@ fun size -> Malloc size); ("kzalloc", special [__ "size" []; drop "flags" []] @@ fun size -> Calloc {count = Cil.one; size}); ("usb_alloc_urb", special [__ "iso_packets" []; drop "mem_flags" []] @@ fun iso_packets -> Malloc MyCFG.unknown_exp); - ("usb_submit_urb", unknown [drop "urb" [r_deep; w_deep]; drop "mem_flags" []]); (* old comment: first argument is written to but according to specification must not be read from anymore *) + ("usb_submit_urb", unknown [drop "urb" [r_deep; w_deep; c_deep]; drop "mem_flags" []]); (* old comment: first argument is written to but according to specification must not be read from anymore *) ("dev_driver_string", unknown [drop "dev" [r_deep]]); ("ioctl", unknown (drop "fd" [] :: drop "request" [] :: VarArgs (drop' [r_deep; w_deep]))); ("idr_pre_get", unknown [drop "idp" [r_deep]; drop "gfp_mask" []]); ("printk", unknown (drop "fmt" [r] :: VarArgs (drop' [r]))); - ("kmem_cache_create", unknown [drop "name" [r]; drop "size" []; drop "align" []; drop "flags" []; drop "ctor" [r]]); + ("kmem_cache_create", unknown [drop "name" [r]; drop "size" []; drop "align" []; drop "flags" []; drop "ctor" [r; c]]); ] [@@coverage off] @@ -1171,6 +1171,8 @@ let zlib_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("gzdopen", unknown [drop "fd" []; drop "mode" [r]]); ("gzread", unknown [drop "file" [r_deep; w_deep]; drop "buf" [w]; drop "len" []]); ("gzclose", unknown [drop "file" [f_deep]]); + ("uncompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []]); + ("compress2", unknown [drop "dest" [r]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "level" []]); ] [@@coverage off] @@ -1194,9 +1196,6 @@ let legacy_libs_misc_list: (string * LibraryDesc.t) list = LibraryDsl.[ (* bzlib *) ("BZ2_bzBuffToBuffCompress", unknown [drop "dest" []; drop "destLen" []; drop "source" [w]; drop "sourceLen" []; drop "blockSize100k" []; drop "verbosity" []; drop "workFactor" []]); ("BZ2_bzBuffToBuffDecompress", unknown [drop "dest" []; drop "destLen" []; drop "source" [w]; drop "sourceLen" []; drop "small" []; drop "verbosity" []]); - (* zlib (Zebedee) *) - ("uncompress", unknown [drop "dest" [w]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []]); - ("compress2", unknown [drop "dest" [r]; drop "destLen" [r; w]; drop "source" [r]; drop "sourceLen" []; drop "level" []]); (* opensssl blowfish *) ("BF_cfb64_encrypt", unknown [drop "in" [r]; drop "out" [w]; drop "length" []; drop "schedule" [r]; drop "ivec" [r; w]; drop "num" [r; w]; drop "enc" []]); ("BF_set_key", unknown [drop "key" [w]; drop "len" []; drop "data" [r]]); From bffb268677da2a64137f4d3f0560a025333de29d Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 12:59:35 +0300 Subject: [PATCH 169/689] Always enable base analysis for soundness for ValidFree and ValidDeref specs --- src/autoTuneSvompSpec.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index 5b44dcec0e..5cdde60fae 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -6,11 +6,11 @@ open AutoTune let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidFree -> (* Enable the useAfterFree analysis *) - let uafAna = ["useAfterFree"] in + let uafAna = ["base"; "useAfterFree"] in Logs.info "Specification: ValidFree -> enabling useAfterFree analysis \"%s\"" (String.concat ", " uafAna); enableAnalyses uafAna | ValidDeref -> (* Enable the memOutOfBounds analysis *) - let memOobAna = ["memOutOfBounds"] in + let memOobAna = ["base"; "memOutOfBounds"] in set_bool "ana.arrayoob" true; Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; set_bool "cil.addNestedScopeAttr" true; From 1f49f1410c690720b5c6d91f6b5130f7fe20b66c Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 13:47:07 +0300 Subject: [PATCH 170/689] Update comments and logs --- src/autoTuneSvompSpec.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index 5cdde60fae..eb422a6a36 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -5,21 +5,21 @@ open AutoTune let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with - | ValidFree -> (* Enable the useAfterFree analysis *) + | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) let uafAna = ["base"; "useAfterFree"] in - Logs.info "Specification: ValidFree -> enabling useAfterFree analysis \"%s\"" (String.concat ", " uafAna); + Logs.info "Specification: ValidFree -> enabling soundness analyses \"%s\"" (String.concat ", " uafAna); enableAnalyses uafAna - | ValidDeref -> (* Enable the memOutOfBounds analysis *) + | ValidDeref -> (* Enable the soundness analyses for ValidDeref spec *) let memOobAna = ["base"; "memOutOfBounds"] in set_bool "ana.arrayoob" true; Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; set_bool "cil.addNestedScopeAttr" true; - Logs.info "Specification: ValidDeref -> enabling memOutOfBounds analysis \"%s\"" (String.concat ", " memOobAna); - enableAnalyses memOobAna; + Logs.info "Specification: ValidDeref -> enabling soundness analyses \"%s\"" (String.concat ", " memOobAna); + enableAnalyses memOobAna | ValidMemtrack - | ValidMemcleanup -> (* Enable the memLeak analysis *) + | ValidMemcleanup -> (* Enable the soundness analyses for ValidMemtrack and ValidMemcleanup specs *) let memLeakAna = ["memLeak"] in - Logs.info "Specification: ValidMemtrack and ValidMemcleanup -> enabling memLeak analysis \"%s\"" (String.concat ", " memLeakAna); + Logs.info "Specification: ValidMemtrack and ValidMemcleanup -> enabling soundness analyses \"%s\"" (String.concat ", " memLeakAna); enableAnalyses memLeakAna | _ -> () From c3da0939b15e5a79f85b21053e0e999e155194e6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 13:52:52 +0300 Subject: [PATCH 171/689] Separate (soundness) analyses activated for termination specification --- src/autoTune.ml | 2 +- src/autoTuneSvompSpec.ml | 11 +++++++++++ src/goblint.ml | 1 + src/goblint_lib.ml | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 07251f9118..04e9872445 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -228,7 +228,7 @@ let focusOnMemSafetySpecification () = let focusOnTermination (spec: Svcomp.Specification.t) = match spec with | Termination -> - let terminationAnas = ["termination"; "threadflag"; "apron"] in + let terminationAnas = ["threadflag"; "apron"] in Logs.info "Specification: Termination -> enabling termination analyses \"%s\"" (String.concat ", " terminationAnas); enableAnalyses terminationAnas; set_string "sem.int.signed_overflow" "assume_none"; diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index eb422a6a36..09f7b04a8a 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -25,3 +25,14 @@ let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = let enableAnalysesForMemSafetySpecification () = List.iter enableAnalysesForMemSafetySpecification (Svcomp.Specification.of_option ()) + +let enableAnalysesForTerminationSpecification (spec: Svcomp.Specification.t) = + match spec with + | Termination -> (* Enable the soundness analyses for Termination spec *) + let terminationAna = ["termination"] in + Logs.info "Specification: Termination -> enabling soundness analyses \"%s\"" (String.concat ", " terminationAna); + enableAnalyses terminationAna + | _ -> () + +let enableAnalysesForTerminationSpecification () = + List.iter enableAnalysesForTerminationSpecification (Svcomp.Specification.of_option ()) diff --git a/src/goblint.ml b/src/goblint.ml index 24afae1597..c7c2dd6a76 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -36,6 +36,7 @@ let main () = Logs.debug "%s" (GobUnix.localtime ()); Logs.debug "%s" GobSys.command_line; (* When analyzing a termination specification, activate the termination analysis before pre-processing. *) + if get_string "ana.specification" <> "" then AutoTuneSvompSpec.enableAnalysesForTerminationSpecification (); if get_bool "ana.autotune.enabled" && AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 32e6fa0dbf..6fb8abb489 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -59,6 +59,7 @@ module GobConfig = GobConfig module AfterConfig = AfterConfig module AutoTune = AutoTune +module AutoTuneSvompSpec = AutoTuneSvompSpec module JsonSchema = JsonSchema module Options = Options From 6aaccdfce643b844b283313cde0358b87826103d Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 13:58:52 +0300 Subject: [PATCH 172/689] Separate (soundness) analyses activated for other specifications --- src/autoTune.ml | 3 +-- src/autoTuneSvompSpec.ml | 16 ++++++++++++++++ src/goblint.ml | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 04e9872445..74d5b4b862 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -247,8 +247,7 @@ let focusOnSpecification (spec: Svcomp.Specification.t) = Logs.info "Specification: NoDataRace -> enabling thread analyses \"%s\"" (String.concat ", " notNeccessaryThreadAnalyses); enableAnalyses notNeccessaryThreadAnalyses; | NoOverflow -> (*We focus on integer analysis*) - set_bool "ana.int.def_exc" true; - set_bool "ana.int.interval" true + set_bool "ana.int.def_exc" true | _ -> () let focusOnSpecification () = diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index 09f7b04a8a..b0b41dd889 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -3,6 +3,7 @@ open GobConfig open AutoTune +(* TODO: have only one function for matching all specifications and find a place where it can be called. *) let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) @@ -36,3 +37,18 @@ let enableAnalysesForTerminationSpecification (spec: Svcomp.Specification.t) = let enableAnalysesForTerminationSpecification () = List.iter enableAnalysesForTerminationSpecification (Svcomp.Specification.of_option ()) + +let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = + match spec with + | UnreachCall s -> () + | NoDataRace -> (* Enable the soundness analyses for NoDataRace spec *) + let dataRaceAna = ["access"; "race"] in + Logs.info "Specification: NoDataRace -> enabling soundness analyses \"%s\"" (String.concat ", " dataRaceAna); + enableAnalyses dataRaceAna + | NoOverflow -> (* Enable the soundness analyses for NoOverflow spec *) + Logs.info "Setting \"ana.int.interval\" to true"; + set_bool "ana.int.interval" true + | _ -> () + +let enableAnalysesForSpecification () = + List.iter enableAnalysesForSpecification (Svcomp.Specification.of_option ()) diff --git a/src/goblint.ml b/src/goblint.ml index c7c2dd6a76..39a24ff211 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -58,6 +58,7 @@ let main () = in (* This is run independant of the autotuner being enabled or not be sound for programs with longjmp *) AutoTune.activateLongjmpAnalysesWhenRequired (); + if get_string "ana.specification" <> "" then AutoTuneSvompSpec.enableAnalysesForSpecification (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; file |> do_analyze changeInfo; do_html_output (); From 5b1da8d9b9d0d694b3e17efe8164ee9b05b8c234 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 14:05:00 +0300 Subject: [PATCH 173/689] Unify the activated specification checks and remove a duplication check --- src/autoTune.ml | 3 +++ src/goblint.ml | 2 +- src/maingoblint.ml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 74d5b4b862..1cbdb4ae1e 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -508,6 +508,9 @@ let specificationIsActivated () = let specificationTerminationIsActivated () = isActivated "termination" +let specificationMemSafetyIsActivated () = + isActivated "memsafetySpecification" + let chooseConfig file = let factors = collectFactors visitCilFileSameGlobals file in let fileCompplexity = estimateComplexity factors file in diff --git a/src/goblint.ml b/src/goblint.ml index 39a24ff211..dd4571092f 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -37,7 +37,7 @@ let main () = Logs.debug "%s" GobSys.command_line; (* When analyzing a termination specification, activate the termination analysis before pre-processing. *) if get_string "ana.specification" <> "" then AutoTuneSvompSpec.enableAnalysesForTerminationSpecification (); - if get_bool "ana.autotune.enabled" && AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); + if AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( let file = diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 0f90a163f4..9c8dc02f49 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -203,7 +203,7 @@ let handle_options () = 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 get_string "ana.specification" <> "" then AutoTuneSvompSpec.enableAnalysesForMemSafetySpecification (); - if AutoTune.isActivated "memsafetySpecification" then + if AutoTune.specificationMemSafetyIsActivated () then AutoTune.focusOnMemSafetySpecification (); AfterConfig.run (); Cilfacade.init_options (); From 66eac09eeebc55b6755700b54a482f0e45e28a6a Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 15:38:18 +0300 Subject: [PATCH 174/689] Fix test annotation in a termination test that should terminate but we can not yet handle --- tests/regression/78-termination/51-modulo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/78-termination/51-modulo.c b/tests/regression/78-termination/51-modulo.c index 5f5b8f1924..81811c1acf 100644 --- a/tests/regression/78-termination/51-modulo.c +++ b/tests/regression/78-termination/51-modulo.c @@ -1,4 +1,4 @@ -// SKIP TERM PARAM: --enable ana.autotune.enabled --enable ana.sv-comp.functions --enable ana.sv-comp.enabled --set ana.autotune.activated "['congruence']" --set ana.specification "CHECK( init(main()), LTL(F end) )" +// SKIP TODO TERM PARAM: --enable ana.autotune.enabled --enable ana.sv-comp.functions --enable ana.sv-comp.enabled --set ana.autotune.activated "['congruence']" --set ana.specification "CHECK( init(main()), LTL(F end) )" // This task previously crashed due to the autotuner int main() { From 1f26a9bcac0c2c78af5f4344ef5cee3eebe792f6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 16 May 2024 15:40:51 +0300 Subject: [PATCH 175/689] Use normal Hashtbl for ARG test enumeration BatHashcons uses a global tag counter... --- src/witness/argTools.ml | 17 +- .../basic/for_fun_true-unreach-call.expected | 22 +- .../for_odd_vesal_true-unreach-call.expected | 172 ++++--- .../basic/for_true-unreach-call.expected | 22 +- .../global_init_true-unreach-call.expected | 16 +- .../basic/if_det_false-unreach-call.expected | 14 +- .../if_det_incr_true-unreach-call.expected | 10 +- .../basic/if_det_true-unreach-call.expected | 8 +- .../basic/if_mod_false-unreach-call.expected | 22 +- .../basic/if_mod_true-unreach-call.expected | 114 ++--- .../if_nondet_fun_false-unreach-call.expected | 22 +- .../if_nondet_var_false-unreach-call.expected | 72 ++- ...clude_multiple_false-unreach-call.expected | 212 ++++----- ...xclude_multiple_true-unreach-call.expected | 66 +-- ...f_trier_exclude_true-unreach-call.expected | 28 +- .../builtin_expect_true-unreach-call.expected | 10 +- .../cfg/free_spawn_true-unreach-call.expected | 174 +++---- .../free_spawn_ub_true-unreach-call.expected | 13 +- .../cfg/join_true-unreach-call.expected | 198 ++++---- ...ocal_shadow_fun_true-unreach-call.expected | 42 +- ...ll_context_join_true-unreach-call.expected | 206 ++++----- ...lticall_context_true-unreach-call.expected | 258 +++++------ .../multicall_join_true-unreach-call.expected | 198 ++++---- ...all_nested_join_true-unreach-call.expected | 435 ++++++++++-------- ...ulticall_nested_true-unreach-call.expected | 94 ++-- ..._return_context_true-unreach-call.expected | 58 +-- .../cfg/multicall_true-unreach-call.expected | 83 ++-- ...ion_global_init_true-unreach-call.expected | 198 ++++---- .../cfg/uncil/and3_true-unreach-call.expected | 32 +- .../uncil/and3dead_true-unreach-call.expected | 32 +- .../uncil/and_copy_true-unreach-call.expected | 30 +- ..._join_invariant_true-unreach-call.expected | 32 +- .../cfg/uncil/and_true-unreach-call.expected | 30 +- .../uncil/and_var_false-unreach-call.expected | 28 +- .../uncil/and_var_true-unreach-call.expected | 26 +- .../cfg/uncil/or3_true-unreach-call.expected | 32 +- .../uncil/or3dead_true-unreach-call.expected | 32 +- .../cfg/uncil/or_true-unreach-call.expected | 30 +- .../eq/eq_double_true-unreach-call.expected | 48 +- .../eq/eq_single_true-unreach-call.expected | 26 +- .../eq/multivar_false-unreach-call1.expected | 30 +- .../eq/multivar_true-unreach-call1.expected | 30 +- 42 files changed, 1591 insertions(+), 1631 deletions(-) diff --git a/src/witness/argTools.ml b/src/witness/argTools.ml index b67205f8ec..55a74b9f12 100644 --- a/src/witness/argTools.ml +++ b/src/witness/argTools.ml @@ -47,12 +47,21 @@ struct struct include Node - module HC = BatHashcons.MakeTable (Node) - let htable = HC.create 113 + module NH = Hashtbl.Make (Node) + let nh = NH.create 113 + let next = ref 0 let to_string n = - let hc = HC.hashcons htable n in - string_of_int hc.tag + let i = + match NH.find_opt nh n with + | Some i -> i + | None -> + let i = !next in + NH.replace nh n i; + incr next; + i + in + string_of_int i end end diff --git a/tests/sv-comp/basic/for_fun_true-unreach-call.expected b/tests/sv-comp/basic/for_fun_true-unreach-call.expected index e9b6bd185d..c4c5b62d64 100644 --- a/tests/sv-comp/basic/for_fun_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_fun_true-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────┐ - │ 123 │ + │ 0 │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 124 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────┐ │ - │ 131 │ │ + │ 8 │ │ └────────────────────────────────┘ │ │ │ │ Entry fun │ ▼ │ ┌────────────────────────────────┐ │ - │ 132 │ │ + │ 9 │ │ └────────────────────────────────┘ │ │ │ │ Assign 'i = 0' │ ▼ │ ┌────────────────────────────────┐ │ ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ - ┌──────────────────▶ │ 130 │ ─┼──────────────────────────────────────────▶ │ 136 │ ─────────────────▶ │ 137 │ + ┌──────────────────▶ │ 7 │ ─┼──────────────────────────────────────────▶ │ 13 │ ─────────────────▶ │ 14 │ │ └────────────────────────────────┘ │ └───────────────────────┘ └─────────────────────┘ │ │ │ Inlined Proc 'fun()' │ │ │ Test (i < 1000,true) └───────────────────────────────────────────────────────────────────────┐ │ InlineReturn │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ 135 │ ─┐ └───────────────▶ │ 133 │ + │ │ 12 │ ─┐ └───────────────▶ │ 10 │ │ └────────────────────────────────┘ │ └─────────────────────┘ │ │ │ │ │ │ InlineEntry '(i < 2000)' │ │ Ret (Some 0, main) │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ 127 │ │ │ 134 │ + │ │ 4 │ │ │ 11 │ │ └────────────────────────────────┘ │ └─────────────────────┘ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ 128 │ │ + │ Assign 'i = i + 1' │ 5 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 125 │ │ + │ │ 2 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 126 │ │ + │ │ 3 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └─────────────────── │ 129 │ ◀┘ + └─────────────────── │ 6 │ ◀┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected index b05d174ebf..7359b71cdd 100644 --- a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected @@ -1,90 +1,84 @@ - ┌────────────────────────────────┐ - │ 148 │ - └────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────┐ - │ 149 │ - └────────────────────────────────┘ - ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────┐ │ - │ │ 171 │ ─┐ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ 157 │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ Assign 'i = i + 2' - │ │ Entry fun │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ 158 │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Assign 'i = 1' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌─────┐ Test (i < 1000,true) ┌────────────────────────────────┐ │ │ - │ │ 153 │ ◀──────────────────────────────────────────── │ 162 │ ◀───────────────────────────────────────────── │ 156 │ ◀┼────────────────────────┘ - │ └────────────────────────────────┘ └─────┘ └────────────────────────────────┘ │ - │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ - │ ▼ │ ▼ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────┐ │ - │ │ 154 │ │ ┌──────────────────────────────────────────── │ 163 │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ - │ │ 151 │ │ │ │ 166 │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ Test (! cond,true) ┌─────────────────────────┐ - │ │ 152 │ │ │ │ 167 │ ─┼──────────────────────────────────────────────────────────────────▶ │ 172 │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ │ │ │ │ - │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' - │ ▼ │ │ ▼ │ ▼ - │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ - └─ │ 155 │ ◀───────────────────────────────────────────────┘ │ │ 164 │ │ │ 170 │ - └────────────────────────────────┘ │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error - │ ▼ │ ▼ - │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ - │ │ 165 │ │ │ 161 │ - │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ - │ │ InlineReturn │ Inlined Proc 'fun()' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ 168 │ │ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, fun) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 169 │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 159 │ ◀┘ - └────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────┐ - │ 160 │ - └────────────────────────────────┘ - ┌────────────────────────────────┐ - │ 150 │ - └────────────────────────────────┘ + ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────┐ │ + │ │ 0 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 1 │ ─┐ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 8 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry fun │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ 9 │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Assign 'i = 1' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌────┐ Test (i < 1000,true) ┌────────────────────────────────┐ │ Assign 'i = i + 2' │ + │ │ 4 │ ◀──────────────────────────────────────────── │ 13 │ ◀───────────────────────────────────────────── │ 7 │ ◀┼───────────────────────────────────────────────┘ + │ └────────────────────────────────┘ └────┘ └────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ + │ ▼ │ ▼ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────┐ │ + │ │ 5 │ │ ┌──────────────────────────────────────────── │ 14 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ + │ │ 2 │ │ │ │ 17 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ Test (! cond,true) ┌─────────────────────────┐ + │ │ 3 │ │ │ │ 18 │ ─┼──────────────────────────────────────────────────────────────────▶ │ 22 │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ │ │ │ │ + │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' + │ ▼ │ │ ▼ │ ▼ + │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ + └─ │ 6 │ ◀───────────────────────────────────────────────┘ │ │ 15 │ │ │ 21 │ + └────────────────────────────────┘ │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error + │ ▼ │ ▼ + │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ + │ │ 16 │ │ │ 12 │ + │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ + │ │ InlineReturn │ Inlined Proc 'fun()' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └───────────────────────────────────────────▶ │ 19 │ │ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, fun) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 20 │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 10 │ ◀┘ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ 11 │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_true-unreach-call.expected b/tests/sv-comp/basic/for_true-unreach-call.expected index 6a0b812d06..67103e5aae 100644 --- a/tests/sv-comp/basic/for_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_true-unreach-call.expected @@ -1,51 +1,51 @@ ┌────────────────────────────────┐ - │ 116 │ + │ 0 │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 117 │ + │ 1 │ └────────────────────────────────┘ │ │ Assign 'i = 0' ▼ - ┌────────────────────────────────┐ Test (i < 1000,false) ┌─────┐ Ret (Some 0, main) ┌─────┐ - ┌──────────────────▶ │ 123 │ ────────────────────────────────────────────▶ │ 125 │ ────────────────────▶ │ 126 │ - │ └────────────────────────────────┘ └─────┘ └─────┘ + ┌────────────────────────────────┐ Test (i < 1000,false) ┌───┐ Ret (Some 0, main) ┌────┐ + ┌──────────────────▶ │ 7 │ ────────────────────────────────────────────▶ │ 9 │ ────────────────────▶ │ 10 │ + │ └────────────────────────────────┘ └───┘ └────┘ │ │ │ │ Test (i < 1000,true) │ ▼ │ ┌────────────────────────────────┐ - │ │ 124 │ ─┐ + │ │ 8 │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(i < 2000)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 120 │ │ + │ │ 4 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ 121 │ │ + │ Assign 'i = i + 1' │ 5 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 118 │ │ + │ │ 2 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 119 │ │ + │ │ 3 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └─────────────────── │ 122 │ ◀┘ + └─────────────────── │ 6 │ ◀┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/global_init_true-unreach-call.expected b/tests/sv-comp/basic/global_init_true-unreach-call.expected index 1a4bb724e4..4e1725a741 100644 --- a/tests/sv-comp/basic/global_init_true-unreach-call.expected +++ b/tests/sv-comp/basic/global_init_true-unreach-call.expected @@ -1,45 +1,45 @@ ┌────────────────────────────────┐ -│ 34 │ +│ 0 │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ -│ 35 │ ─┐ +│ 1 │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(g == 1)' │ ▼ │ ┌────────────────────────────────┐ │ -│ 40 │ │ +│ 6 │ │ └────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────┐ │ -│ 38 │ │ +│ 4 │ │ └────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(g == 1)' ▼ │ ┌────────────────────────────────┐ │ -│ 39 │ │ +│ 5 │ │ └────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────┐ │ -│ 41 │ │ +│ 7 │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ -│ 37 │ ◀┘ +│ 3 │ ◀┘ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ -│ 36 │ +│ 2 │ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_false-unreach-call.expected b/tests/sv-comp/basic/if_det_false-unreach-call.expected index c840d10f89..96509723ec 100644 --- a/tests/sv-comp/basic/if_det_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_false-unreach-call.expected @@ -1,39 +1,39 @@ ┌─────────────────────────┐ -│ 31 │ +│ 0 │ └─────────────────────────┘ │ │ Entry main ▼ ┌─────────────────────────┐ -│ 32 │ +│ 1 │ └─────────────────────────┘ │ │ Test (1,true) ▼ ┌─────────────────────────┐ -│ 33 │ +│ 2 │ └─────────────────────────┘ │ │ Assign 'x = 1' ▼ ┌─────────────────────────┐ -│ 34 │ +│ 3 │ └─────────────────────────┘ │ │ Test (x,true) ▼ ┌─────────────────────────┐ -│ 35 │ +│ 4 │ └─────────────────────────┘ │ │ InlineEntry '()' ▼ ┌─────────────────────────┐ -│ 36 │ +│ 5 │ └─────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌─────────────────────────┐ -│ 37 │ +│ 6 │ └─────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected index d95af858b5..dc4074b3a3 100644 --- a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected @@ -1,27 +1,27 @@ ┌─────────────────────┐ -│ 31 │ +│ 0 │ └─────────────────────┘ │ │ Entry main ▼ ┌─────────────────────┐ -│ 32 │ ◀┐ +│ 1 │ ◀┐ └─────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌─────────────────────┐ │ -│ 33 │ │ +│ 2 │ │ └─────────────────────┘ │ │ │ │ Assign 'x = -1' │ Test (x,false) ▼ │ ┌─────────────────────┐ │ -│ 34 │ │ +│ 3 │ │ └─────────────────────┘ │ │ │ │ Assign 'x = x + 1' │ ▼ │ ┌─────────────────────┐ │ -│ 35 │ ─┘ +│ 4 │ ─┘ └─────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_true-unreach-call.expected b/tests/sv-comp/basic/if_det_true-unreach-call.expected index 2ad36188ce..127ca693c5 100644 --- a/tests/sv-comp/basic/if_det_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_true-unreach-call.expected @@ -1,21 +1,21 @@ ┌─────────────────┐ -│ 27 │ +│ 0 │ └─────────────────┘ │ │ Entry main ▼ ┌─────────────────┐ -│ 28 │ ◀┐ +│ 1 │ ◀┐ └─────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌─────────────────┐ │ -│ 29 │ │ Test (x,false) +│ 2 │ │ Test (x,false) └─────────────────┘ │ │ │ │ Assign 'x = 0' │ ▼ │ ┌─────────────────┐ │ -│ 30 │ ─┘ +│ 3 │ ─┘ └─────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_false-unreach-call.expected b/tests/sv-comp/basic/if_mod_false-unreach-call.expected index 93a0a7f1e4..b7a96353e2 100644 --- a/tests/sv-comp/basic/if_mod_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_false-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────────────┐ - │ 77 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌────────────────────▶ │ 78 │ + ┌────────────────────▶ │ 1 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 82 │ ─┐ + │ │ 5 │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 83 │ │ + │ │ 6 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 50,false) │ 79 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x >= 50,false) │ 2 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 80 │ │ + │ │ 3 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 81 │ ◀┘ + │ │ 4 │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp 00' │ ▼ │ ┌────────────────────────────────────────┐ - └───────────────────── │ 84 │ + └───────────────────── │ 7 │ └────────────────────────────────────────┘ │ │ Test (x >= 50,true) ▼ ┌────────────────────────────────────────┐ - │ 85 │ + │ 8 │ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ 86 │ + │ 9 │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ 87 │ + │ 10 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_true-unreach-call.expected b/tests/sv-comp/basic/if_mod_true-unreach-call.expected index d73993ebe1..f27d391c86 100644 --- a/tests/sv-comp/basic/if_mod_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_true-unreach-call.expected @@ -1,69 +1,45 @@ -┌───────────────────────────────────────────────┐ -│ 62 │ -└───────────────────────────────────────────────┘ - │ - │ Entry main - ▼ -┌───────────────────────────────────────────────┐ -│ 63 │ -└───────────────────────────────────────────────┘ - ▲ - │ Test (x >= 100,false) - │ -┌───────────────────────────────────────────────┐ -│ 68 │ -└───────────────────────────────────────────────┘ -┌───────────────────────────────────────────────┐ -│ 69 │ -└───────────────────────────────────────────────┘ - │ - │ Entry __VERIFIER_nondet_int - ▼ -┌───────────────────────────────────────────────┐ -│ 70 │ -└───────────────────────────────────────────────┘ - │ - │ Ret (Some val, __VERIFIER_nondet_int) - ▼ -┌───────────────────────────────────────────────┐ -│ 75 │ -└───────────────────────────────────────────────┘ -┌───────────────────────────────────────────────┐ -│ 64 │ -└───────────────────────────────────────────────┘ - │ - │ InlineReturn 'tmp' - ▼ -┌───────────────────────────────────────────────┐ -│ 65 │ -└───────────────────────────────────────────────┘ - ▲ - │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - │ -┌───────────────────────────────────────────────┐ -│ 66 │ -└───────────────────────────────────────────────┘ - │ - │ InlineEntry '()' - ▼ -┌───────────────────────────────────────────────┐ -│ 67 │ -└───────────────────────────────────────────────┘ -┌───────────────────────────────────────────────┐ -│ 71 │ -└───────────────────────────────────────────────┘ - │ - │ Test (1,true) - ▼ -┌───────────────────────────────────────────────┐ -│ 72 │ -└───────────────────────────────────────────────┘ -┌───────────────────────────────────────────────┐ -│ 73 │ -└───────────────────────────────────────────────┘ - │ - │ Assign 'x = tmp 00' - ▼ -┌───────────────────────────────────────────────┐ -│ 74 │ -└───────────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 0 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + ┌─────────────────────▶ │ 1 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (1,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 4 │ ─┐ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '()' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 5 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_nondet_int │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ Test (x >= 100,false) │ 7 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 2 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn 'tmp' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 3 │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = tmp 00' + │ ▼ + │ ┌────────────────────────────────────────┐ + └────────────────────── │ 6 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected index 0b061b2a64..06d8e76736 100644 --- a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────────────┐ - │ 79 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌──────────────▶ │ 80 │ + ┌──────────────▶ │ 1 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 84 │ ─┐ + │ │ 5 │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 85 │ │ + │ │ 6 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x,false) │ 81 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x,false) │ 2 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 82 │ │ + │ │ 3 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 83 │ ◀┘ + │ │ 4 │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp' │ ▼ │ ┌────────────────────────────────────────┐ - └─────────────── │ 86 │ + └─────────────── │ 7 │ └────────────────────────────────────────┘ │ │ Test (x,true) ▼ ┌────────────────────────────────────────┐ - │ 87 │ + │ 8 │ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ 88 │ + │ 9 │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ 89 │ + │ 10 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected index 9fd998e281..3337b59a7d 100644 --- a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected @@ -1,39 +1,33 @@ - ┌─────────────────────────┐ - │ 36 │ - └─────────────────────────┘ - │ - │ Entry main - ▼ - ┌─────────────────────────┐ - │ 37 │ - └─────────────────────────┘ - │ - │ Test (1,true) - ▼ - ┌─────────────────────────┐ - │ 38 │ - └─────────────────────────┘ -┌────┐ Test (x,false) ┌─────────────────────────┐ -│ 42 │ ◀──────────────── │ 41 │ -└────┘ └─────────────────────────┘ - │ - │ Test (x,true) - ▼ - ┌─────────────────────────┐ - │ 43 │ - └─────────────────────────┘ - │ - │ InlineEntry '()' - ▼ - ┌─────────────────────────┐ - │ 44 │ - └─────────────────────────┘ - ┌─────────────────────────┐ - │ 39 │ - └─────────────────────────┘ - │ - │ Entry __VERIFIER_error - ▼ - ┌─────────────────────────┐ - │ 40 │ - └─────────────────────────┘ +┌─────────────────────────┐ +│ 0 │ +└─────────────────────────┘ + │ + │ Entry main + ▼ +┌─────────────────────────┐ +│ 1 │ ◀┐ +└─────────────────────────┘ │ + │ │ + │ Test (1,true) │ Test (x,false) + ▼ │ +┌─────────────────────────┐ │ +│ 2 │ ─┘ +└─────────────────────────┘ + │ + │ Test (x,true) + ▼ +┌─────────────────────────┐ +│ 5 │ +└─────────────────────────┘ + │ + │ InlineEntry '()' + ▼ +┌─────────────────────────┐ +│ 3 │ +└─────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ +┌─────────────────────────┐ +│ 4 │ +└─────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected index 426c2ea3c9..25d029027a 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected @@ -1,114 +1,98 @@ - ┌────────────────────────────────────────┐ - │ 128 │ - └────────────────────────────────────────┘ - │ InlineReturn - │ Entry main ┌────────────────────────────────────────────────────────────────────────┐ - ▼ ▼ │ - InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 0)' ┌─────────────────────┐ │ - ┌────────────────────────────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ 144 │ ─┼────┐ - │ │ │ └─────────────────────┘ │ │ - │ Inlined Proc '__VERIFIER_assert(x == 2)' │ │ ▲ │ │ - │ ┌───────────────────────────────────────────────────────────────────▶ │ 129 │ │ Test (x == 0,true) │ │ - │ │ │ │ │ │ │ - │ │ │ │ │ │ │ - │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ │ │ - │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Test (1,true) │ InlineReturn │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 136 │ ─┐ ┌────┼────────────────────────────────────────────┘ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 137 │ │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 148 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x != 1)' │ 146 │ │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 138 │ ◀┘ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Assign 'x = tmp' │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 142 │ ──────────────────────────────────────────────────┘ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ Test (x == 0,false) │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ 143 │ ─┐ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Test (x == 2,false) │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └───────────────────────────────────────── │ 149 │ │ Test (x == 2,true) │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ - ┌────┼────┼───────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └──────────────────────────────────────────────────────────────────── │ 135 │ ◀┘ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ │ InlineEntry '(x == 2)' │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ InlineEntry '(x == 0)' │ │ │ - │ │ │ 133 │ ◀──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼────┘ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 134 │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 130 │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ └───────────────────────────────────────────────────────────────────────── │ 131 │ ───────────────────────────────────────────────────────┘ │ - │ └────────────────────────────────────────┘ │ - │ InlineEntry '(x != 1)' ┌────────────────────────────────────────┐ │ - └─────────────────────────────────────────────────────────────────────────────▶ │ 150 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌─────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ │ - │ 141 │ ◀────────────────────────────────────────── │ 139 │ │ - └─────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ - │ InlineEntry '()' │ Test (! cond,false) │ - ▼ ▼ │ - ┌─────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ 145 │ │ 140 │ │ - └─────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ - │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ - ▼ ▼ │ - ┌─────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ 132 │ │ 147 │ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - └─────────────────────────┘ └────────────────────────────────────────┘ + + ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 0 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ InlineReturn + │ ▼ ▼ + │ Inlined Proc '__VERIFIER_assert(x == 0)' ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ + │ │ │ │ + │ │ Inlined Proc '__VERIFIER_assert(x != 1)' │ │ InlineReturn + │ │ ┌─────────────────────────────────────────────▶ │ 1 │ ◀─────────────────┐ + │ │ │ │ │ │ + │ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ + │ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ + │ │ │ │ │ Test (1,true) │ │ + │ │ │ │ ▼ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ │ 8 │ ─┐ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ InlineEntry '()' │ │ │ + │ │ │ │ ▼ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ 9 │ │ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ │ ▼ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ Inlined Proc '__VERIFIER_assert(x == 2)' │ 20 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ │ ▼ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ 18 │ │ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ InlineReturn 'tmp' │ │ │ + │ │ │ │ ▼ │ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ 10 │ ◀┘ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ + │ │ │ │ │ Assign 'x = tmp' │ │ + │ │ │ │ ▼ │ │ + │ ┌────────────────────────────────┐ Test (x == 0,true) │ │ ┌────────────────────────────────────────┐ │ │ + │ │ 16 │ ◀───────────────────────────┼────┼───────────────────────────────────────── │ 14 │ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ + │ │ InlineEntry '(x == 0)' │ │ │ Test (x == 0,false) │ InlineReturn │ + │ ▼ │ │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ 5 │ ◀┐ │ │ │ 15 │ ─┐ │ │ + │ └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ │ │ Test (x == 2,true) │ │ │ + │ ▼ │ │ │ ▼ │ │ │ + │ ┌────────────────────────────────┐ │ InlineEntry '(x == 2)' │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 6 │ │ │ └───────────────────────────────────────── │ 7 │ │ Test (x == 2,false) │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ Test (! cond,false) └──────────────────────────┼─────────────────────────────────────────────────┘ │ │ │ + │ ▼ │ │ │ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 2 │ └────────────────────────────────────────────── │ 21 │ ◀┘ │ │ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ InlineEntry '(x != 1)' │ │ + │ ▼ ▼ │ │ + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ + └─ │ 3 │ ─────────────────────────────────┐ │ 22 │ │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + ┌────────────────────────────────┐ Test (! cond,true) │ ┌────────────────────────────────────────┐ │ │ + │ 13 │ ◀────────────────────────────────┼───────────────────────────────────────── │ 11 │ │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ InlineEntry '()' │ │ Test (! cond,false) │ │ + ▼ │ ▼ │ │ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ 17 │ │ │ 12 │ │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ Entry __VERIFIER_error │ │ Ret (None, __VERIFIER_assert) │ │ + ▼ │ ▼ │ │ + ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ 4 │ │ │ 19 │ ──────────────────────────────────────────────────┘ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index 715bc56cf8..2ba7b8e5fe 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -1,14 +1,14 @@ ┌────────────────────────────────────────┐ - │ 133 │ + │ 0 │ └────────────────────────────────────────┘ │ InlineReturn │ Entry main ┌────────────────────────────────────────────────────────────────────────┐ ▼ ▼ │ - InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 0)' ┌─────────────────────┐ │ - ┌───────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ 143 │ ─┼────┐ + InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ │ + ┌───────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ 4 │ ─┼────┐ │ │ │ └─────────────────────┘ │ │ - │ Inlined Proc '__VERIFIER_assert(x == 2)' │ │ ▲ │ │ - │ ┌──────────────────────────────────────────────▶ │ 134 │ │ Test (x == 0,true) │ │ + │ Inlined Proc '__VERIFIER_assert(x == 0)' │ │ ▲ │ │ + │ ┌──────────────────────────────────────────────▶ │ 1 │ │ Test (x == 2,true) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ │ │ @@ -17,116 +17,116 @@ │ │ │ │ Test (1,true) │ InlineReturn │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 138 │ ─┐ ┌────┼────────────────────────────────────────────┘ │ │ + │ │ │ │ 5 │ ─┐ ┌────┼────────────────────────────────────────────┘ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 139 │ │ │ │ │ │ + │ │ │ │ 6 │ │ │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 149 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ + │ │ │ │ 16 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 150 │ │ │ │ │ │ + │ │ │ │ 17 │ │ │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 140 │ ◀┘ │ │ │ │ + │ │ │ │ 7 │ ◀┘ │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ Assign 'x = tmp' │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 141 │ ──────────────────────────────────────────────────┘ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ Test (x == 0,false) │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ 142 │ ─┐ │ │ │ + │ │ │ │ 8 │ ─┐ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Test (x == 0,false) │ │ │ │ │ + │ │ │ ▼ │ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ │ │ 9 │ ─┼────────────────────────────────────────────────┘ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Test (x == 2,false) │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 146 │ │ │ │ │ + │ │ │ │ 13 │ │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Test (x != 0,true) │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 147 │ │ │ │ │ + │ │ │ │ 14 │ │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ Test (x != 2,true) │ Test (x == 2,true) │ │ │ + │ │ │ │ Test (x != 2,true) │ Test (x == 0,true) │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 155 │ │ │ │ │ + │ │ │ │ 22 │ │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Assign 'tmp___0 = 1' │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └────────────────────────────────────────── │ 151 │ │ │ │ │ + │ │ └────────────────────────────────────────── │ 18 │ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ ┌────┼────┼──────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └─────────────────────────────────────────────── │ 137 │ ◀┘ │ │ │ + │ │ └─────────────────────────────────────────────── │ 10 │ ◀┘ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ - │ │ │ InlineEntry '(x == 2)' │ │ │ + │ │ │ InlineEntry '(x == 0)' │ │ │ │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ InlineEntry '(x == 0)' │ │ │ - │ │ │ 135 │ ◀──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼────┘ + │ │ ┌────────────────────────────────────────┐ InlineEntry '(x == 2)' │ │ │ + │ │ │ 2 │ ◀──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 136 │ │ │ + │ │ │ 3 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 148 │ │ │ + │ │ │ 15 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ └──────────────────────────────────────────────────── │ 154 │ ───────────────────────────────────────────────────────┘ │ + │ └──────────────────────────────────────────────────── │ 21 │ ───────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ InlineEntry '(tmp___0)' ┌────────────────────────────────────────┐ │ - └────────────────────────────────────────────────────────▶ │ 152 │ │ + └────────────────────────────────────────────────────────▶ │ 19 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 144 │ │ + │ 11 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 145 │ │ + │ 12 │ │ └────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 153 │ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ 20 │ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected index 68f5200bc8..44a30b2c66 100644 --- a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected @@ -5,85 +5,85 @@ │ ┌───────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 104 │ │ │ + │ │ │ 0 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 0)' │ InlineReturn │ │ ▼ ▼ ▼ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ ┌────────────────────────────────────────▶ │ 105 │ ◀┐ + │ │ ┌────────────────────────────────────────▶ │ 1 │ ◀┐ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Test (1,true) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ │ 110 │ ─┐ │ + │ │ │ │ 6 │ ─┐ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 111 │ │ │ + │ │ │ │ 7 │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 106 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ │ │ 2 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 107 │ │ │ + │ │ │ │ 3 │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 112 │ ◀┘ │ + │ │ │ │ 8 │ ◀┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Assign 'x = tmp' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ │ 113 │ ─┐ │ InlineReturn + │ │ │ │ 9 │ ─┐ │ InlineReturn │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ Test (x == 0,true) │ │ │ │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌──────────────────────▶ │ 119 │ │ │ └───────────────────────────────────────── │ 115 │ ─┼────────────────────────────────────────────────┐ │ + ┌──────────────────────▶ │ 15 │ │ │ └───────────────────────────────────────── │ 11 │ ─┼────────────────────────────────────────────────┐ │ │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ Test (x == 0,false) │ │ │ ▼ │ │ │ │ │ │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 117 │ │ └────────────────────────────────────────────── │ 114 │ ◀┘ │ │ + │ │ 13 │ │ └────────────────────────────────────────────── │ 10 │ ◀┘ │ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ InlineEntry '(x != 0)' │ │ │ ▼ │ ▼ │ │ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ 118 │ │ │ 116 │ │ │ + │ │ 14 │ │ │ 12 │ │ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ │ │ ▼ │ ▼ │ │ │ InlineEntry '(x == 0)' ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ 120 │ ─┘ │ 108 │ │ │ + │ │ 16 │ ─┘ │ 4 │ │ │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 109 │ │ │ + │ │ 5 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 121 │ ──────────────────────────────────────────────────┼────────────────┘ + │ │ 17 │ ──────────────────────────────────────────────────┼────────────────┘ │ └────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected b/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected index 5bbfc95f79..396e5ca0d5 100644 --- a/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected +++ b/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected @@ -1,27 +1,27 @@ ┌───────────────────────────────────────────────┐ -│ 22 │ +│ 0 │ └───────────────────────────────────────────────┘ │ │ Entry main ▼ ┌───────────────────────────────────────────────┐ -│ 23 │ +│ 1 │ └───────────────────────────────────────────────┘ │ │ Assign 'x = 0' ▼ ┌───────────────────────────────────────────────┐ -│ 24 │ +│ 2 │ └───────────────────────────────────────────────┘ │ │ Proc '__builtin_expect((long )(x == 0), 1L)' ▼ ┌───────────────────────────────────────────────┐ -│ 25 │ +│ 3 │ └───────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌───────────────────────────────────────────────┐ -│ 26 │ +│ 4 │ └───────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected index a37a63d9be..c8643d023e 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected @@ -1,87 +1,87 @@ - ┌────────────────────────────────────────┐ - │ 104 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 105 │ - └────────────────────────────────────────┘ - │ - │ Assign 'p = (void *)0' - ▼ - ┌────────────────────────────────────────┐ - │ 112 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 113 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 114 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 106 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 107 │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp ' - ▼ - ┌────────────────────────────────────────┐ - │ 115 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x == 0,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 116 │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x == 1,false) │ Test (x == 0,true) - │ ▼ │ -┌─────┐ Test (x == -1,false) │ ┌────────────────────────────────────────┐ │ -│ 110 │ ◀─────────────────────────────────┼─────────────────── │ 118 │ │ -└─────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Test (x == 1,true) │ Test (x == -1,true) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ └──────────────────▶ │ 117 │ ◀┘ - │ └────────────────────────────────────────┘ - │ │ - │ │ Proc 'tmp___0 = malloc(1)' - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ 108 │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'p = (void *)tmp___0' - │ ▼ - │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────┐ - └──────────────────────────────────────────────────────────▶ │ 109 │ - └────────────────────────────────────────┘ - │ - │ Proc 'free(p)' - ▼ - ┌────────────────────────────────────────┐ - │ 111 │ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 119 │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 0 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 1 │ + └────────────────────────────────────────┘ + │ + │ Assign 'p = (void *)0' + ▼ + ┌────────────────────────────────────────┐ + │ 8 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 9 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 10 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 2 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 3 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp ' + ▼ + ┌────────────────────────────────────────┐ + │ 11 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x == 0,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌─────────────────── │ 12 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Test (x == 1,false) │ Test (x == 0,true) + │ ▼ │ +┌───┐ Test (x == -1,false) │ ┌────────────────────────────────────────┐ │ +│ 6 │ ◀─────────────────────────────────┼─────────────────── │ 14 │ │ +└───┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Test (x == 1,true) │ Test (x == -1,true) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ └──────────────────▶ │ 13 │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Proc 'tmp___0 = malloc(1)' + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 4 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'p = (void *)tmp___0' + │ ▼ + │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────┐ + └────────────────────────────────────────────────────────▶ │ 5 │ + └────────────────────────────────────────┘ + │ + │ Proc 'free(p)' + ▼ + ┌────────────────────────────────────────┐ + │ 7 │ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 15 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected index 3218aae4bc..a2eb7a644b 100644 --- a/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected @@ -1,30 +1,27 @@ ┌───────────────────────────────────┐ -│ 22 │ +│ 0 │ └───────────────────────────────────┘ │ │ Entry main ▼ ┌───────────────────────────────────┐ -│ 23 │ +│ 1 │ └───────────────────────────────────┘ │ │ Assign 'p = (void (*)())(& foo)' ▼ ┌───────────────────────────────────┐ -│ 24 │ +│ 2 │ └───────────────────────────────────┘ │ │ Proc 'free(p)' ▼ ┌───────────────────────────────────┐ -│ 25 │ -└───────────────────────────────────┘ -┌───────────────────────────────────┐ -│ 26 │ +│ 3 │ └───────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌───────────────────────────────────┐ -│ 27 │ +│ 4 │ └───────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected index eb7f3c2029..00a349b354 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -1,99 +1,99 @@ - ┌────────────────────────────────────────┐ - │ 76 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 77 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 78 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 79 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 92 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ -┌────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ -│ 82 │ ◀────────────────── │ 80 │ ◀┘ -└────┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,true) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ 81 │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 1' - │ ▼ - │ Assign 'x = 2' ┌────────────────────────────────────────┐ - └──────────────────────▶ │ 83 │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ 87 │ - └────────────────────────────────────────┘ - │ - │ Test (x <= 2,true) - ▼ - ┌────────────────────────────────────────┐ - │ 88 │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1' - ▼ - ┌────────────────────────────────────────┐ - │ 89 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 93 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 85 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 86 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 91 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 90 │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 84 │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 0 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 1 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 2 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 16 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ +┌───┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ +│ 6 │ ◀────────────────── │ 4 │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,true) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 5 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 1' + │ ▼ + │ Assign 'x = 2' ┌────────────────────────────────────────┐ + └─────────────────────▶ │ 7 │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ 11 │ + └────────────────────────────────────────┘ + │ + │ Test (x <= 2,true) + ▼ + ┌────────────────────────────────────────┐ + │ 12 │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1' + ▼ + ┌────────────────────────────────────────┐ + │ 13 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 17 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 9 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 10 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 15 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 14 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 8 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected index a65f2f2886..e0a0ace31d 100644 --- a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected +++ b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected @@ -2,125 +2,125 @@ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ 159 │ │ + │ │ 0 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry main │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 160 │ ─┐ │ + │ │ 1 │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 161 │ │ │ + │ │ 2 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 162 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 174 │ │ │ + │ │ 15 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ Assign 'i = i + 1' - │ │ 165 │ ◀┘ │ + │ │ 6 │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'n = tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 172 │ ─┐ │ + │ │ 13 │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(n)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 168 │ │ │ + │ │ 9 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry sum │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 169 │ │ │ + │ │ 10 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Assign 'sum___0 = 0' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 170 │ │ │ + │ │ 11 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Assign 'i = 0' │ │ │ ▼ │ │ │ ┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ │ │ - │ │ 163 │ ◀──────────────────── │ 171 │ ◀┼────────────────────────────────────────────────┘ + │ │ 4 │ ◀──────────────────── │ 12 │ ◀┼────────────────────────────────────────────────┘ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) │ │ ▼ ▼ │ │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - └─ │ 164 │ │ 183 │ │ + └─ │ 5 │ │ 24 │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ Ret (Some sum___0, sum) │ Inlined Proc 'tmp___0 = sum(n)' ▼ │ ┌────────────────────────────────────────┐ │ - │ 182 │ │ + │ 23 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp___0' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 173 │ ◀┘ + │ 14 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 's = tmp___0' ▼ ┌────────────────────────────────────────┐ - │ 178 │ ─┐ + │ 19 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(s >= 0)' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 176 │ │ + │ 17 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌─────────────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ │ - │ 184 │ ◀──────────────────── │ 177 │ │ + │ 25 │ ◀──────────────────── │ 18 │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(s >= 0)' ▼ ▼ │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ 179 │ │ 175 │ │ + │ 20 │ │ 16 │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ ▼ ▼ │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ 180 │ │ 166 │ │ + │ 21 │ │ 7 │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 167 │ ◀┘ + │ 8 │ ◀┘ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 181 │ + │ 22 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected index f46cd151fa..a5778e7847 100644 --- a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected @@ -1,105 +1,101 @@ - ┌────────────────────────────────────────┐ - │ 106 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 107 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 115 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 116 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 131 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌──────────────────────────────────────────── │ 117 │ ◀┘ - │ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,true) - │ ▼ -┌────────────────────────────────┐ InlineEntry '(1)' │ ┌────────────────────────────────────────┐ -│ 124 │ ◀────────────────────────────────────────────────┼──────────────────────────────────────────── │ 129 │ ──────────────────────────────────────────────────┐ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ - │ Entry foo │ Test (tmp,false) │ - ▼ │ │ -┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ -│ 125 │ ─┐ └───────────────────────────────────────────▶ │ 110 │ ─┐ │ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ InlineEntry '(x - 1 < x)' │ │ InlineEntry '(2)' │ │ - ▼ │ ▼ │ │ -┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ -│ 130 │ │ │ 111 │ │ │ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ Entry __VERIFIER_assert │ │ Entry foo │ │ - ▼ │ ▼ │ │ -┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ -│ 121 │ │ ┌──────────────────────────────────────────── │ 127 │ │ │ -└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ │ InlineEntry '(x - 1 < x)' │ │ - ▼ │ │ ▼ │ │ -┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ -│ 122 │ │ │ │ 113 │ │ │ -└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ │ - ▼ │ │ ▼ │ │ -┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ -│ 128 │ │ │ │ 114 │ │ │ -└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ │ - ▼ │ │ ▼ │ │ -┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ -│ 120 │ ◀┘ │ │ 108 │ │ │ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ Ret (None, foo) │ │ Ret (None, __VERIFIER_assert) │ │ - ▼ │ ▼ │ │ -┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ -│ 119 │ │ │ 109 │ │ │ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineReturn │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ └───────────────────────────────────────────▶ │ 126 │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, foo) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ 118 │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ Inlined Proc 'foo(2)' │ Inlined Proc 'foo(1)' - │ ▼ ▼ ▼ - │ InlineReturn ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ 112 │ - └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 123 │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 0 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 1 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 9 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 10 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 25 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌────────────────────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ + ┌─────────────────────────────────────────────────────────────────────────────────── │ 4 │ ◀───────────────────────────────────────────── │ 11 │ ◀┘ + │ └────────────────────┘ └────────────────────────────────────────┘ + │ │ │ + │ │ InlineEntry '(2)' │ Test (tmp,true) + │ ▼ ▼ + │ ┌────────────────────┐ ┌────────────────────────────────────────┐ + │ │ 5 │ │ 23 │ ─┐ + │ └────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Entry foo │ InlineEntry '(1)' │ + │ ▼ ▼ │ + │ ┌────────────────────────────────┐ InlineEntry '(x - 1 < x)' ┌────────────────────┐ ┌────────────────────────────────────────┐ │ + │ │ 7 │ ◀───────────────────────────────────────────── │ 21 │ │ 18 │ │ + │ └────────────────────────────────┘ └────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ Entry foo │ + │ ▼ │ ▼ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ │ 8 │ │ ┌──────────────────────────────────────────── │ 19 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ InlineEntry '(x - 1 < x)' │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + │ │ 2 │ │ │ │ 24 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + │ │ 3 │ │ │ │ 15 │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ │ ┌────────────────────────────────────────┐ │ + │ │ 20 │ ◀────────────────────────────────────────────────┘ │ │ 16 │ │ + │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Ret (None, foo) │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ ▼ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ │ 12 │ │ │ 22 │ │ + │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ InlineReturn │ + │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ + │ │ └───────────────────────────────────────────▶ │ 14 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Ret (None, foo) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 13 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineReturn │ Inlined Proc 'foo(1)' + │ │ ▼ ▼ + │ │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ 6 │ + │ └─────────────────────────────────────────────────────────────────────────────────────────┘ + │ │ ▲ + │ │ Ret (Some 0, main) │ Inlined Proc 'foo(2)' + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 17 │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected index ad86510bcd..5fd345474f 100644 --- a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected @@ -1,135 +1,123 @@ - ┌────────────────────────────────┐ - │ 70 │ - └────────────────────────────────┘ - │ - │ Entry main - ▼ -┌────┐ Inlined Proc 'foo(1)' ┌────────────────────────────────┐ -│ 73 │ ◀───────────────────────────────────────────── │ 71 │ -└────┘ └────────────────────────────────┘ - │ - │ InlineEntry '(1)' - ▼ - ┌────────────────────────────────┐ - │ 72 │ - └────────────────────────────────┘ - ┌────────────────────────────────┐ - │ 81 │ - └────────────────────────────────┘ - │ - │ Entry foo - ▼ - ┌────────────────────────────────┐ - │ 82 │ ─┐ - └────────────────────────────────┘ │ - │ │ - │ InlineEntry '(x - 1 < x)' │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 92 │ │ - └────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 77 │ │ - └────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' - ▼ │ - ┌────────────────────────────────┐ │ - │ 78 │ │ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 89 │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 79 │ ◀┘ - └────────────────────────────────┘ - │ - │ Ret (None, foo) - ▼ - ┌────────────────────────────────┐ - │ 80 │ - └────────────────────────────────┘ - │ - │ InlineReturn - ▼ - ┌────────────────────────────────┐ - │ 90 │ ─┐ - └────────────────────────────────┘ │ - │ │ - │ InlineEntry '(2)' │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 87 │ │ - └────────────────────────────────┘ │ - │ │ - │ Entry foo │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────────── │ 88 │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(x - 1 < x)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ 95 │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ 83 │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(2)' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ 84 │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ 93 │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ 85 │ │ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, foo) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 86 │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 91 │ ◀┘ - └────────────────────────────────┘ - ┌────────────────────────────────┐ - │ 74 │ - └────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────┐ - │ 75 │ - └────────────────────────────────┘ - ┌────────────────────────────────┐ - │ 76 │ - └────────────────────────────────┘ - ┌────────────────────────────────┐ - │ 94 │ - └────────────────────────────────┘ + ┌────────────────────────────────┐ + │ 0 │ + └────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────┐ + │ 1 │ ─┐ + └────────────────────────────────┘ │ + │ │ + │ InlineEntry '(1)' │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 2 │ │ + └────────────────────────────────┘ │ + │ │ + │ Entry foo │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌──────────────────────────────────────────── │ 10 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(x - 1 < x)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 18 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 6 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 7 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 17 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └───────────────────────────────────────────▶ │ 8 │ │ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, foo) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ 9 │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + ┌──────────────────────────────────────────── │ 3 │ ◀┘ + │ └────────────────────────────────┘ + │ │ + │ │ InlineEntry '(2)' + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 15 │ + │ └────────────────────────────────┘ + │ │ + │ │ Entry foo + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 16 │ ─┐ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineEntry '(x - 1 < x)' │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 20 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry __VERIFIER_assert │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 11 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ Inlined Proc 'foo(2)' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 12 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 19 │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ 13 │ ◀┘ + │ └────────────────────────────────┘ + │ │ + │ │ Ret (None, foo) + │ ▼ + │ ┌────────────────────────────────┐ + │ │ 14 │ + │ └────────────────────────────────┘ + │ │ + │ │ InlineReturn + │ ▼ + │ ┌────────────────────────────────┐ + └───────────────────────────────────────────▶ │ 4 │ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ 5 │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected index c01d4adf7b..2e9030c78d 100644 --- a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected @@ -1,99 +1,99 @@ - ┌────────────────────────────────────────┐ - │ 87 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 88 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 92 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 93 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 104 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ - ┌─ │ 89 │ ◀───────────────────────────────────────────── │ 94 │ ◀┘ - │ └────┘ └────────────────────────────────────────┘ - │ │ │ - │ │ │ Test (tmp,true) - │ │ ▼ - │ │ ┌────────────────────────────────────────┐ - │ │ │ 102 │ ─┐ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineEntry '(1)' │ - │ │ ▼ │ - │ │ InlineEntry '(1)' ┌────────────────────────────────────────┐ │ - │ └─────────────────────────────────────────────────▶ │ 90 │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry foo │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ ┌──────────────────────────────────────────── │ 100 │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineEntry '(x - 1 < x)' │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 103 │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 97 │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 98 │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 101 │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineReturn │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ └───────────────────────────────────────────▶ │ 96 │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, foo) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ 95 │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ Inlined Proc 'foo(1)' ┌────────────────────────────────────────┐ │ - └──────────────────────────────────────────────────────▶ │ 91 │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 99 │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 0 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 1 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 5 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 6 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 17 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ + ┌───┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ + ┌─ │ 2 │ ◀───────────────────────────────────────────── │ 7 │ ◀┘ + │ └───┘ └────────────────────────────────────────┘ + │ │ │ + │ │ │ Test (tmp,true) + │ │ ▼ + │ │ ┌────────────────────────────────────────┐ + │ │ │ 15 │ ─┐ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineEntry '(1)' │ + │ │ ▼ │ + │ │ InlineEntry '(1)' ┌────────────────────────────────────────┐ │ + │ └────────────────────────────────────────────────▶ │ 3 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry foo │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ ┌──────────────────────────────────────────── │ 13 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineEntry '(x - 1 < x)' │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 16 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 10 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 11 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 14 │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineReturn │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ └───────────────────────────────────────────▶ │ 9 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (None, foo) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ 8 │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ InlineReturn │ + │ ▼ │ + │ Inlined Proc 'foo(1)' ┌────────────────────────────────────────┐ │ + └─────────────────────────────────────────────────────▶ │ 4 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 12 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected index 35502817fd..85c21b15a5 100644 --- a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected @@ -1,201 +1,234 @@ - - ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - ┌───────────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ Inlined Proc 'foo(x, 3)' │ │ - │ ┌─────────┼──────────────────────────────────────────────────────────────┐ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ ▼ ▼ │ │ │ - │ │ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ ┌────┼──────────────────────────────────────────────────────────▶ │ 269 │ │ │ 265 │ │ │ - │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ ▲ │ │ │ │ - │ │ │ └─────────────────────────────────┐ │ Ret (None, bar) │ Inlined Proc 'foo(x, 4)' │ │ Entry main │ │ - │ │ │ │ ▼ │ │ ▼ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ │ 296 │ ──────────────────────────────────────────────────┼────────────────────────────┘ │ 266 │ ─┐ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineEntry '()' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ InlineEntry '(x, 4)' │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ ┌───────────────────────────────────────────┼────┼──────────────────────────────────────┼────────────────────────▶ │ 299 │ │ │ 283 │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry foo │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ │ │ ▼ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ └───────────────────────── │ 292 │ │ │ 284 │ │ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ InlineEntry '(x < y)' │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ │ ▼ │ ▼ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ 293 │ │ │ 326 │ │ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ Entry __VERIFIER_assert │ │ InlineReturn 'tmp' │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ │ ▼ │ ▼ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ ┌─────────────────────────────────────────────────────────── │ 300 │ │ ┌───────────────────────────────────────────── │ 294 │ ◀┘ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ │ │ Test (tmp,true) │ │ - │ │ │ │ │ │ │ ▼ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ InlineEntry '(1)' │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ │ │ 325 │ ◀─────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 323 │ ────────────────────────────────────────────────────────────────────────────────────┐ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry bar │ │ Test (tmp,false) │ │ │ - │ │ │ │ │ ▼ │ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ 301 │ ─┐ │ └────────────────────────────────────────────▶ │ 315 │ ─┐ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineEntry '()' │ │ │ InlineEntry '(2)' │ │ │ │ - │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ │ 302 │ │ │ │ 313 │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ Entry bar │ │ │ │ - │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ │ 281 │ │ │ ┌───────────────────────────────────────────── │ 314 │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineEntry '()' │ │ │ │ - │ │ │ │ │ ▼ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ │ 282 │ │ │ │ │ 272 │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineReturn 'tmp' │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ - │ │ │ │ │ ▼ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ ┌───────────────────────── │ 289 │ ◀┘ │ │ │ 273 │ │ │ │ │ - │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ │ Test (tmp,false) │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ - │ │ │ │ │ │ ▼ │ │ ▼ │ │ │ │ - │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ └───────────────────────────────────────────┼────┼────┼─────────────────────────────────┼───────────────────────── │ 298 │ ──────────────────────────────────────────────────┘ │ │ 322 │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ Test (tmp,true) │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ InlineReturn 'tmp' │ │ │ │ - │ │ │ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ └────────────────────────▶ │ 267 │ ─┐ └────────────────────────────────────────────▶ │ 317 │ ─┼────────────────────────────────────────────────┐ │ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ - │ ┌────────────────────────────────────────────────┼────┼────┘ │ InlineEntry '(x, 3)' │ │ Test (tmp,false) │ │ │ │ │ - │ │ │ │ ▼ │ ▼ │ │ │ │ │ - │ │ │ │ ┌────────────────────────────────┐ Entry foo ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ ┌───────────────────────────────────────────┼────┼─ │ 316 │ ◀────────────────────────── │ 268 │ │ ┌────────────────────────────────────────────────────────────────────────── │ 319 │ │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineEntry '(x < y)' ┌──────────────────────────────────────────────────────────────────────┘ │ ┌──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ ▼ │ │ │ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ Test (tmp,true) │ │ │ │ - │ │ │ │ │ │ 274 │ │ ┌────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 318 │ ◀─────────────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ │ InlineEntry '(x, 3)' │ │ │ - │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ 275 │ │ │ │ │ │ 290 │ │ │ │ - │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Test (! cond,false) │ │ │ │ │ Entry foo │ │ │ - │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ 270 │ │ │ │ │ │ 291 │ ─┐ │ │ │ - │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ │ InlineEntry '(x < y)' │ │ │ │ - │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ │ 271 │ │ │ │ │ │ 320 │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ InlineReturn │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ - │ │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └───────────────────────────────────────────┼────┼▶ │ 311 │ │ │ │ │ │ 286 │ │ │ │ │ - │ │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ Ret (None, foo) │ │ │ │ │ Test (! cond,false) │ │ │ │ - │ │ │ │ ▼ │ │ │ │ ▼ │ │ │ │ - │ │ │ │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ └─ │ 310 │ │ │ │ │ │ 287 │ │ │ │ │ - │ │ │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ - │ │ └───────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ - │ │ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ │ 312 │ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ - │ │ │ │ │ ▼ │ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ │ │ 285 │ ◀┘ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Ret (None, foo) │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ 280 │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ InlineReturn │ │ - │ │ │ │ Inlined Proc 'foo(x, 4)' │ │ InlineReturn ┌─────────────────────────────────┼────────────────────────────────────────────────────────────────────────┼────┼────┐ - │ │ │ │ │ ▼ ▼ │ │ │ │ - │ │ │ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ - │ │ │ └────────────────────────────┼────────────────────────────────────────────▶ │ 279 │ ◀┼───────────────────────────────────────────┐ │ │ │ - │ │ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ │ Ret (None, bar) │ │ Inlined Proc 'foo(x, 3)' │ │ │ - │ │ │ │ ▼ │ │ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ │ 288 │ │ │ │ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ Inlined Proc 'bar(2)' │ InlineReturn │ Inlined Proc 'bar(1)' │ │ │ │ - │ │ │ │ ▼ │ │ │ │ │ - │ │ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ └────────────────────────────────────────────▶ │ 295 │ ◀┘ │ │ │ │ - │ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ ▲ InlineReturn │ │ │ │ - │ │ │ │ Ret (Some 0, main) └─────────────────────────────────────────────────────────────────────────────┼────────────────────────────┘ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ 306 │ │ ┌────┼────┘ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ │ - │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌────────────────────────────┘ │ - │ │ │ ▼ │ │ - │ │ Test (! cond,false) ┌────────────────────────────────────────┐ ┌───────────────────────────┐ │ ┌────────────────────────────────────────┐ ┌────────────────────────────────┐ ┌───────────────────────────┐ │ - │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ 297 │ │ 304 │ ─┘ │ 307 │ │ 305 │ │ 278 │ │ - │ └────────────────────────────────────────┘ └───────────────────────────┘ └────────────────────────────────────────┘ └────────────────────────────────┘ └───────────────────────────┘ │ - │ │ ▲ │ │ ▲ │ - │ │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ Entry foo │ Ret (None, __VERIFIER_assert) │ Ret (None, foo) │ - │ ▼ │ ▼ ▼ │ │ - │ ┌────────────────────────────────────────┐ ┌───────────────────────────┐ InlineEntry '(x < y)' ┌────────────────────────────────────────┐ ┌────────────────────────────────┐ InlineReturn ┌───────────────────────────┐ │ - │ │ 276 │ │ 324 │ ◀────────────────────────────────────────────── │ 308 │ ─┐ │ 321 │ ─────────────────────────────────────────▶ │ 303 │ │ - │ └────────────────────────────────────────┘ └───────────────────────────┘ └────────────────────────────────────────┘ │ └────────────────────────────────┘ └───────────────────────────┘ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x < y)' ▲ │ - │ │ InlineReturn └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x < y)' │ - │ │ 277 │ ◀──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ └────────────────────────────────────────┘ - │ │ - │ │ Ret (None, foo) - │ ▼ - │ ┌────────────────────────────────────────┐ - └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ 309 │ - └────────────────────────────────────────┘ + Test (tmp,false) + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ ▼ + │ InlineReturn ┌────────────────────────────────────────────────────────────────┐ Inlined Proc 'foo(x, 4)' ┌────────────────────────────────┐ + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────▶ │ 4 │ ◀────────────────────────── │ 33 │ + │ │ └────────────────────────────────────────────────────────────────┘ └────────────────────────────────┘ + │ │ │ ▲ ▲ │ + │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ Ret (None, bar) │ Inlined Proc 'foo(x, 3)' │ InlineReturn │ InlineEntry '(x, 4)' + │ │ ▼ │ │ ▼ + │ │ ┌──────────────────┐ │ │ ┌────────────────────────────────┐ + │ │ │ 31 │ │ │ │ 34 │ + │ │ └──────────────────┘ │ │ └────────────────────────────────┘ + │ │ │ │ │ │ + │ │ │ │ │ │ Entry foo + │ │ │ │ │ ▼ + │ │ │ │ │ ┌────────────────────────────────┐ + │ │ │ │ │ │ 27 │ ─┐ + │ │ │ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ │ + │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────┘ │ │ InlineEntry '(x < y)' │ + │ │ │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ + │ │ │ │ 0 │ │ │ │ 28 │ │ + │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Entry main │ │ │ Entry __VERIFIER_assert │ + │ │ │ ▼ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ + │ │ │ │ 1 │ ─┐ │ │ │ 35 │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' + │ │ │ ▼ │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ │ + │ │ │ │ 18 │ │ │ │ │ 32 │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ Ret (None, __VERIFIER_assert) │ + │ │ │ ▼ │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ │ + │ │ │ │ 19 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ 11 │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineReturn │ + │ │ │ ▼ │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ │ + │ │ │ │ 61 │ │ │ │ │ 12 │ ◀┘ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ + │ │ │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ │ │ Ret (None, foo) + │ │ │ ▼ │ │ │ ▼ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ + │ │ │ ┌───────────────────────────────────────────── │ 29 │ ◀┘ │ └────────────────────────────────────────── │ 44 │ + │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────┘ + │ │ │ │ │ │ + │ │ │ │ │ Test (tmp,true) │ + │ │ │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ InlineEntry '(1)' │ │ ┌────────────────────────────────────────┐ │ + │ │ │ 60 │ ◀─────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 58 │ ───────────────────────────────────────────────────────────────────┐ │ + │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ + │ │ │ Entry bar │ │ Test (tmp,false) │ │ + │ │ ▼ │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ 36 │ ─┐ │ └────────────────────────────────────────────▶ │ 50 │ ─┐ │ │ + │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ InlineEntry '()' │ │ │ InlineEntry '(2)' │ │ │ + │ │ ▼ │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 37 │ │ │ │ 48 │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ Entry __VERIFIER_nondet_int │ │ │ Entry bar │ │ │ + │ │ ▼ │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 16 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ ┌───────────────────────────────────────────── │ 49 │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineEntry '()' │ │ │ + │ │ ▼ │ │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ 17 │ │ │ │ │ 7 │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ InlineReturn 'tmp' │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ ▼ │ │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ └──────────────────────────────────────── │ 24 │ ◀┘ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ 8 │ │ │ │ + │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ Test (tmp,true) │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ ▼ │ │ ▼ │ │ │ + │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 2 │ ──────────────────────────────────────────────────┘ │ │ 57 │ │ │ │ + │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ InlineEntry '(x, 3)' │ │ InlineReturn 'tmp' │ │ │ + │ ▼ │ ▼ │ │ │ + │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 3 │ └────────────────────────────────────────────▶ │ 52 │ ─┼────────────────────────────────────────────────┐ │ │ + │ └────────────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ + │ │ Entry foo │ Test (tmp,false) │ │ │ │ + │ ▼ ▼ │ │ │ │ + │ ┌────────────────────────────────┐ InlineEntry '(x < y)' ┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ 9 │ ◀───────────────────────────────────────── │ 51 │ ┌────────────────────────────────────────────────────────────────────────── │ 54 │ ─┼────────────────────────────────────────────────┼────────────────┼───────────────────────────────────────────────────────────┐ │ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ ▼ │ │ │ │ │ │ │ + │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ Test (tmp,true) │ │ │ │ + │ │ 10 │ │ ┌────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 53 │ ◀─────────────────────────────────────────────────┘ │ │ │ + │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ │ │ InlineEntry '(x, 3)' │ │ │ + │ ▼ │ │ │ │ ▼ │ │ │ + │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 5 │ │ │ │ │ │ 25 │ │ │ │ + │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ │ │ Entry foo │ │ │ + │ ▼ │ │ │ │ ▼ │ │ │ + │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ 6 │ │ │ │ │ │ 26 │ ─┐ │ │ │ + │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │ InlineReturn │ │ │ │ │ InlineEntry '(x < y)' │ │ │ │ + │ ▼ │ │ │ │ ▼ │ │ │ │ + │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ 46 │ ◀────────────────────────────────────────────┘ │ │ │ │ 55 │ │ │ │ │ + │ └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Ret (None, foo) │ │ │ │ Entry __VERIFIER_assert │ │ │ │ + │ ▼ │ │ │ ▼ │ │ │ │ + │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + └─ │ 45 │ │ │ │ │ 21 │ │ │ │ │ + └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ Inlined Proc 'foo(x, 4)' │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 22 │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 47 │ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ InlineReturn │ │ │ │ + │ │ │ ▼ │ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ │ 20 │ ◀┘ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ Ret (None, foo) │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ 15 │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ InlineReturn │ │ + │ │ │ │ InlineReturn ┌────────────────┼──────────────────────────────────────────────────────┐ │ │ + │ │ │ ▼ ▼ │ │ │ │ + │ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ + │ └────────────────────────────┼────────────────────────────────────────────▶ │ 14 │ ◀┼─────────────────────────┐ │ │ │ + │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ Ret (None, bar) │ │ │ │ │ + │ │ ▼ │ │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ Inlined Proc 'bar(2)' │ 23 │ │ Inlined Proc 'bar(1)' │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ InlineReturn │ │ Inlined Proc 'foo(x, 3)' │ │ │ + │ │ ▼ │ │ │ │ │ + │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ + │ └────────────────────────────────────────────▶ │ 30 │ ◀┘ │ │ │ │ + │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ + │ │ ▲ │ │ │ │ + │ │ Ret (Some 0, main) │ InlineReturn │ │ │ │ + │ ▼ │ │ │ │ │ + │ ┌────────────────────────────────────────┐ │ │ │ │ │ + │ │ 41 │ └──────────────────────────────────────────┼────────────────────────────┼────┼──────────────────────────┘ + │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ + ┌────────────────────────────────────────┐ InlineEntry '(x, 4)' │ │ + │ 42 │ ◀─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────┘ + └────────────────────────────────────────┘ │ + │ │ + │ Entry foo │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 43 │ ─┐ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ InlineEntry '(x < y)' │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ 59 │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Entry __VERIFIER_assert │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ 39 │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ 40 │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ 56 │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ InlineReturn │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ 38 │ ◀┘ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, foo) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 13 │ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected index d0630b0424..617aaa0385 100644 --- a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected @@ -1,279 +1,279 @@ ┌────────────────────────────────┐ - │ 156 │ + │ 0 │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 157 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(1)' │ ▼ │ ┌────────────────────────────────┐ │ - │ 170 │ │ + │ 14 │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────── │ 176 │ │ + ┌──────────────────────────────────────── │ 20 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 177 │ │ + │ │ 21 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 185 │ ─┼───────────────────────────────────────────┐ + │ │ 29 │ ─┼───────────────────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 200 │ │ │ + │ │ 44 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 183 │ │ │ + │ │ 27 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc 'foo(x, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 184 │ │ │ + │ │ 28 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 198 │ │ │ + │ │ 42 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 182 │ ◀┼───────────────────────────────────────────┘ + │ │ 26 │ ◀┼───────────────────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 168 │ │ + │ │ 12 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────▶ │ 169 │ ─┼───────────────────────────────────────────┐ + └───────────────────────────────────────▶ │ 13 │ ─┼───────────────────────────────────────────┐ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 4)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - │ 193 │ │ │ + │ 37 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - ┌──────────────────────────────────────── │ 194 │ │ │ + ┌──────────────────────────────────────── │ 38 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 202 │ │ │ + │ │ 46 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 190 │ │ │ + │ │ 34 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ Inlined Proc 'foo(x, 4)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 191 │ │ │ + │ │ 35 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 201 │ │ │ + │ │ 45 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - └───────────────────────────────────────▶ │ 192 │ │ │ + └───────────────────────────────────────▶ │ 36 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - │ 166 │ │ │ + │ 10 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - │ 167 │ ◀┼───────────────────────────────────────────┘ + │ 11 │ ◀┼───────────────────────────────────────────┘ └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ │ - │ 181 │ │ Inlined Proc 'bar(1)' + │ 25 │ │ Inlined Proc 'bar(1)' └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────── │ 171 │ ◀┘ + ┌──────────────────────────────────────── │ 15 │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ InlineEntry '(2)' │ ▼ │ ┌────────────────────────────────┐ - │ │ 174 │ + │ │ 18 │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ - │ │ 175 │ ─┐ + │ │ 19 │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 199 │ │ + │ │ 43 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 161 │ ─┼───────────────────────────────────────────┐ + │ │ 5 │ ─┼───────────────────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 162 │ │ │ + │ │ 6 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 180 │ │ │ + │ │ 24 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 164 │ │ │ + │ │ 8 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 165 │ │ │ + │ │ 9 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 163 │ ◀┼───────────────────────────────────────────┘ + │ │ 7 │ ◀┼───────────────────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 197 │ │ Inlined Proc 'foo(x, 3)' + │ │ 41 │ │ Inlined Proc 'foo(x, 3)' │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - ┌────────────────────────────┼──────────────────────────────────────── │ 158 │ ◀┘ + ┌────────────────────────────┼──────────────────────────────────────── │ 2 │ ◀┘ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 4)' │ │ ▼ │ │ ┌────────────────────────────────┐ - │ │ │ 159 │ + │ │ │ 3 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ - │ │ │ 186 │ ─┐ + │ │ │ 30 │ ─┐ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 187 │ │ + │ │ │ 31 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 189 │ │ + │ │ │ 33 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Inlined Proc 'foo(x, 4)' │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 188 │ │ + │ │ │ 32 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 172 │ │ + │ │ │ 16 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 173 │ ◀┘ + │ │ │ 17 │ ◀┘ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ - │ │ │ 196 │ + │ │ │ 40 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ - └────────────────────────────┼───────────────────────────────────────▶ │ 160 │ + └────────────────────────────┼───────────────────────────────────────▶ │ 4 │ │ └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ - │ Inlined Proc 'bar(2)' │ 195 │ + │ Inlined Proc 'bar(2)' │ 39 │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ - └───────────────────────────────────────▶ │ 178 │ + └───────────────────────────────────────▶ │ 22 │ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ - │ 179 │ + │ 23 │ └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected index aef127c365..89378c87e4 100644 --- a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected @@ -1,171 +1,171 @@ ┌────────────────────────────────┐ - │ 98 │ + │ 0 │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 99 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(1)' │ ▼ │ ┌────────────────────────────────┐ │ - │ 124 │ │ + │ 26 │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ │ - ┌───────────────────────── │ 107 │ │ + ┌───────────────────────── │ 9 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(1, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 108 │ │ + │ │ 10 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 112 │ ─┼────────────────────────────┐ + │ │ 14 │ ─┼────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 125 │ │ │ + │ │ 27 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 110 │ │ │ + │ │ 12 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc 'foo(1, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 111 │ │ │ + │ │ 13 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 123 │ │ │ + │ │ 25 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 109 │ ◀┼────────────────────────────┘ + │ │ 11 │ ◀┼────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 102 │ │ + │ │ 4 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └────────────────────────▶ │ 103 │ │ Inlined Proc 'bar(1)' + └────────────────────────▶ │ 5 │ │ Inlined Proc 'bar(1)' └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ │ - │ 120 │ │ + │ 22 │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ - ┌───────────────────────── │ 104 │ ◀┘ + ┌───────────────────────── │ 6 │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ InlineEntry '(2)' │ ▼ │ ┌────────────────────────────────┐ - │ │ 105 │ + │ │ 7 │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ - │ │ 115 │ ─┐ + │ │ 17 │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(1, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 116 │ │ + │ │ 18 │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 121 │ ─┼────────────────────────────┐ + │ │ 23 │ ─┼────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 100 │ │ │ + │ │ 2 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 101 │ │ │ + │ │ 3 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc 'bar(2)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 118 │ │ │ + │ │ 20 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 126 │ │ │ + │ │ 28 │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 117 │ ◀┼────────────────────────────┘ + │ │ 19 │ ◀┼────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 113 │ │ Inlined Proc 'foo(1, 3)' + │ │ 15 │ │ Inlined Proc 'foo(1, 3)' │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 114 │ ◀┘ + │ │ 16 │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ - │ │ 119 │ + │ │ 21 │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ - └────────────────────────▶ │ 106 │ + └────────────────────────▶ │ 8 │ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ - │ 122 │ + │ 24 │ └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_true-unreach-call.expected index ad8c1df4e0..bd10a33329 100644 --- a/tests/sv-comp/cfg/multicall_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_true-unreach-call.expected @@ -1,47 +1,36 @@ - ┌────────────────────────────────┐ - │ 52 │ - └────────────────────────────────┘ - │ - ┌──────────────────────────────────────────────────┐ │ Entry main - │ │ ▼ - │ ┌──────────────────┐ InlineReturn ┌─────────────────────┐ Inlined Proc 'foo(1)' ┌────────────────────────────────┐ - │ │ 61 │ ───────────────────────▶ │ 55 │ ◀───────────────────────────────────────────── │ 53 │ - │ └──────────────────┘ └─────────────────────┘ └────────────────────────────────┘ - │ ▲ │ │ - │ │ Ret (None, foo) └──────────────────────┐ │ InlineEntry '(1)' - │ │ │ ▼ - │ │ Inlined Proc 'foo(1)' ┌─────────────────────┐ │ ┌────────────────────────────────┐ - └────┼─────────────────────────────────────────▶ │ 56 │ └───────────────────────────────────────────▶ │ 54 │ - │ └─────────────────────┘ └────────────────────────────────┘ - │ │ │ - │ │ Ret (Some 0, main) │ Entry foo - │ ▼ ▼ - │ ┌─────────────────────┐ ┌────────────────────────────────┐ InlineEntry '(x - 1 < x)' ┌────┐ - │ │ 57 │ │ 62 │ ───────────────────────────▶ │ 64 │ - │ └─────────────────────┘ └────────────────────────────────┘ └────┘ - │ │ │ - │ ┌───────────────────────────────────────────────┘ │ - │ │ │ - │ │ ┌────────────────────────────────┐ Entry __VERIFIER_assert │ - │ │ │ 58 │ ◀──────────────────────────────┘ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ │ Test (! cond,false) - │ │ ▼ - │ │ ┌────────────────────────────────┐ - │ │ │ 59 │ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) - │ │ ▼ - │ │ ┌────────────────────────────────┐ - │ │ │ 63 │ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ InlineReturn - │ │ ▼ - │ │ ┌────────────────────────────────┐ - │ └───────────────────────────────────────────▶ │ 60 │ - │ └────────────────────────────────┘ - │ │ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────┐ │ + │ │ 0 │ │ + │ └────────────────────────────┘ │ + │ │ │ + │ InlineReturn │ Entry main │ + ▼ ▼ │ + ┌─────────────────────┐ Inlined Proc 'foo(1)' ┌────────────────────────────┐ │ + ┌────────────────────── │ 3 │ ◀─────────────────────── │ 1 │ │ + │ └─────────────────────┘ └────────────────────────────┘ │ + │ │ │ │ + │ Inlined Proc 'foo(1)' └──────────────────────┐ │ InlineEntry '(1)' │ + │ │ ▼ │ + │ ┌─────────────────────┐ │ ┌────────────────────────────┐ │ + └─────────────────────▶ │ 4 │ └─────────────────────▶ │ 2 │ │ + └─────────────────────┘ └────────────────────────────┘ │ + │ │ │ + │ Ret (Some 0, main) │ Entry foo │ + ▼ ▼ │ + ┌─────────────────────┐ ┌────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' ┌────────────────────────────────┐ Ret (None, foo) ┌───┐ + │ 5 │ │ 10 │ ─────────────────────────────────────────────▶ │ 8 │ ─────────────────▶ │ 9 │ + └─────────────────────┘ └────────────────────────────┘ └────────────────────────────────┘ └───┘ + │ ▲ + │ InlineEntry '(x - 1 < x)' │ InlineReturn + ▼ │ + ┌────────────────────────────┐ ┌────────────────────────────────┐ + │ 12 │ │ 11 │ + └────────────────────────────┘ └────────────────────────────────┘ + │ ▲ + │ Entry __VERIFIER_assert │ Ret (None, __VERIFIER_assert) + ▼ │ + ┌────────────────────────────┐ Test (! cond,false) ┌────────────────────────────────┐ + │ 6 │ ─────────────────────────────────────────────▶ │ 7 │ + └────────────────────────────┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected index 131d47879c..ec88f178ac 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -1,99 +1,99 @@ - ┌────────────────────────────────────────┐ - │ 87 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 88 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 94 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 95 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 89 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ -┌────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ -│ 97 │ ◀────────────────── │ 90 │ ◀┘ -└────┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,true) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ 96 │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 1' - │ ▼ - │ Assign 'x = 2' ┌────────────────────────────────────────┐ - └──────────────────────▶ │ 98 │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ 102 │ - └────────────────────────────────────────┘ - │ - │ Test (x <= 2,true) - ▼ - ┌────────────────────────────────────────┐ - │ 103 │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1' - ▼ - ┌────────────────────────────────────────┐ - │ 91 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 92 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 100 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 101 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 104 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 93 │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 99 │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ 0 │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ 1 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 7 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 8 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 2 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ │ +│ 9 │ ◀───────────────── │ 3 │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ 10 │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └────────────────────▶ │ 11 │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ 15 │ + └────────────────────────────────────────┘ + │ + │ Test (x <= 2,true) + ▼ + ┌────────────────────────────────────────┐ + │ 16 │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1' + ▼ + ┌────────────────────────────────────────┐ + │ 4 │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 5 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 13 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 14 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 17 │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ 6 │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ 12 │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected index e2b68f50eb..44f5f26406 100644 --- a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 85 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 86 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 87 │ │ + │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 88 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 94 │ │ + │ 9 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 89 │ ◀┘ + │ 4 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 90 │ ─┐ + │ 5 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 91 │ │ + ┌─────────────────── │ 6 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 3,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 93 │ ─┼────────────────────────────────────────────────┐ + │ │ 8 │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x < 2,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼─────────────────── │ 99 │ │ │ + ┌────┼─────────────────── │ 14 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 100 │ │ │ + │ │ │ 15 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 96 │ │ │ + │ │ │ 11 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x < 3,false) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 97 │ │ │ + │ │ │ 12 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 98 │ │ │ + │ │ │ 13 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x < 2,false) │ │ ▼ ▼ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └──────────────────▶ │ 92 │ + │ └──────────────────▶ │ 7 │ │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 95 │ │ + │ │ 10 │ │ │ └────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected index 3dd83faf20..0efe3e380b 100644 --- a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 82 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 83 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 84 │ │ + │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 85 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 91 │ │ + │ 9 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 86 │ ◀┘ + │ 4 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 87 │ ─┐ + │ 5 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 88 │ │ + ┌─────────────────── │ 6 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 3,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 90 │ ─┼────────────────────────────────────────────────┐ + │ │ 8 │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x == 1,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼─────────────────── │ 96 │ │ │ + ┌────┼─────────────────── │ 14 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 97 │ │ │ + │ │ │ 15 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 93 │ │ │ + │ │ │ 11 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x < 3,false) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 94 │ │ │ + │ │ │ 12 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 95 │ │ │ + │ │ │ 13 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x == 1,false) │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └──────────────────▶ │ 89 │ + │ └──────────────────▶ │ 7 │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 92 │ │ + │ │ 10 │ │ │ └────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected index f953de97ab..3f2ddfeffe 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected @@ -5,89 +5,89 @@ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 99 │ │ │ + │ │ │ 0 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry main │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 100 │ ─┐ │ │ + │ │ │ 1 │ ─┐ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 107 │ │ │ │ + │ │ │ 8 │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Test (x < 2,false) │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 108 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ 9 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 117 │ │ │ │ + │ │ │ 18 │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 109 │ ◀┘ │ │ + │ │ │ 10 │ ◀┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 0,false) │ Assign 'x = tmp' │ │ │ ▼ ▼ │ │ │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ - └──────────────────▶ │ 113 │ ─┐ │ 110 │ ──────────────────────────────────────────────────┘ │ + └──────────────────▶ │ 14 │ ─┐ │ 11 │ ──────────────────────────────────────────────────┘ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(1)' │ │ Test (x > 0,true) │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 119 │ │ │ 111 │ ───────────────────────────────────────────────────────┘ + │ 20 │ │ │ 12 │ ───────────────────────────────────────────────────────┘ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ │ Test (x < 2,true) ▼ │ ▼ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ - │ 114 │ │ │ 112 │ ─┐ + │ 15 │ │ │ 13 │ ─┐ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(1)' │ InlineEntry '(x == 1)' │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 115 │ │ │ 103 │ │ + │ 16 │ │ │ 4 │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 118 │ │ │ 104 │ │ + │ 19 │ │ │ 5 │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 116 │ ◀┘ │ 101 │ │ + │ 17 │ ◀┘ │ 2 │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 102 │ │ + │ │ 3 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 105 │ ◀┘ + │ │ 6 │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Ret (Some 0, main) │ ▼ │ Ret (Some 1, main) ┌────────────────────────────────────────┐ - └─────────────────────────────────────────────────────────────────────▶ │ 106 │ + └─────────────────────────────────────────────────────────────────────▶ │ 7 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected index e7f993a79e..e8ea9a36a7 100644 --- a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected @@ -1,93 +1,93 @@ ┌────────────────────────────────────────┐ - │ 94 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 95 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 98 │ │ + │ 4 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 99 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 5 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 113 │ │ + │ 19 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 100 │ ◀┘ + │ 6 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 101 │ ─┐ + │ 7 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 104 │ │ Test (x > 0,false) + ┌────────────────── │ 10 │ │ Test (x > 0,false) │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 2,false) │ │ ▼ │ ┌────────────────────────────────┐ InlineEntry '(1)' │ ┌────────────────────────────────────────┐ │ -│ 96 │ ◀──────────────────────┼────────────────── │ 106 │ ◀┘ +│ 2 │ ◀──────────────────────┼────────────────── │ 12 │ ◀┘ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ Test (x < 2,true) └─────────────────────────────────────────┐ ▼ │ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ -│ 97 │ └─────────────────▶ │ 105 │ ─┼────────────────────────────────────────────────┐ +│ 3 │ └─────────────────▶ │ 11 │ ─┼────────────────────────────────────────────────┐ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Test (! cond,false) │ InlineEntry '(x == 1)' │ │ ▼ ▼ │ │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ -│ 110 │ │ 109 │ │ │ +│ 16 │ │ 15 │ │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ │ ▼ ▼ │ │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ -│ 111 │ ───────────────────────┐ │ 102 │ │ │ +│ 17 │ ───────────────────────┐ │ 8 │ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 103 │ │ │ + │ │ 9 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ InlineReturn │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 112 │ │ │ + │ │ 18 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(1)' │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────▶ │ 107 │ + └─────────────────▶ │ 13 │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 108 │ + │ 14 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected index a938376e1b..08afea2b9a 100644 --- a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected @@ -1,87 +1,87 @@ ┌────────────────────────────────────────┐ - │ 75 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 76 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 77 │ │ + │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 78 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 85 │ │ + │ 10 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 79 │ ◀┘ + │ 4 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 80 │ ─┐ + │ 5 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 82 │ │ + ┌─────────────────── │ 7 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 2,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 83 │ ─┼────────────────────────────────────────────────┐ + │ │ 8 │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 88 │ │ │ + │ │ 13 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ Test (x < 2,false) │ 86 │ │ │ + │ Test (x < 2,false) │ 11 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 87 │ │ │ + │ │ 12 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 89 │ │ │ + │ │ 14 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ Test (x > 0,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └──────────────────▶ │ 84 │ + └──────────────────▶ │ 9 │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 81 │ + │ 6 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected index c3731e3731..7b54a56ece 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -1,81 +1,81 @@ ┌────────────────────────────────────────┐ - │ 96 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 97 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 102 │ │ + │ 6 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 103 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 7 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 110 │ │ + │ 14 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 104 │ ◀┘ + │ 8 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌─────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ - ┌──────────────────▶ │ 108 │ ◀────────────────────── │ 105 │ + ┌──────────────────▶ │ 12 │ ◀────────────────────── │ 9 │ │ └─────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ Test (x < 2,false) │ │ Test (x > 0,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ - └──────────────────────┼──────────────────────────────────────────── │ 106 │ + └──────────────────────┼──────────────────────────────────────────── │ 10 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (x < 2,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 107 │ + │ │ 11 │ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'tmp___0 = 1' │ ▼ │ Assign 'tmp___0 = 0' ┌────────────────────────────────────────┐ - └───────────────────────────────────────────▶ │ 109 │ + └───────────────────────────────────────────▶ │ 13 │ └────────────────────────────────────────┘ │ │ Assign 'y = tmp___0' ▼ ┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ - │ 100 │ ◀────────────────────── │ 111 │ + │ 4 │ ◀────────────────────── │ 15 │ └─────────────────────┘ └────────────────────────────────────────┘ │ │ │ Ret (Some 0, main) │ Test (y,true) ▼ ▼ ┌─────────────────────┐ ┌────────────────────────────────────────┐ - │ 101 │ │ 112 │ + │ 5 │ │ 16 │ └─────────────────────┘ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ 98 │ + │ 2 │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ 99 │ + │ 3 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected index a30c746881..e8a4c886b1 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -1,75 +1,75 @@ ┌────────────────────────────────────────┐ -│ 67 │ +│ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ -│ 68 │ ─┐ +│ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 69 │ │ +│ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 70 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' +│ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 76 │ │ +│ 9 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 72 │ ◀┘ +│ 5 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ -│ 73 │ ─┐ +│ 6 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 74 │ │ Test (x > 0,false) +│ 7 │ │ Test (x > 0,false) └────────────────────────────────────────┘ │ │ │ │ Test (x < 0,false) │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 75 │ ◀┘ +│ 8 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'tmp___0 = 0' ▼ ┌────────────────────────────────────────┐ -│ 79 │ +│ 12 │ └────────────────────────────────────────┘ │ │ Assign 'y = tmp___0' ▼ ┌────────────────────────────────────────┐ -│ 77 │ +│ 10 │ └────────────────────────────────────────┘ │ │ Test (y,false) ▼ ┌────────────────────────────────────────┐ -│ 78 │ +│ 11 │ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ -│ 71 │ +│ 4 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected index f0b2b8a75e..2910f985c9 100644 --- a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 85 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 86 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 87 │ │ + │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 88 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 91 │ │ + │ 6 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 89 │ ◀┘ + │ 4 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 90 │ ─┐ + │ 5 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x < 1,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 99 │ │ + ┌────────────────── │ 14 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x > 2,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 100 │ ─┼────────────────────────────────────────────────┐ + │ │ 15 │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x > 1,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼────────────────── │ 95 │ │ │ + ┌────┼────────────────── │ 10 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 96 │ │ │ + │ │ │ 11 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 93 │ │ │ + │ │ │ 8 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 2,true) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 94 │ │ │ + │ │ │ 9 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 98 │ │ │ + │ │ │ 13 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x > 1,true) │ │ ▼ ▼ ▼ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └─────────────────▶ │ 97 │ + │ └─────────────────▶ │ 12 │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 92 │ │ + │ │ 7 │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected index 9caf2c8722..4198737683 100644 --- a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 82 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 83 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 84 │ │ + │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 85 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 88 │ │ + │ 6 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 86 │ ◀┘ + │ 4 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 87 │ ─┐ + │ 5 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x < 1,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 96 │ │ + ┌────────────────── │ 14 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x > 2,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 97 │ ─┼────────────────────────────────────────────────┐ + │ │ 15 │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x != 1,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼────────────────── │ 92 │ │ │ + ┌────┼────────────────── │ 10 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 93 │ │ │ + │ │ │ 11 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 90 │ │ │ + │ │ │ 8 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 2,true) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 91 │ │ │ + │ │ │ 9 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 95 │ │ │ + │ │ │ 13 │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x != 1,true) │ │ ▼ ▼ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └─────────────────▶ │ 94 │ + │ └─────────────────▶ │ 12 │ │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 89 │ │ + │ │ 7 │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected index 936c7325ad..8a6729bf9d 100644 --- a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected @@ -1,87 +1,87 @@ ┌────────────────────────────────────────┐ - │ 75 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 76 │ ─┐ + │ 1 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 77 │ │ + │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 78 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 82 │ │ + │ 7 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 79 │ ◀┘ + │ 4 │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 80 │ ─┐ + │ 5 │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x < 1,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 89 │ │ + ┌────────────────── │ 14 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x > 1,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 85 │ ─┼────────────────────────────────────────────────┐ + │ │ 10 │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 86 │ │ │ + │ │ 11 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ Test (x > 1,true) │ 83 │ │ │ + │ Test (x > 1,true) │ 8 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 84 │ │ │ + │ │ 9 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 88 │ │ │ + │ │ 13 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ Test (x < 1,true) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────▶ │ 87 │ + └─────────────────▶ │ 12 │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 81 │ + │ 6 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/eq_double_true-unreach-call.expected b/tests/sv-comp/eq/eq_double_true-unreach-call.expected index aa592b3eda..ab09689b24 100644 --- a/tests/sv-comp/eq/eq_double_true-unreach-call.expected +++ b/tests/sv-comp/eq/eq_double_true-unreach-call.expected @@ -1,141 +1,141 @@ ┌────────────────────────────────────────┐ - │ 143 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ InlineReturn ┌────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(a == b)' - ┌─────────────────────────────────────────────────────▶ │ 144 │ ◀─────────────────────────────────────────────────┐ + ┌─────────────────────────────────────────────────────▶ │ 1 │ ◀─────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (1,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 157 │ ─┐ │ + │ │ 14 │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 165 │ │ │ + │ │ 22 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 166 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ 23 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 163 │ │ │ + │ │ 20 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 159 │ ◀┘ │ + │ │ 16 │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 160 │ │ + │ │ 17 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 147 │ ─┐ │ + │ │ 4 │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 148 │ │ │ + │ │ 5 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 162 │ │ │ + │ │ 19 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 161 │ │ │ + │ │ 18 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 158 │ │ │ + │ │ 15 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ ┌───────────────────────────────────────────────── │ 149 │ ◀┘ │ + │ ┌───────────────────────────────────────────────── │ 6 │ ◀┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' ┌────────────────────────────────────────────────┘ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 164 │ │ + │ │ │ 21 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ 154 │ │ + │ │ Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ 11 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 155 │ │ + │ │ │ 12 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp___0' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ └────────────────────────────────────────────────▶ │ 150 │ │ + │ └────────────────────────────────────────────────▶ │ 7 │ │ │ └────────────────────────────────────────┘ │ │ │ │ └────┐ │ Assign 'a = tmp___0' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 151 │ │ + │ │ 8 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'b = a' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 156 │ ─┘ + │ │ 13 │ ─┘ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(a == b)' │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 152 │ + │ │ 9 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 153 │ + │ │ 10 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 145 │ + │ │ 2 │ │ └────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────────────┐ - └───────────────────────────────────────────────── │ 146 │ + └───────────────────────────────────────────────── │ 3 │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/eq_single_true-unreach-call.expected b/tests/sv-comp/eq/eq_single_true-unreach-call.expected index f2a329738d..c4b20b3b26 100644 --- a/tests/sv-comp/eq/eq_single_true-unreach-call.expected +++ b/tests/sv-comp/eq/eq_single_true-unreach-call.expected @@ -1,75 +1,75 @@ ┌────────────────────────────────────────┐ - │ 80 │ + │ 0 │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ InlineReturn - ┌────────────────────────────────────────▶ │ 81 │ ◀─────────────────────────────────────────────────┐ + ┌────────────────────────────────────────▶ │ 1 │ ◀─────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (1,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 86 │ ─┐ │ + │ │ 6 │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 87 │ │ │ + │ │ 7 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 90 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ 10 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x == y)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 82 │ │ │ + │ │ 2 │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 83 │ ◀┘ │ + │ │ 3 │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' ┌────────────────────────────────────────────────┘ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 88 │ │ + │ │ 8 │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - └───────────────────────────────────────── │ 89 │ │ + └───────────────────────────────────────── │ 9 │ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x == y)' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 92 │ │ + │ 12 │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 84 │ │ + │ 4 │ │ └────────────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 85 │ │ + │ 5 │ │ └────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 91 │ ─┘ + │ 11 │ ─┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/multivar_false-unreach-call1.expected b/tests/sv-comp/eq/multivar_false-unreach-call1.expected index c01f6bfbc5..348de9666c 100644 --- a/tests/sv-comp/eq/multivar_false-unreach-call1.expected +++ b/tests/sv-comp/eq/multivar_false-unreach-call1.expected @@ -2,89 +2,89 @@ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 110 │ │ + │ │ 0 │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Entry main │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 111 │ ─┐ │ + │ │ 1 │ ─┐ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 118 │ │ │ + │ │ 8 │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_uint │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 119 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ │ 9 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 126 │ │ │ + │ │ 16 │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 122 │ ◀┘ │ + │ │ 12 │ ◀┘ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 123 │ │ + │ │ 13 │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌─────────────────────────┐ Test (x < 1024U,true) ┌─────────────────────────────────────────┐ Assign 'y = y + 1U' │ - │ │ 124 │ ◀─────────────────────── │ 129 │ ◀──────────────────────────────────────────────────┘ + │ │ 14 │ ◀─────────────────────── │ 19 │ ◀──────────────────────────────────────────────────┘ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ - └─ │ 125 │ │ 128 │ ─┐ + └─ │ 15 │ │ 18 │ ─┐ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x < y)' │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 114 │ │ + │ 4 │ │ └─────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ - │ 127 │ ◀─────────────────────── │ 115 │ │ + │ 17 │ ◀─────────────────────── │ 5 │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 120 │ │ 112 │ │ + │ 10 │ │ 2 │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 121 │ │ 113 │ │ + │ 11 │ │ 3 │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 116 │ ◀┘ + │ 6 │ ◀┘ └─────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌─────────────────────────────────────────┐ - │ 117 │ + │ 7 │ └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/multivar_true-unreach-call1.expected b/tests/sv-comp/eq/multivar_true-unreach-call1.expected index bfd9aa576f..ca2b36923d 100644 --- a/tests/sv-comp/eq/multivar_true-unreach-call1.expected +++ b/tests/sv-comp/eq/multivar_true-unreach-call1.expected @@ -2,89 +2,89 @@ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 110 │ │ + │ │ 0 │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Entry main │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 111 │ ─┐ │ + │ │ 1 │ ─┐ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 118 │ │ │ + │ │ 8 │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_uint │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 119 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ │ 9 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 126 │ │ │ + │ │ 16 │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 122 │ ◀┘ │ + │ │ 12 │ ◀┘ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 123 │ │ + │ │ 13 │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌─────────────────────────┐ Test (x < 1024U,true) ┌─────────────────────────────────────────┐ Assign 'y = y + 1U' │ - │ │ 124 │ ◀─────────────────────── │ 129 │ ◀──────────────────────────────────────────────────┘ + │ │ 14 │ ◀─────────────────────── │ 19 │ ◀──────────────────────────────────────────────────┘ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ - └─ │ 125 │ │ 128 │ ─┐ + └─ │ 15 │ │ 18 │ ─┐ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x == y)' │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 114 │ │ + │ 4 │ │ └─────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ - │ 127 │ ◀─────────────────────── │ 115 │ │ + │ 17 │ ◀─────────────────────── │ 5 │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 120 │ │ 112 │ │ + │ 10 │ │ 2 │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 121 │ │ 113 │ │ + │ 11 │ │ 3 │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 116 │ ◀┘ + │ 6 │ ◀┘ └─────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌─────────────────────────────────────────┐ - │ 117 │ + │ 7 │ └─────────────────────────────────────────┘ From e1c3144b4c794c5c09c72389f19007784b5f8122 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 15:56:33 +0300 Subject: [PATCH 176/689] Extract duplicated log messages to a function --- src/autoTuneSvompSpec.ml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index b0b41dd889..be91619bc7 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -3,24 +3,26 @@ open GobConfig open AutoTune +let logEnablingAnalyses spec ana = Logs.info "Specification: %s -> enabling soundness analyses \"%s\"" (Svcomp.Specification.to_string [spec]) (String.concat ", " ana) + (* TODO: have only one function for matching all specifications and find a place where it can be called. *) let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) let uafAna = ["base"; "useAfterFree"] in - Logs.info "Specification: ValidFree -> enabling soundness analyses \"%s\"" (String.concat ", " uafAna); + logEnablingAnalyses spec uafAna; enableAnalyses uafAna | ValidDeref -> (* Enable the soundness analyses for ValidDeref spec *) let memOobAna = ["base"; "memOutOfBounds"] in + logEnablingAnalyses spec memOobAna; + enableAnalyses memOobAna; set_bool "ana.arrayoob" true; Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; - set_bool "cil.addNestedScopeAttr" true; - Logs.info "Specification: ValidDeref -> enabling soundness analyses \"%s\"" (String.concat ", " memOobAna); - enableAnalyses memOobAna + set_bool "cil.addNestedScopeAttr" true | ValidMemtrack | ValidMemcleanup -> (* Enable the soundness analyses for ValidMemtrack and ValidMemcleanup specs *) let memLeakAna = ["memLeak"] in - Logs.info "Specification: ValidMemtrack and ValidMemcleanup -> enabling soundness analyses \"%s\"" (String.concat ", " memLeakAna); + logEnablingAnalyses spec memLeakAna; enableAnalyses memLeakAna | _ -> () @@ -31,7 +33,7 @@ let enableAnalysesForTerminationSpecification (spec: Svcomp.Specification.t) = match spec with | Termination -> (* Enable the soundness analyses for Termination spec *) let terminationAna = ["termination"] in - Logs.info "Specification: Termination -> enabling soundness analyses \"%s\"" (String.concat ", " terminationAna); + logEnablingAnalyses spec terminationAna; enableAnalyses terminationAna | _ -> () @@ -43,7 +45,7 @@ let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = | UnreachCall s -> () | NoDataRace -> (* Enable the soundness analyses for NoDataRace spec *) let dataRaceAna = ["access"; "race"] in - Logs.info "Specification: NoDataRace -> enabling soundness analyses \"%s\"" (String.concat ", " dataRaceAna); + logEnablingAnalyses spec dataRaceAna; enableAnalyses dataRaceAna | NoOverflow -> (* Enable the soundness analyses for NoOverflow spec *) Logs.info "Setting \"ana.int.interval\" to true"; From abfedf16829d518e838379f3a3c288d4ea62c750 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 15:58:23 +0300 Subject: [PATCH 177/689] Refactor --- src/autoTuneSvompSpec.ml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index be91619bc7..ef08a19327 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -9,21 +9,21 @@ let logEnablingAnalyses spec ana = Logs.info "Specification: %s -> enabling soun let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) - let uafAna = ["base"; "useAfterFree"] in - logEnablingAnalyses spec uafAna; - enableAnalyses uafAna + let analyses = ["base"; "useAfterFree"] in + logEnablingAnalyses spec analyses; + enableAnalyses analyses | ValidDeref -> (* Enable the soundness analyses for ValidDeref spec *) - let memOobAna = ["base"; "memOutOfBounds"] in - logEnablingAnalyses spec memOobAna; - enableAnalyses memOobAna; + let analyses = ["base"; "memOutOfBounds"] in + logEnablingAnalyses spec analyses; + enableAnalyses analyses; set_bool "ana.arrayoob" true; Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; set_bool "cil.addNestedScopeAttr" true | ValidMemtrack | ValidMemcleanup -> (* Enable the soundness analyses for ValidMemtrack and ValidMemcleanup specs *) - let memLeakAna = ["memLeak"] in - logEnablingAnalyses spec memLeakAna; - enableAnalyses memLeakAna + let analyses = ["memLeak"] in + logEnablingAnalyses spec analyses; + enableAnalyses analyses | _ -> () let enableAnalysesForMemSafetySpecification () = @@ -32,9 +32,9 @@ let enableAnalysesForMemSafetySpecification () = let enableAnalysesForTerminationSpecification (spec: Svcomp.Specification.t) = match spec with | Termination -> (* Enable the soundness analyses for Termination spec *) - let terminationAna = ["termination"] in - logEnablingAnalyses spec terminationAna; - enableAnalyses terminationAna + let analyses = ["termination"] in + logEnablingAnalyses spec analyses; + enableAnalyses analyses | _ -> () let enableAnalysesForTerminationSpecification () = @@ -44,9 +44,9 @@ let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = match spec with | UnreachCall s -> () | NoDataRace -> (* Enable the soundness analyses for NoDataRace spec *) - let dataRaceAna = ["access"; "race"] in - logEnablingAnalyses spec dataRaceAna; - enableAnalyses dataRaceAna + let analyses = ["access"; "race"] in + logEnablingAnalyses spec analyses; + enableAnalyses analyses | NoOverflow -> (* Enable the soundness analyses for NoOverflow spec *) Logs.info "Setting \"ana.int.interval\" to true"; set_bool "ana.int.interval" true From 8be1263b948c4a60c1d1e903373b6e98e733a463 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 16:08:02 +0300 Subject: [PATCH 178/689] Extract duplicated option enabling to a function --- src/autoTuneSvompSpec.ml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvompSpec.ml index ef08a19327..6351ec65af 100644 --- a/src/autoTuneSvompSpec.ml +++ b/src/autoTuneSvompSpec.ml @@ -5,6 +5,13 @@ open AutoTune let logEnablingAnalyses spec ana = Logs.info "Specification: %s -> enabling soundness analyses \"%s\"" (Svcomp.Specification.to_string [spec]) (String.concat ", " ana) +let enableOptions options = + let enableOpt option = + Logs.info "Setting \"%s\" to true" option; + set_bool option true + in + List.iter enableOpt options + (* TODO: have only one function for matching all specifications and find a place where it can be called. *) let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with @@ -16,9 +23,8 @@ let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = let analyses = ["base"; "memOutOfBounds"] in logEnablingAnalyses spec analyses; enableAnalyses analyses; - set_bool "ana.arrayoob" true; - Logs.info "Setting \"cil.addNestedScopeAttr\" to true"; - set_bool "cil.addNestedScopeAttr" true + let options = ["ana.arrayoob"; "cil.addNestedScopeAttr"] in + enableOptions options | ValidMemtrack | ValidMemcleanup -> (* Enable the soundness analyses for ValidMemtrack and ValidMemcleanup specs *) let analyses = ["memLeak"] in @@ -48,8 +54,8 @@ let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = logEnablingAnalyses spec analyses; enableAnalyses analyses | NoOverflow -> (* Enable the soundness analyses for NoOverflow spec *) - Logs.info "Setting \"ana.int.interval\" to true"; - set_bool "ana.int.interval" true + let options = ["ana.int.interval"] in + enableOptions options | _ -> () let enableAnalysesForSpecification () = From a70b570567a816bce7e45478223a84f3c3886e7e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 16:11:26 +0300 Subject: [PATCH 179/689] Fix typo, rename: AutoTuneSvompSpec -> AutoTuneSvcompSpec --- src/{autoTuneSvompSpec.ml => autoTuneSvcompSpec.ml} | 0 src/goblint.ml | 4 ++-- src/goblint_lib.ml | 2 +- src/maingoblint.ml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/{autoTuneSvompSpec.ml => autoTuneSvcompSpec.ml} (100%) diff --git a/src/autoTuneSvompSpec.ml b/src/autoTuneSvcompSpec.ml similarity index 100% rename from src/autoTuneSvompSpec.ml rename to src/autoTuneSvcompSpec.ml diff --git a/src/goblint.ml b/src/goblint.ml index dd4571092f..4a585e6826 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -36,7 +36,7 @@ let main () = Logs.debug "%s" (GobUnix.localtime ()); Logs.debug "%s" GobSys.command_line; (* When analyzing a termination specification, activate the termination analysis before pre-processing. *) - if get_string "ana.specification" <> "" then AutoTuneSvompSpec.enableAnalysesForTerminationSpecification (); + if get_string "ana.specification" <> "" then AutoTuneSvcompSpec.enableAnalysesForTerminationSpecification (); if AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( @@ -58,7 +58,7 @@ let main () = in (* This is run independant of the autotuner being enabled or not be sound for programs with longjmp *) AutoTune.activateLongjmpAnalysesWhenRequired (); - if get_string "ana.specification" <> "" then AutoTuneSvompSpec.enableAnalysesForSpecification (); + if get_string "ana.specification" <> "" then AutoTuneSvcompSpec.enableAnalysesForSpecification (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; file |> do_analyze changeInfo; do_html_output (); diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 6fb8abb489..3619679dac 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -59,7 +59,7 @@ module GobConfig = GobConfig module AfterConfig = AfterConfig module AutoTune = AutoTune -module AutoTuneSvompSpec = AutoTuneSvompSpec +module AutoTuneSvcompSpec = AutoTuneSvcompSpec module JsonSchema = JsonSchema module Options = Options diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 9c8dc02f49..2892bdee34 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -202,7 +202,7 @@ let handle_options () = check_arguments (); 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 get_string "ana.specification" <> "" then - AutoTuneSvompSpec.enableAnalysesForMemSafetySpecification (); + AutoTuneSvcompSpec.enableAnalysesForMemSafetySpecification (); if AutoTune.specificationMemSafetyIsActivated () then AutoTune.focusOnMemSafetySpecification (); AfterConfig.run (); From 218ed38704eb7313fef2f6c000c4ef9c11209518 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 16 May 2024 16:16:40 +0300 Subject: [PATCH 180/689] Replace enumerated ARG node labels in tests with constant --- src/config/options.schema.json | 7 + src/framework/control.ml | 21 +- src/util/server.ml | 8 +- src/witness/argTools.ml | 43 +- .../basic/for_fun_true-unreach-call.expected | 22 +- .../for_odd_vesal_true-unreach-call.expected | 166 +++---- .../basic/for_true-unreach-call.expected | 22 +- .../global_init_true-unreach-call.expected | 16 +- .../basic/if_det_false-unreach-call.expected | 14 +- .../if_det_incr_true-unreach-call.expected | 10 +- .../basic/if_det_true-unreach-call.expected | 8 +- .../basic/if_mod_false-unreach-call.expected | 22 +- .../basic/if_mod_true-unreach-call.expected | 16 +- .../if_nondet_fun_false-unreach-call.expected | 22 +- .../if_nondet_var_false-unreach-call.expected | 12 +- ...clude_multiple_false-unreach-call.expected | 188 ++++---- ...xclude_multiple_true-unreach-call.expected | 243 +++++----- ...f_trier_exclude_true-unreach-call.expected | 168 ++++--- .../builtin_expect_true-unreach-call.expected | 10 +- .../cfg/free_spawn_true-unreach-call.expected | 30 +- .../free_spawn_ub_true-unreach-call.expected | 10 +- .../cfg/join_true-unreach-call.expected | 198 ++++---- ...ocal_shadow_fun_true-unreach-call.expected | 42 +- ...ll_context_join_true-unreach-call.expected | 34 +- ...lticall_context_true-unreach-call.expected | 42 +- .../multicall_join_true-unreach-call.expected | 34 +- ...all_nested_join_true-unreach-call.expected | 428 ++++++++---------- ...ulticall_nested_true-unreach-call.expected | 94 ++-- ..._return_context_true-unreach-call.expected | 58 +-- .../cfg/multicall_true-unreach-call.expected | 78 ++-- ...ion_global_init_true-unreach-call.expected | 34 +- .../cfg/uncil/and3_true-unreach-call.expected | 32 +- .../uncil/and3dead_true-unreach-call.expected | 32 +- .../uncil/and_copy_true-unreach-call.expected | 30 +- ..._join_invariant_true-unreach-call.expected | 185 ++++---- .../cfg/uncil/and_true-unreach-call.expected | 30 +- .../uncil/and_var_false-unreach-call.expected | 28 +- .../uncil/and_var_true-unreach-call.expected | 26 +- .../cfg/uncil/or3_true-unreach-call.expected | 32 +- .../uncil/or3dead_true-unreach-call.expected | 32 +- .../cfg/uncil/or_true-unreach-call.expected | 30 +- tests/sv-comp/dune.inc | 82 ++-- .../eq/eq_double_true-unreach-call.expected | 48 +- .../eq/eq_single_true-unreach-call.expected | 26 +- .../eq/multivar_false-unreach-call1.expected | 30 +- .../eq/multivar_true-unreach-call1.expected | 30 +- tests/sv-comp/gen/gen.ml | 2 +- 47 files changed, 1351 insertions(+), 1424 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 99c887ca53..be1ef3c63f 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1826,6 +1826,13 @@ "description": "Output ARG as dot file.", "type": "boolean", "default": false + }, + "argdotlabel": { + "title": "exp.argdotlabel", + "description": "Which ARG node labels to use? node/empty", + "type": "string", + "enum": ["node", "empty"], + "default": "node" } }, "additionalProperties": false diff --git a/src/framework/control.ml b/src/framework/control.ml index 0c54d0d373..118942227b 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -748,17 +748,18 @@ struct if get_bool "exp.arg" then ( let module ArgTool = ArgTools.Make (R) in let module Arg = (val ArgTool.create entrystates) in - let module Arg = - (val match get_string "witness.graphml.id" with - | "node" -> - (module Arg: ArgTools.BiArg) - | "enumerate" -> - (module ArgTools.Enumerate (Arg)) - | _ -> failwith "witness.graphml.id: illegal value" - ) - in if get_bool "exp.argdot" then ( - let module ArgDot = ArgTools.Dot (Arg) in + let module NoLabelNodeStyle = + struct + type node = Arg.Node.t + let extra_node_styles node = + match GobConfig.get_string "exp.argdotlabel" with + | "node" -> [] + | "empty" -> ["label=\"_\""] (* can't have empty string because graph-easy will default to node ID then... *) + | _ -> assert false + end + in + let module ArgDot = ArgTools.Dot (Arg) (NoLabelNodeStyle) in let oc = Batteries.open_out "arg.dot" in Fun.protect (fun () -> let ppf = Format.formatter_of_out_channel oc in diff --git a/src/util/server.ml b/src/util/server.ml index 80ddc81d31..7b603e7c6e 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -554,7 +554,13 @@ let () = } [@@deriving to_yojson] let process () serv = let module ArgWrapper = (val (ResettableLazy.force serv.arg_wrapper)) in - let module ArgDot = ArgTools.Dot (ArgWrapper.Arg) in + let module NoExtraNodeStyle = + struct + type node = ArgWrapper.Arg.Node.t + let extra_node_styles node = [] + end + in + let module ArgDot = ArgTools.Dot (ArgWrapper.Arg) (NoExtraNodeStyle) in let arg = Format.asprintf "%t" ArgDot.dot in {arg} end); diff --git a/src/witness/argTools.ml b/src/witness/argTools.ml index 55a74b9f12..2b21659dd5 100644 --- a/src/witness/argTools.ml +++ b/src/witness/argTools.ml @@ -14,7 +14,13 @@ sig val query: Node.t -> 'a Queries.t -> 'a Queries.result end -module Dot (Arg: BiArg) = +module type NodeStyles = +sig + type node + val extra_node_styles: node -> string list +end + +module Dot (Arg: BiArg) (NodeStyles: NodeStyles with type node = Arg.Node.t) = struct let dot_node_name ppf node = Format.fprintf ppf "\"%s\"" (Arg.Node.to_string node) @@ -24,12 +30,13 @@ struct let dot_node ppf node = let shape = match Arg.Node.cfgnode node with - | Statement {skind=If (_,_,_,_,_); _} -> "diamond" - | Statement _ -> "box" (* TODO: default nothing like CFG *) + | Statement {skind=If (_,_,_,_,_); _} -> ["shape=diamond"] + | Statement _ -> [] (* use default shape *) | Function _ - | FunctionEntry _ -> "box" + | FunctionEntry _ -> ["shape=box"] in - Format.fprintf ppf "@,%a [shape=%s];" dot_node_name node shape; + let styles = String.concat "," (shape @ NodeStyles.extra_node_styles node) in + Format.fprintf ppf "@,%a [%s];" dot_node_name node styles; List.iter (dot_edge ppf node) (Arg.next node) let dot_nodes ppf = @@ -39,32 +46,6 @@ struct Format.fprintf ppf "@[digraph arg {%t@]@,}@\n" dot_nodes end -module Enumerate (Arg: BiArg): BiArg = -struct - include Arg - - module Node = - struct - include Node - - module NH = Hashtbl.Make (Node) - let nh = NH.create 113 - let next = ref 0 - - let to_string n = - let i = - match NH.find_opt nh n with - | Some i -> i - | None -> - let i = !next in - NH.replace nh n i; - incr next; - i - in - string_of_int i - end -end - let current_arg: (module BiArg) option ref = ref None module Make (R: ResultQuery.SpecSysSol2) = diff --git a/tests/sv-comp/basic/for_fun_true-unreach-call.expected b/tests/sv-comp/basic/for_fun_true-unreach-call.expected index c4c5b62d64..d8e29f44e5 100644 --- a/tests/sv-comp/basic/for_fun_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_fun_true-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────┐ │ - │ 8 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry fun │ ▼ │ ┌────────────────────────────────┐ │ - │ 9 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ Assign 'i = 0' │ ▼ │ ┌────────────────────────────────┐ │ ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ - ┌──────────────────▶ │ 7 │ ─┼──────────────────────────────────────────▶ │ 13 │ ─────────────────▶ │ 14 │ + ┌──────────────────▶ │ _ │ ─┼──────────────────────────────────────────▶ │ _ │ ─────────────────▶ │ _ │ │ └────────────────────────────────┘ │ └───────────────────────┘ └─────────────────────┘ │ │ │ Inlined Proc 'fun()' │ │ │ Test (i < 1000,true) └───────────────────────────────────────────────────────────────────────┐ │ InlineReturn │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ 12 │ ─┐ └───────────────▶ │ 10 │ + │ │ _ │ ─┐ └───────────────▶ │ _ │ │ └────────────────────────────────┘ │ └─────────────────────┘ │ │ │ │ │ │ InlineEntry '(i < 2000)' │ │ Ret (Some 0, main) │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ 4 │ │ │ 11 │ + │ │ _ │ │ │ _ │ │ └────────────────────────────────┘ │ └─────────────────────┘ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ 5 │ │ + │ Assign 'i = i + 1' │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 2 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 3 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └─────────────────── │ 6 │ ◀┘ + └─────────────────── │ _ │ ◀┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected index 7359b71cdd..73284ddaeb 100644 --- a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected @@ -1,84 +1,84 @@ - ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────┐ │ - │ │ 0 │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry main │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ 1 │ ─┐ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ 8 │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry fun │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ 9 │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Assign 'i = 1' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌────┐ Test (i < 1000,true) ┌────────────────────────────────┐ │ Assign 'i = i + 2' │ - │ │ 4 │ ◀──────────────────────────────────────────── │ 13 │ ◀───────────────────────────────────────────── │ 7 │ ◀┼───────────────────────────────────────────────┘ - │ └────────────────────────────────┘ └────┘ └────────────────────────────────┘ │ - │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ - │ ▼ │ ▼ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────┐ │ - │ │ 5 │ │ ┌──────────────────────────────────────────── │ 14 │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ - │ │ 2 │ │ │ │ 17 │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ Test (! cond,true) ┌─────────────────────────┐ - │ │ 3 │ │ │ │ 18 │ ─┼──────────────────────────────────────────────────────────────────▶ │ 22 │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ │ │ │ │ - │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' - │ ▼ │ │ ▼ │ ▼ - │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ - └─ │ 6 │ ◀───────────────────────────────────────────────┘ │ │ 15 │ │ │ 21 │ - └────────────────────────────────┘ │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error - │ ▼ │ ▼ - │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ - │ │ 16 │ │ │ 12 │ - │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ - │ │ InlineReturn │ Inlined Proc 'fun()' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ 19 │ │ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, fun) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 20 │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - │ 10 │ ◀┘ - └────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────┐ - │ 11 │ - └────────────────────────────────┘ + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌────────────────────────────────┐ │ + │ │ _ │ ─┐ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ _ │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry fun │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ + │ │ _ │ │ │ + │ └────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Assign 'i = 1' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌───┐ Test (i < 1000,true) ┌────────────────────────────────┐ │ Assign 'i = i + 2' │ + │ │ _ │ ◀──────────────────────────────────────────── │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┼───────────────────────────────────────────────┘ + │ └────────────────────────────────┘ └───┘ └────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ + │ ▼ │ ▼ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────┐ │ + │ │ _ │ │ ┌──────────────────────────────────────────── │ _ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ + │ │ _ │ │ │ │ _ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ Test (! cond,true) ┌─────────────────────────┐ + │ │ _ │ │ │ │ _ │ ─┼──────────────────────────────────────────────────────────────────▶ │ _ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ │ │ │ │ + │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' + │ ▼ │ │ ▼ │ ▼ + │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ + └─ │ _ │ ◀───────────────────────────────────────────────┘ │ │ _ │ │ │ _ │ + └────────────────────────────────┘ │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error + │ ▼ │ ▼ + │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ + │ │ _ │ │ │ _ │ + │ └────────────────────────────────┘ │ └─────────────────────────┘ + │ │ │ + │ │ InlineReturn │ Inlined Proc 'fun()' + │ ▼ │ + │ ┌────────────────────────────────┐ │ + └───────────────────────────────────────────▶ │ _ │ │ + └────────────────────────────────┘ │ + │ │ + │ Ret (None, fun) │ + ▼ │ + ┌────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────┐ │ + │ _ │ ◀┘ + └────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────┐ + │ _ │ + └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_true-unreach-call.expected b/tests/sv-comp/basic/for_true-unreach-call.expected index 67103e5aae..6a711a84d0 100644 --- a/tests/sv-comp/basic/for_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_true-unreach-call.expected @@ -1,51 +1,51 @@ ┌────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 1 │ + │ _ │ └────────────────────────────────┘ │ │ Assign 'i = 0' ▼ - ┌────────────────────────────────┐ Test (i < 1000,false) ┌───┐ Ret (Some 0, main) ┌────┐ - ┌──────────────────▶ │ 7 │ ────────────────────────────────────────────▶ │ 9 │ ────────────────────▶ │ 10 │ - │ └────────────────────────────────┘ └───┘ └────┘ + ┌────────────────────────────────┐ Test (i < 1000,false) ┌───┐ Ret (Some 0, main) ┌───┐ + ┌──────────────────▶ │ _ │ ────────────────────────────────────────────▶ │ _ │ ────────────────────▶ │ _ │ + │ └────────────────────────────────┘ └───┘ └───┘ │ │ │ │ Test (i < 1000,true) │ ▼ │ ┌────────────────────────────────┐ - │ │ 8 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(i < 2000)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 4 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ 5 │ │ + │ Assign 'i = i + 1' │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 2 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 3 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └─────────────────── │ 6 │ ◀┘ + └─────────────────── │ _ │ ◀┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/global_init_true-unreach-call.expected b/tests/sv-comp/basic/global_init_true-unreach-call.expected index 4e1725a741..7e87b517d4 100644 --- a/tests/sv-comp/basic/global_init_true-unreach-call.expected +++ b/tests/sv-comp/basic/global_init_true-unreach-call.expected @@ -1,45 +1,45 @@ ┌────────────────────────────────┐ -│ 0 │ +│ _ │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ -│ 1 │ ─┐ +│ _ │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(g == 1)' │ ▼ │ ┌────────────────────────────────┐ │ -│ 6 │ │ +│ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────┐ │ -│ 4 │ │ +│ _ │ │ └────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(g == 1)' ▼ │ ┌────────────────────────────────┐ │ -│ 5 │ │ +│ _ │ │ └────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────┐ │ -│ 7 │ │ +│ _ │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ -│ 3 │ ◀┘ +│ _ │ ◀┘ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ -│ 2 │ +│ _ │ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_false-unreach-call.expected b/tests/sv-comp/basic/if_det_false-unreach-call.expected index 96509723ec..49de731f92 100644 --- a/tests/sv-comp/basic/if_det_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_false-unreach-call.expected @@ -1,39 +1,39 @@ ┌─────────────────────────┐ -│ 0 │ +│ _ │ └─────────────────────────┘ │ │ Entry main ▼ ┌─────────────────────────┐ -│ 1 │ +│ _ │ └─────────────────────────┘ │ │ Test (1,true) ▼ ┌─────────────────────────┐ -│ 2 │ +│ _ │ └─────────────────────────┘ │ │ Assign 'x = 1' ▼ ┌─────────────────────────┐ -│ 3 │ +│ _ │ └─────────────────────────┘ │ │ Test (x,true) ▼ ┌─────────────────────────┐ -│ 4 │ +│ _ │ └─────────────────────────┘ │ │ InlineEntry '()' ▼ ┌─────────────────────────┐ -│ 5 │ +│ _ │ └─────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌─────────────────────────┐ -│ 6 │ +│ _ │ └─────────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected index dc4074b3a3..336a8ccb63 100644 --- a/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_incr_true-unreach-call.expected @@ -1,27 +1,27 @@ ┌─────────────────────┐ -│ 0 │ +│ _ │ └─────────────────────┘ │ │ Entry main ▼ ┌─────────────────────┐ -│ 1 │ ◀┐ +│ _ │ ◀┐ └─────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌─────────────────────┐ │ -│ 2 │ │ +│ _ │ │ └─────────────────────┘ │ │ │ │ Assign 'x = -1' │ Test (x,false) ▼ │ ┌─────────────────────┐ │ -│ 3 │ │ +│ _ │ │ └─────────────────────┘ │ │ │ │ Assign 'x = x + 1' │ ▼ │ ┌─────────────────────┐ │ -│ 4 │ ─┘ +│ _ │ ─┘ └─────────────────────┘ diff --git a/tests/sv-comp/basic/if_det_true-unreach-call.expected b/tests/sv-comp/basic/if_det_true-unreach-call.expected index 127ca693c5..883b8a1a76 100644 --- a/tests/sv-comp/basic/if_det_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_det_true-unreach-call.expected @@ -1,21 +1,21 @@ ┌─────────────────┐ -│ 0 │ +│ _ │ └─────────────────┘ │ │ Entry main ▼ ┌─────────────────┐ -│ 1 │ ◀┐ +│ _ │ ◀┐ └─────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌─────────────────┐ │ -│ 2 │ │ Test (x,false) +│ _ │ │ Test (x,false) └─────────────────┘ │ │ │ │ Assign 'x = 0' │ ▼ │ ┌─────────────────┐ │ -│ 3 │ ─┘ +│ _ │ ─┘ └─────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_false-unreach-call.expected b/tests/sv-comp/basic/if_mod_false-unreach-call.expected index b7a96353e2..a8d688ee26 100644 --- a/tests/sv-comp/basic/if_mod_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_false-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌────────────────────▶ │ 1 │ + ┌────────────────────▶ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 5 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 6 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 50,false) │ 2 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x >= 50,false) │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 3 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 4 │ ◀┘ + │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp 00' │ ▼ │ ┌────────────────────────────────────────┐ - └───────────────────── │ 7 │ + └───────────────────── │ _ │ └────────────────────────────────────────┘ │ │ Test (x >= 50,true) ▼ ┌────────────────────────────────────────┐ - │ 8 │ + │ _ │ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ 9 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ 10 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_mod_true-unreach-call.expected b/tests/sv-comp/basic/if_mod_true-unreach-call.expected index f27d391c86..d130a4c037 100644 --- a/tests/sv-comp/basic/if_mod_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_true-unreach-call.expected @@ -1,45 +1,45 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌─────────────────────▶ │ 1 │ + ┌─────────────────────▶ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 4 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 5 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 100,false) │ 7 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x >= 100,false) │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 2 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 3 │ ◀┘ + │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp 00' │ ▼ │ ┌────────────────────────────────────────┐ - └────────────────────── │ 6 │ + └────────────────────── │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected index 06d8e76736..8a713183c5 100644 --- a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected @@ -1,63 +1,63 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - ┌──────────────▶ │ 1 │ + ┌──────────────▶ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 5 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '()' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 6 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ Test (x,false) │ 2 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ Test (x,false) │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 3 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn 'tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 4 │ ◀┘ + │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = tmp' │ ▼ │ ┌────────────────────────────────────────┐ - └─────────────── │ 7 │ + └─────────────── │ _ │ └────────────────────────────────────────┘ │ │ Test (x,true) ▼ ┌────────────────────────────────────────┐ - │ 8 │ + │ _ │ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ 9 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ 10 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected index 3337b59a7d..c09019ec2c 100644 --- a/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_var_false-unreach-call.expected @@ -1,33 +1,33 @@ ┌─────────────────────────┐ -│ 0 │ +│ _ │ └─────────────────────────┘ │ │ Entry main ▼ ┌─────────────────────────┐ -│ 1 │ ◀┐ +│ _ │ ◀┐ └─────────────────────────┘ │ │ │ │ Test (1,true) │ Test (x,false) ▼ │ ┌─────────────────────────┐ │ -│ 2 │ ─┘ +│ _ │ ─┘ └─────────────────────────┘ │ │ Test (x,true) ▼ ┌─────────────────────────┐ -│ 5 │ +│ _ │ └─────────────────────────┘ │ │ InlineEntry '()' ▼ ┌─────────────────────────┐ -│ 3 │ +│ _ │ └─────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌─────────────────────────┐ -│ 4 │ +│ _ │ └─────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected index 25d029027a..89b8c8d42c 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected @@ -1,98 +1,92 @@ - ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────────────┐ │ - │ │ 0 │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry main │ InlineReturn - │ ▼ ▼ - │ Inlined Proc '__VERIFIER_assert(x == 0)' ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ - │ │ │ │ - │ │ Inlined Proc '__VERIFIER_assert(x != 1)' │ │ InlineReturn - │ │ ┌─────────────────────────────────────────────▶ │ 1 │ ◀─────────────────┐ - │ │ │ │ │ │ - │ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ - │ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ - │ │ │ │ │ Test (1,true) │ │ - │ │ │ │ ▼ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ │ 8 │ ─┐ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ InlineEntry '()' │ │ │ - │ │ │ │ ▼ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ 9 │ │ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ │ ▼ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ Inlined Proc '__VERIFIER_assert(x == 2)' │ 20 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ │ ▼ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ 18 │ │ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ InlineReturn 'tmp' │ │ │ - │ │ │ │ ▼ │ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ 10 │ ◀┘ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ - │ │ │ │ │ Assign 'x = tmp' │ │ - │ │ │ │ ▼ │ │ - │ ┌────────────────────────────────┐ Test (x == 0,true) │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 16 │ ◀───────────────────────────┼────┼───────────────────────────────────────── │ 14 │ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ - │ │ InlineEntry '(x == 0)' │ │ │ Test (x == 0,false) │ InlineReturn │ - │ ▼ │ │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 5 │ ◀┐ │ │ │ 15 │ ─┐ │ │ - │ └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ │ │ Test (x == 2,true) │ │ │ - │ ▼ │ │ │ ▼ │ │ │ - │ ┌────────────────────────────────┐ │ InlineEntry '(x == 2)' │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 6 │ │ │ └───────────────────────────────────────── │ 7 │ │ Test (x == 2,false) │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ Test (! cond,false) └──────────────────────────┼─────────────────────────────────────────────────┘ │ │ │ - │ ▼ │ │ │ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 2 │ └────────────────────────────────────────────── │ 21 │ ◀┘ │ │ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ InlineEntry '(x != 1)' │ │ - │ ▼ ▼ │ │ - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ - └─ │ 3 │ ─────────────────────────────────┐ │ 22 │ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - ┌────────────────────────────────┐ Test (! cond,true) │ ┌────────────────────────────────────────┐ │ │ - │ 13 │ ◀────────────────────────────────┼───────────────────────────────────────── │ 11 │ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ InlineEntry '()' │ │ Test (! cond,false) │ │ - ▼ │ ▼ │ │ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ 17 │ │ │ 12 │ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ Entry __VERIFIER_error │ │ Ret (None, __VERIFIER_assert) │ │ - ▼ │ ▼ │ │ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ 4 │ │ │ 19 │ ──────────────────────────────────────────────────┘ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┐ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 1)' + │ │ │ ▼ ▼ + │ ┌────────────────────────────────┐ InlineEntry '(x != 1)' ┌──────────────────────┐ │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ _ │ ◀──────────────────────── │ _ │ └────────────────────────────────────────▶ │ │ + │ └────────────────────────────────┘ └──────────────────────┘ │ │ + │ │ ▲ InlineReturn │ │ InlineReturn + │ │ Entry __VERIFIER_assert ┌──────────────────────────┼────────────────────────────────────────────────────────────────▶ │ _ │ ◀─────────────────┐ + │ ▼ │ │ │ │ │ + │ ┌─────────────────────────┐ Test (! cond,true) ┌────────────────────────────────┐ │ │ │ │ │ + │ │ _ │ ◀──────────────────── │ _ │ │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ + │ └─────────────────────────┘ └────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ │ + │ │ InlineEntry '()' │ Test (! cond,false) │ │ │ │ Test (1,true) │ │ + │ ▼ ▼ │ │ │ ▼ │ │ + │ ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ │ _ │ │ │ │ │ _ │ ─┐ │ │ + │ └─────────────────────────┘ └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ │ │ │ InlineEntry '()' │ │ │ + │ ▼ ▼ │ │ │ ▼ │ │ │ + │ ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ _ │ │ _ │ ─┘ │ │ │ _ │ │ │ │ + │ └─────────────────────────┘ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + └──────────────────────────────────────────────────────┐ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ ▼ │ │ │ + │ │ Test (x == 2,false) │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x == 2)' │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ _ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ │ + │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ _ │ ◀┘ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Assign 'x = tmp' │ │ + │ │ │ ▼ │ │ + ┌────────────────────────────────┐ Test (x == 0,true) │ │ ┌────────────────────────────────────────┐ │ │ + │ _ │ ◀───────────────────────────┼───────────────────────┼───────────────────────────────────────── │ _ │ │ InlineReturn │ + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Test (x == 0,false) │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────┼───────────────────────────────────────── │ _ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Test (x == 2,true) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────────────────────── │ _ │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '(x == 2)' │ │ + │ ▼ │ │ + │ InlineEntry '(x == 0)' ┌────────────────────────────────────────┐ │ │ + └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ _ │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Entry __VERIFIER_assert │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Test (! cond,false) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ ──────────────────────────────────────────────────┘ │ + └────────────────────────────────────────┘ │ + │ │ + └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index 2ba7b8e5fe..3bcca8a6d5 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -1,132 +1,111 @@ - ┌────────────────────────────────────────┐ - │ 0 │ - └────────────────────────────────────────┘ - │ InlineReturn - │ Entry main ┌────────────────────────────────────────────────────────────────────────┐ - ▼ ▼ │ - InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ │ - ┌───────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ 4 │ ─┼────┐ - │ │ │ └─────────────────────┘ │ │ - │ Inlined Proc '__VERIFIER_assert(x == 0)' │ │ ▲ │ │ - │ ┌──────────────────────────────────────────────▶ │ 1 │ │ Test (x == 2,true) │ │ - │ │ │ │ │ │ │ - │ │ │ │ │ │ │ - │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ │ │ - │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Test (1,true) │ InlineReturn │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 5 │ ─┐ ┌────┼────────────────────────────────────────────┘ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 6 │ │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 16 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 17 │ │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 7 │ ◀┘ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ Assign 'x = tmp' │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 8 │ ─┐ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Test (x == 0,false) │ │ │ │ │ - │ │ │ ▼ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ │ │ 9 │ ─┼────────────────────────────────────────────────┘ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Test (x == 2,false) │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 13 │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Test (x != 0,true) │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 14 │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Test (x != 2,true) │ Test (x == 0,true) │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 22 │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Assign 'tmp___0 = 1' │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └────────────────────────────────────────── │ 18 │ │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ - ┌────┼────┼──────────────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ └─────────────────────────────────────────────── │ 10 │ ◀┘ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ │ InlineEntry '(x == 0)' │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ InlineEntry '(x == 2)' │ │ │ - │ │ │ 2 │ ◀──────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────┼────┘ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 3 │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 15 │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ └──────────────────────────────────────────────────── │ 21 │ ───────────────────────────────────────────────────────┘ │ - │ └────────────────────────────────────────┘ │ - │ InlineEntry '(tmp___0)' ┌────────────────────────────────────────┐ │ - └────────────────────────────────────────────────────────▶ │ 19 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 11 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 12 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 20 │ ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - └────────────────────────────────────────┘ + + ┌───────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + ┌─────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ _ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ ┌─────────────────────────────────────────────────────────────┘ │ Entry main │ Inlined Proc '__VERIFIER_assert(x == 0)' │ + │ │ ▼ ▼ │ + │ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ + │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ _ │ + │ │ │ │ │ └─────────────────────┘ + │ │ │ InlineReturn │ │ ▲ + │ │ │ ┌─────────────────────────────────────────────────────────────────────▶ │ _ │ │ Test (x == 2,true) + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ + │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Test (1,true) │ InlineReturn │ + │ │ │ │ │ ▼ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ │ │ _ │ ─┐ ┌────┼────────────────────────────────────────────┘ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineEntry '()' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ _ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ InlineEntry '(x == 2)' │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ _ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ _ │ ◀┘ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Assign 'x = tmp' │ │ + │ │ │ │ │ ▼ │ │ + │ │ ┌────────────────────────────────┐ │ Test (x == 0,true) │ ┌────────────────────────────────────────┐ │ │ + │ │ │ _ │ ◀┼───────────────────────────┼────────────────────────────────────────── │ _ │ │ │ + │ │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ InlineEntry '(x == 0)' │ │ │ Test (x == 0,false) │ │ + │ │ ▼ │ │ ▼ │ │ + │ │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + └──────────────────────────┼▶ │ _ │ │ │ │ _ │ ──────────────────────────────────────────────────┘ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ │ Test (x == 2,false) │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ │ │ _ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Test (! cond,false) │ │ │ Test (x != 0,true) │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ │ │ _ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Test (x != 2,true) │ + │ ▼ │ │ ▼ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ + └─ │ _ │ ─┘ │ │ _ │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 'tmp___0 = 1' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + └────────────────────────────────────────── │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ ───────────────────────────────────────────────────────┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected index 44a30b2c66..08a583459b 100644 --- a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected @@ -1,89 +1,81 @@ - ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - │ ┌───────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 0 │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 0)' │ InlineReturn - │ │ ▼ ▼ ▼ - │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ ┌────────────────────────────────────────▶ │ 1 │ ◀┐ - │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ Test (1,true) │ - │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ │ 6 │ ─┐ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 7 │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 2 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 3 │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ 8 │ ◀┘ │ - │ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ Assign 'x = tmp' │ - │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ │ 9 │ ─┐ │ InlineReturn - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Test (x == 0,true) │ │ - │ │ │ ▼ │ │ - ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌──────────────────────▶ │ 15 │ │ │ └───────────────────────────────────────── │ 11 │ ─┼────────────────────────────────────────────────┐ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ │ Test (x == 0,false) │ │ - │ ▼ │ │ │ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 13 │ │ └────────────────────────────────────────────── │ 10 │ ◀┘ │ │ - │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ InlineEntry '(x != 0)' │ │ - │ ▼ │ ▼ │ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ 14 │ │ │ 12 │ │ │ - │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ ▼ │ │ - │ InlineEntry '(x == 0)' ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ 16 │ ─┘ │ 4 │ │ │ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ 5 │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ 17 │ ──────────────────────────────────────────────────┼────────────────┘ - │ └────────────────────────────────────────┘ │ - │ │ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ _ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Entry main │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x != 0)' + │ │ ▼ ▼ ▼ + │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ ┌────────────────────────────────────────▶ │ _ │ ◀┐ + │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ Test (1,true) │ + │ │ │ ▼ │ + │ │ │ ┌────────────────────────────────────────┐ │ + │ │ │ │ _ │ ─┐ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ _ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ _ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ + │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ _ │ ◀┘ │ + │ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ │ Assign 'x = tmp' │ InlineReturn + │ │ │ ▼ │ +┌────────────────────────────────┐ │ Test (x == 0,false) │ ┌────────────────────────────────────────┐ │ +│ _ │ ◀┼────────────────────────────┼───────────────────────────────────────── │ _ │ │ +└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ InlineEntry '(x != 0)' │ │ │ Test (x == 0,true) │ + ▼ │ │ ▼ │ +┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ +│ _ │ │ └───────────────────────────────────────── │ _ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Entry __VERIFIER_assert │ │ InlineEntry '(x == 0)' │ + ▼ │ ▼ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ _ │ │ │ _ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Test (! cond,false) │ │ Entry __VERIFIER_assert │ + ▼ │ ▼ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ _ │ │ │ _ │ │ +└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ Test (! cond,false) │ + ▼ │ ▼ │ +┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ +│ _ │ ─┘ │ _ │ │ +└────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ ───────────────────────────────────────────────────────────────────────────────────────────────┘ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected b/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected index 396e5ca0d5..7f2218fdcb 100644 --- a/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected +++ b/tests/sv-comp/cfg/builtin_expect_true-unreach-call.expected @@ -1,27 +1,27 @@ ┌───────────────────────────────────────────────┐ -│ 0 │ +│ _ │ └───────────────────────────────────────────────┘ │ │ Entry main ▼ ┌───────────────────────────────────────────────┐ -│ 1 │ +│ _ │ └───────────────────────────────────────────────┘ │ │ Assign 'x = 0' ▼ ┌───────────────────────────────────────────────┐ -│ 2 │ +│ _ │ └───────────────────────────────────────────────┘ │ │ Proc '__builtin_expect((long )(x == 0), 1L)' ▼ ┌───────────────────────────────────────────────┐ -│ 3 │ +│ _ │ └───────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌───────────────────────────────────────────────┐ -│ 4 │ +│ _ │ └───────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected index c8643d023e..8e9d9e6d42 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected @@ -1,87 +1,87 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ + │ _ │ └────────────────────────────────────────┘ │ │ Assign 'p = (void *)0' ▼ ┌────────────────────────────────────────┐ - │ 8 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 9 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 10 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp ' ▼ ┌────────────────────────────────────────┐ - │ 11 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x == 0,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 12 │ │ + ┌─────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x == 1,false) │ Test (x == 0,true) │ ▼ │ ┌───┐ Test (x == -1,false) │ ┌────────────────────────────────────────┐ │ -│ 6 │ ◀─────────────────────────────────┼─────────────────── │ 14 │ │ +│ _ │ ◀─────────────────────────────────┼─────────────────── │ _ │ │ └───┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Test (x == 1,true) │ Test (x == -1,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ └──────────────────▶ │ 13 │ ◀┘ + │ └──────────────────▶ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Proc 'tmp___0 = malloc(1)' │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 4 │ + │ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'p = (void *)tmp___0' │ ▼ │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────┐ - └────────────────────────────────────────────────────────▶ │ 5 │ + └────────────────────────────────────────────────────────▶ │ _ │ └────────────────────────────────────────┘ │ │ Proc 'free(p)' ▼ ┌────────────────────────────────────────┐ - │ 7 │ + │ _ │ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 15 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected index a2eb7a644b..0a0df994d4 100644 --- a/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_ub_true-unreach-call.expected @@ -1,27 +1,27 @@ ┌───────────────────────────────────┐ -│ 0 │ +│ _ │ └───────────────────────────────────┘ │ │ Entry main ▼ ┌───────────────────────────────────┐ -│ 1 │ +│ _ │ └───────────────────────────────────┘ │ │ Assign 'p = (void (*)())(& foo)' ▼ ┌───────────────────────────────────┐ -│ 2 │ +│ _ │ └───────────────────────────────────┘ │ │ Proc 'free(p)' ▼ ┌───────────────────────────────────┐ -│ 3 │ +│ _ │ └───────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌───────────────────────────────────┐ -│ 4 │ +│ _ │ └───────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected index 00a349b354..7291ee1450 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -1,99 +1,99 @@ - ┌────────────────────────────────────────┐ - │ 0 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 1 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 2 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 16 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ -┌───┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ -│ 6 │ ◀────────────────── │ 4 │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,true) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ 5 │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 1' - │ ▼ - │ Assign 'x = 2' ┌────────────────────────────────────────┐ - └─────────────────────▶ │ 7 │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ 11 │ - └────────────────────────────────────────┘ - │ - │ Test (x <= 2,true) - ▼ - ┌────────────────────────────────────────┐ - │ 12 │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1' - ▼ - ┌────────────────────────────────────────┐ - │ 13 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 17 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 9 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 10 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 15 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 14 │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 8 │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '()' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_nondet_int │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ │ + │ │ + │ Ret (Some val, __VERIFIER_nondet_int) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn 'tmp' │ + ▼ │ +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ │ +│ _ │ ◀───────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (x <= 2,true) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ InlineEntry '(tmp___0)' │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ InlineReturn │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected index e0a0ace31d..f491e8b8da 100644 --- a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected +++ b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected @@ -2,125 +2,125 @@ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ 0 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry main │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 1 │ ─┐ │ + │ │ _ │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 2 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 15 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ Assign 'i = i + 1' - │ │ 6 │ ◀┘ │ + │ │ _ │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'n = tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 13 │ ─┐ │ + │ │ _ │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(n)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 9 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry sum │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 10 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Assign 'sum___0 = 0' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 11 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Assign 'i = 0' │ │ │ ▼ │ │ │ ┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ │ │ - │ │ 4 │ ◀──────────────────── │ 12 │ ◀┼────────────────────────────────────────────────┘ + │ │ _ │ ◀──────────────────── │ _ │ ◀┼────────────────────────────────────────────────┘ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) │ │ ▼ ▼ │ │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - └─ │ 5 │ │ 24 │ │ + └─ │ _ │ │ _ │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ Ret (Some sum___0, sum) │ Inlined Proc 'tmp___0 = sum(n)' ▼ │ ┌────────────────────────────────────────┐ │ - │ 23 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp___0' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 14 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 's = tmp___0' ▼ ┌────────────────────────────────────────┐ - │ 19 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(s >= 0)' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 17 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌─────────────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ │ - │ 25 │ ◀──────────────────── │ 18 │ │ + │ _ │ ◀──────────────────── │ _ │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(s >= 0)' ▼ ▼ │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ 20 │ │ 16 │ │ + │ _ │ │ _ │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ ▼ ▼ │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ 21 │ │ 7 │ │ + │ _ │ │ _ │ │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 8 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 22 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected index a5778e7847..b15191797f 100644 --- a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected @@ -1,101 +1,101 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 9 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 10 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 25 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ - ┌─────────────────────────────────────────────────────────────────────────────────── │ 4 │ ◀───────────────────────────────────────────── │ 11 │ ◀┘ + ┌─────────────────────────────────────────────────────────────────────────────────── │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┘ │ └────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '(2)' │ Test (tmp,true) │ ▼ ▼ │ ┌────────────────────┐ ┌────────────────────────────────────────┐ - │ │ 5 │ │ 23 │ ─┐ + │ │ _ │ │ _ │ ─┐ │ └────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Entry foo │ InlineEntry '(1)' │ │ ▼ ▼ │ │ ┌────────────────────────────────┐ InlineEntry '(x - 1 < x)' ┌────────────────────┐ ┌────────────────────────────────────────┐ │ - │ │ 7 │ ◀───────────────────────────────────────────── │ 21 │ │ 18 │ │ + │ │ _ │ ◀───────────────────────────────────────────── │ _ │ │ _ │ │ │ └────────────────────────────────┘ └────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ Entry foo │ │ ▼ │ ▼ │ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ │ ┌──────────────────────────────────────────── │ 19 │ │ + │ │ _ │ │ ┌──────────────────────────────────────────── │ _ │ │ │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ InlineEntry '(x - 1 < x)' │ │ ▼ │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ 2 │ │ │ │ 24 │ │ + │ │ _ │ │ │ │ _ │ │ │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ 3 │ │ │ │ 15 │ │ + │ │ _ │ │ │ │ _ │ │ │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ │ ▼ │ │ ▼ │ │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ │ ┌────────────────────────────────────────┐ │ - │ │ 20 │ ◀────────────────────────────────────────────────┘ │ │ 16 │ │ + │ │ _ │ ◀────────────────────────────────────────────────┘ │ │ _ │ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, foo) │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ ▼ │ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ │ 12 │ │ │ 22 │ │ + │ │ _ │ │ │ _ │ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ └───────────────────────────────────────────▶ │ 14 │ │ + │ │ └───────────────────────────────────────────▶ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, foo) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 13 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ Inlined Proc 'foo(1)' │ │ ▼ ▼ │ │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ 6 │ + │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ _ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc 'foo(2)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 17 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected index 5fd345474f..2a7118873d 100644 --- a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected @@ -1,123 +1,123 @@ ┌────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(1)' │ ▼ │ ┌────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry foo │ ▼ │ ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────────── │ 10 │ │ + ┌──────────────────────────────────────────── │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x - 1 < x)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 18 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 6 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 7 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 17 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ 8 │ │ + └───────────────────────────────────────────▶ │ _ │ │ └────────────────────────────────┘ │ │ │ │ Ret (None, foo) │ ▼ │ ┌────────────────────────────────┐ │ - │ 9 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────────── │ 3 │ ◀┘ + ┌──────────────────────────────────────────── │ _ │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ InlineEntry '(2)' │ ▼ │ ┌────────────────────────────────┐ - │ │ 15 │ + │ │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry foo │ ▼ │ ┌────────────────────────────────┐ - │ │ 16 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x - 1 < x)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 20 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 11 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ Inlined Proc 'foo(2)' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 12 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 19 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 13 │ ◀┘ + │ │ _ │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ Ret (None, foo) │ ▼ │ ┌────────────────────────────────┐ - │ │ 14 │ + │ │ _ │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ - └───────────────────────────────────────────▶ │ 4 │ + └───────────────────────────────────────────▶ │ _ │ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ - │ 5 │ + │ _ │ └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected index 2e9030c78d..66a088602a 100644 --- a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected @@ -1,99 +1,99 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 5 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 6 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 17 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌───┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ - ┌─ │ 2 │ ◀───────────────────────────────────────────── │ 7 │ ◀┘ + ┌─ │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┘ │ └───┘ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (tmp,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ - │ │ │ 15 │ ─┐ + │ │ │ _ │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(1)' │ │ │ ▼ │ │ │ InlineEntry '(1)' ┌────────────────────────────────────────┐ │ - │ └────────────────────────────────────────────────▶ │ 3 │ │ + │ └────────────────────────────────────────────────▶ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ ┌──────────────────────────────────────────── │ 13 │ │ + │ ┌──────────────────────────────────────────── │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x - 1 < x)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 16 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 10 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 11 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 14 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ └───────────────────────────────────────────▶ │ 9 │ │ + │ └───────────────────────────────────────────▶ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ Inlined Proc 'foo(1)' ┌────────────────────────────────────────┐ │ - └─────────────────────────────────────────────────────▶ │ 4 │ ◀┘ + └─────────────────────────────────────────────────────▶ │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 12 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected index 85c21b15a5..7b902edb11 100644 --- a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected @@ -1,234 +1,194 @@ - Test (tmp,false) - ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ ▼ - │ InlineReturn ┌────────────────────────────────────────────────────────────────┐ Inlined Proc 'foo(x, 4)' ┌────────────────────────────────┐ - ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────▶ │ 4 │ ◀────────────────────────── │ 33 │ - │ │ └────────────────────────────────────────────────────────────────┘ └────────────────────────────────┘ - │ │ │ ▲ ▲ │ - │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ Ret (None, bar) │ Inlined Proc 'foo(x, 3)' │ InlineReturn │ InlineEntry '(x, 4)' - │ │ ▼ │ │ ▼ - │ │ ┌──────────────────┐ │ │ ┌────────────────────────────────┐ - │ │ │ 31 │ │ │ │ 34 │ - │ │ └──────────────────┘ │ │ └────────────────────────────────┘ - │ │ │ │ │ │ - │ │ │ │ │ │ Entry foo - │ │ │ │ │ ▼ - │ │ │ │ │ ┌────────────────────────────────┐ - │ │ │ │ │ │ 27 │ ─┐ - │ │ │ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ │ - │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────┘ │ │ InlineEntry '(x < y)' │ - │ │ │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ - │ │ │ │ 0 │ │ │ │ 28 │ │ - │ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Entry main │ │ │ Entry __VERIFIER_assert │ - │ │ │ ▼ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ - │ │ │ │ 1 │ ─┐ │ │ │ 35 │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' - │ │ │ ▼ │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ │ 18 │ │ │ │ │ 32 │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ Ret (None, __VERIFIER_assert) │ - │ │ │ ▼ │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ │ 19 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ 11 │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineReturn │ - │ │ │ ▼ │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ │ 61 │ │ │ │ │ 12 │ ◀┘ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────┘ - │ │ │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ │ │ Ret (None, foo) - │ │ │ ▼ │ │ │ ▼ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────┐ - │ │ │ ┌───────────────────────────────────────────── │ 29 │ ◀┘ │ └────────────────────────────────────────── │ 44 │ - │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────┘ - │ │ │ │ │ │ - │ │ │ │ │ Test (tmp,true) │ - │ │ │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ InlineEntry '(1)' │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 60 │ ◀─────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 58 │ ───────────────────────────────────────────────────────────────────┐ │ - │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ - │ │ │ Entry bar │ │ Test (tmp,false) │ │ - │ │ ▼ │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 36 │ ─┐ │ └────────────────────────────────────────────▶ │ 50 │ ─┐ │ │ - │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ InlineEntry '()' │ │ │ InlineEntry '(2)' │ │ │ - │ │ ▼ │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 37 │ │ │ │ 48 │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ Entry __VERIFIER_nondet_int │ │ │ Entry bar │ │ │ - │ │ ▼ │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 16 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ ┌───────────────────────────────────────────── │ 49 │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineEntry '()' │ │ │ - │ │ ▼ │ │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 17 │ │ │ │ │ 7 │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ InlineReturn 'tmp' │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ ▼ │ │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ └──────────────────────────────────────── │ 24 │ ◀┘ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ 8 │ │ │ │ - │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ Test (tmp,true) │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ ▼ │ │ ▼ │ │ │ - │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 2 │ ──────────────────────────────────────────────────┘ │ │ 57 │ │ │ │ - │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ InlineEntry '(x, 3)' │ │ InlineReturn 'tmp' │ │ │ - │ ▼ │ ▼ │ │ │ - │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 3 │ └────────────────────────────────────────────▶ │ 52 │ ─┼────────────────────────────────────────────────┐ │ │ - │ └────────────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ - │ │ Entry foo │ Test (tmp,false) │ │ │ │ - │ ▼ ▼ │ │ │ │ - │ ┌────────────────────────────────┐ InlineEntry '(x < y)' ┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ 9 │ ◀───────────────────────────────────────── │ 51 │ ┌────────────────────────────────────────────────────────────────────────── │ 54 │ ─┼────────────────────────────────────────────────┼────────────────┼───────────────────────────────────────────────────────────┐ │ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ ▼ │ │ │ │ │ │ │ - │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ Test (tmp,true) │ │ │ │ - │ │ 10 │ │ ┌────────────────────────────────────────────────┼────────────────────────────┼───────────────────────────────────────────── │ 53 │ ◀─────────────────────────────────────────────────┘ │ │ │ - │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ │ │ InlineEntry '(x, 3)' │ │ │ - │ ▼ │ │ │ │ ▼ │ │ │ - │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 5 │ │ │ │ │ │ 25 │ │ │ │ - │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ │ │ Entry foo │ │ │ - │ ▼ │ │ │ │ ▼ │ │ │ - │ ┌────────────────────────────────┐ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ 6 │ │ │ │ │ │ 26 │ ─┐ │ │ │ - │ └────────────────────────────────┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ - │ │ InlineReturn │ │ │ │ │ InlineEntry '(x < y)' │ │ │ │ - │ ▼ │ │ │ │ ▼ │ │ │ │ - │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ 46 │ ◀────────────────────────────────────────────┘ │ │ │ │ 55 │ │ │ │ │ - │ └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ Ret (None, foo) │ │ │ │ Entry __VERIFIER_assert │ │ │ │ - │ ▼ │ │ │ ▼ │ │ │ │ - │ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - └─ │ 45 │ │ │ │ │ 21 │ │ │ │ │ - └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ Inlined Proc 'foo(x, 4)' │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 22 │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 47 │ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ InlineReturn │ │ │ │ - │ │ │ ▼ │ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ │ 20 │ ◀┘ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ Ret (None, foo) │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ 15 │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ InlineReturn │ │ - │ │ │ │ InlineReturn ┌────────────────┼──────────────────────────────────────────────────────┐ │ │ - │ │ │ ▼ ▼ │ │ │ │ - │ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ - │ └────────────────────────────┼────────────────────────────────────────────▶ │ 14 │ ◀┼─────────────────────────┐ │ │ │ - │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ Ret (None, bar) │ │ │ │ │ - │ │ ▼ │ │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ Inlined Proc 'bar(2)' │ 23 │ │ Inlined Proc 'bar(1)' │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ │ │ │ │ │ │ │ - │ │ │ InlineReturn │ │ Inlined Proc 'foo(x, 3)' │ │ │ - │ │ ▼ │ │ │ │ │ - │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ - │ └────────────────────────────────────────────▶ │ 30 │ ◀┘ │ │ │ │ - │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ - │ │ ▲ │ │ │ │ - │ │ Ret (Some 0, main) │ InlineReturn │ │ │ │ - │ ▼ │ │ │ │ │ - │ ┌────────────────────────────────────────┐ │ │ │ │ │ - │ │ 41 │ └──────────────────────────────────────────┼────────────────────────────┼────┼──────────────────────────┘ - │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ - ┌────────────────────────────────────────┐ InlineEntry '(x, 4)' │ │ - │ 42 │ ◀─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────┘ - └────────────────────────────────────────┘ │ - │ │ - │ Entry foo │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 43 │ ─┐ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ InlineEntry '(x < y)' │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ 59 │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Entry __VERIFIER_assert │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ 39 │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ 40 │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Ret (None, __VERIFIER_assert) │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ 56 │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ InlineReturn │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ 38 │ ◀┘ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, foo) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 13 │ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - └────────────────────────────────────────┘ + + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + ┌──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ │ + │ │ InlineReturn │ │ + │ ┌────┼────────────────────────────────────────────────────────────────┐ │ Inlined Proc 'foo(x, 4)' ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + │ │ │ ▼ ▼ │ │ │ + │ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ ┌───────────────────────────────────────▶ │ _ │ │ │ _ │ │ │ + │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ ▲ │ │ │ │ + │ │ │ │ │ Ret (None, bar) │ Inlined Proc 'foo(x, 3)' │ │ Entry main │ │ + │ │ │ │ ▼ │ │ ▼ │ │ + │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ InlineReturn │ _ │ ──────────────────────────────────────────────────┼────────────────────────────┘ │ _ │ ─┐ │ │ + │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ └────────────────────────────┐ │ InlineEntry '()' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ └────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ _ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ │ │ _ │ │ │ │ + │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ + │ │ │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ InlineEntry '(2)' ┌───────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ _ │ ◀────────────────────────────────────────────── │ _ │ ◀┼────────────────────── │ _ │ ◀┘ │ │ + │ │ │ └────────────────────────────────────────┘ └───────────────────────────┘ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ Entry bar ┌────────────────────────────┘ │ Test (tmp,true) │ │ + │ │ │ ▼ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ _ │ ─┐ │ ┌────────────────────── │ _ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineEntry '()' │ │ │ │ InlineEntry '(1)' │ │ + │ │ │ ▼ │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ _ │ │ │ │ │ _ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ Entry bar │ │ + │ │ │ ▼ │ │ │ ▼ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ _ │ ─┐ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineEntry '()' │ │ │ + │ │ │ ▼ │ │ │ ▼ │ │ │ + │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ + │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ + │ │ │ │ InlineReturn 'tmp' │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ + │ │ │ ▼ │ │ │ ▼ │ │ │ + ┌────────────────────────────────┐ │ Test (tmp,false) │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ _ │ ◀┼─────────────────────────┼──────────────────────────────────────── │ _ │ ◀┘ │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ + │ InlineEntry '(x, 4)' │ │ │ Test (tmp,true) │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ + ▼ │ │ ▼ │ │ ▼ │ │ │ + ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ _ │ │ │ │ _ │ ──────────────────────────────────────────────────┘ │ │ _ │ │ │ │ + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ + │ Entry foo │ │ │ InlineEntry '(x, 3)' │ │ InlineReturn 'tmp' │ │ │ + ▼ │ │ ▼ │ ▼ │ │ │ + ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ + ┌──────────────────────────────────────── │ _ │ │ │ │ _ │ ┌────────────────────────────┼────────────────────── │ _ │ ◀┘ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ │ │ │ │ │ + │ │ InlineEntry '(x < y)' │ │ │ Entry foo │ │ │ Test (tmp,true) │ │ + │ ▼ │ │ ▼ │ │ ▼ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ │ │ │ _ │ ─┐ │ │ │ _ │ ─┐ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ │ InlineEntry '(x < y)' │ │ │ │ InlineEntry '(x, 3)' │ │ │ + │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ _ │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ + │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ │ Entry __VERIFIER_assert │ │ │ │ Entry foo │ │ │ + │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ _ │ │ │ │ _ │ │ │ │ │ _ │ ─┼────────────────────────────────────────────────┐ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ InlineEntry '(x < y)' │ │ │ │ + │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ _ │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ │ + │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ │ + │ │ InlineReturn │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ Entry __VERIFIER_assert │ │ │ │ + │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ │ + │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + └───────────────────────────────────────▶ │ _ │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ │ + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ │ │ + │ Ret (None, foo) │ │ │ InlineReturn │ │ │ │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ + ▼ │ │ ▼ │ │ │ ▼ │ │ │ │ + ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ _ │ ─┘ │ │ _ │ ◀┘ │ │ │ _ │ │ │ │ │ + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ │ │ + │ │ Ret (None, foo) │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ + │ ▼ │ │ ▼ │ │ │ │ + │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ + └──────────────────────────────────────── │ _ │ │ │ │ _ │ │ │ │ │ + └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ InlineReturn │ │ │ │ + │ │ ▼ │ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ │ + │ │ │ _ │ ◀┼────────────────────────────────────────────────┘ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ + │ │ │ Ret (None, foo) │ │ │ + │ │ ▼ │ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ _ │ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ │ + Test (tmp,false) │ │ │ │ │ │ + ┌──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ InlineReturn │ Inlined Proc 'foo(x, 3)' │ │ + ▼ │ ▼ ▼ │ │ + ┌────────────────────────────────────────┐ InlineReturn │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ + ┌───────────────────────────────────────────────────────────── │ _ │ ┌─────────────────────────────────────────────────────────────────────────────┼─────────────────────▶ │ _ │ ◀┼─────────────────────────┐ │ + │ └────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ │ + │ │ InlineEntry '(x, 4)' │ │ │ Ret (None, bar) │ │ │ + │ ▼ │ │ ▼ │ │ │ + │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ _ │ │ │ Inlined Proc 'bar(1)' │ _ │ │ InlineReturn │ │ + │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ + │ │ │ │ │ │ │ Inlined Proc 'foo(x, 4)' │ + │ │ Entry foo │ │ │ InlineReturn │ │ │ + │ ▼ │ │ ▼ │ │ │ + │ ┌────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ + │ ┌──────────────────────────────────────── │ _ │ │ └─────────────────────▶ │ _ │ ◀┘ │ │ + │ │ └────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ │ │ │ ▲ Inlined Proc 'bar(2)' │ │ + │ │ │ InlineEntry '(x < y)' │ │ Ret (Some 0, main) └─────────────────────────────────────────────────────────────────────┼────────────────────────────┘ + │ │ ▼ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + │ │ │ _ │ │ │ _ │ │ + │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ │ Entry __VERIFIER_assert │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ _ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ _ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ │ │ _ │ │ │ + │ │ └────────────────────────────────────────┘ │ │ + │ │ │ │ │ + │ │ │ InlineReturn │ │ + │ │ ▼ │ │ + │ │ ┌────────────────────────────────────────┐ │ │ + │ └───────────────────────────────────────▶ │ _ │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (None, foo) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ ─┘ │ + │ └────────────────────────────────────────┘ │ + │ │ + └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected index 617aaa0385..1357a744c9 100644 --- a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected @@ -1,279 +1,279 @@ ┌────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(1)' │ ▼ │ ┌────────────────────────────────┐ │ - │ 14 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────── │ 20 │ │ + ┌──────────────────────────────────────── │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 21 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 29 │ ─┼───────────────────────────────────────────┐ + │ │ _ │ ─┼───────────────────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 44 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 27 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc 'foo(x, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 28 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 42 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 26 │ ◀┼───────────────────────────────────────────┘ + │ │ _ │ ◀┼───────────────────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 12 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────▶ │ 13 │ ─┼───────────────────────────────────────────┐ + └───────────────────────────────────────▶ │ _ │ ─┼───────────────────────────────────────────┐ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 4)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - │ 37 │ │ │ + │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - ┌──────────────────────────────────────── │ 38 │ │ │ + ┌──────────────────────────────────────── │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 46 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 34 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ Inlined Proc 'foo(x, 4)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 35 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 45 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - └───────────────────────────────────────▶ │ 36 │ │ │ + └───────────────────────────────────────▶ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - │ 10 │ │ │ + │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ - │ 11 │ ◀┼───────────────────────────────────────────┘ + │ _ │ ◀┼───────────────────────────────────────────┘ └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ │ - │ 25 │ │ Inlined Proc 'bar(1)' + │ _ │ │ Inlined Proc 'bar(1)' └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────── │ 15 │ ◀┘ + ┌──────────────────────────────────────── │ _ │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ InlineEntry '(2)' │ ▼ │ ┌────────────────────────────────┐ - │ │ 18 │ + │ │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ - │ │ 19 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 43 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 5 │ ─┼───────────────────────────────────────────┐ + │ │ _ │ ─┼───────────────────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 6 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 24 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 8 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 9 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 7 │ ◀┼───────────────────────────────────────────┘ + │ │ _ │ ◀┼───────────────────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 41 │ │ Inlined Proc 'foo(x, 3)' + │ │ _ │ │ Inlined Proc 'foo(x, 3)' │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - ┌────────────────────────────┼──────────────────────────────────────── │ 2 │ ◀┘ + ┌────────────────────────────┼──────────────────────────────────────── │ _ │ ◀┘ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(x, 4)' │ │ ▼ │ │ ┌────────────────────────────────┐ - │ │ │ 3 │ + │ │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ - │ │ │ 30 │ ─┐ + │ │ │ _ │ ─┐ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 31 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 33 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Inlined Proc 'foo(x, 4)' │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 32 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 16 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ - │ │ │ 17 │ ◀┘ + │ │ │ _ │ ◀┘ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ - │ │ │ 40 │ + │ │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ - └────────────────────────────┼───────────────────────────────────────▶ │ 4 │ + └────────────────────────────┼───────────────────────────────────────▶ │ _ │ │ └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ - │ Inlined Proc 'bar(2)' │ 39 │ + │ Inlined Proc 'bar(2)' │ _ │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ - └───────────────────────────────────────▶ │ 22 │ + └───────────────────────────────────────▶ │ _ │ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ - │ 23 │ + │ _ │ └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected index 89378c87e4..183936016b 100644 --- a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected @@ -1,171 +1,171 @@ ┌────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────┘ │ │ │ │ InlineEntry '(1)' │ ▼ │ ┌────────────────────────────────┐ │ - │ 26 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ │ - ┌───────────────────────── │ 9 │ │ + ┌───────────────────────── │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(1, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 10 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 14 │ ─┼────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 27 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 12 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc 'foo(1, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 13 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 25 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 11 │ ◀┼────────────────────────────┘ + │ │ _ │ ◀┼────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 4 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - └────────────────────────▶ │ 5 │ │ Inlined Proc 'bar(1)' + └────────────────────────▶ │ _ │ │ Inlined Proc 'bar(1)' └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ │ - │ 22 │ │ + │ _ │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ │ - ┌───────────────────────── │ 6 │ ◀┘ + ┌───────────────────────── │ _ │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ InlineEntry '(2)' │ ▼ │ ┌────────────────────────────────┐ - │ │ 7 │ + │ │ _ │ │ └────────────────────────────────┘ │ │ │ │ Entry bar │ ▼ │ ┌────────────────────────────────┐ - │ │ 17 │ ─┐ + │ │ _ │ ─┐ │ └────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(1, 3)' │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 18 │ │ + │ │ _ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ Entry foo │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 23 │ ─┼────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────┐ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x < y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 2 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 3 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc 'bar(2)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 20 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 28 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────┐ │ │ - │ │ 19 │ ◀┼────────────────────────────┘ + │ │ _ │ ◀┼────────────────────────────┘ │ └────────────────────────────────┘ │ │ │ │ │ │ Ret (None, foo) │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 15 │ │ Inlined Proc 'foo(1, 3)' + │ │ _ │ │ Inlined Proc 'foo(1, 3)' │ └────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ 16 │ ◀┘ + │ │ _ │ ◀┘ │ └────────────────────────────────┘ │ │ │ │ Ret (None, bar) │ ▼ │ ┌────────────────────────────────┐ - │ │ 21 │ + │ │ _ │ │ └────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────┐ - └────────────────────────▶ │ 8 │ + └────────────────────────▶ │ _ │ └────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────┐ - │ 24 │ + │ _ │ └────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/multicall_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_true-unreach-call.expected index bd10a33329..ecdff7eb2c 100644 --- a/tests/sv-comp/cfg/multicall_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_true-unreach-call.expected @@ -1,36 +1,44 @@ - ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────┐ │ - │ │ 0 │ │ - │ └────────────────────────────┘ │ - │ │ │ - │ InlineReturn │ Entry main │ - ▼ ▼ │ - ┌─────────────────────┐ Inlined Proc 'foo(1)' ┌────────────────────────────┐ │ - ┌────────────────────── │ 3 │ ◀─────────────────────── │ 1 │ │ - │ └─────────────────────┘ └────────────────────────────┘ │ - │ │ │ │ - │ Inlined Proc 'foo(1)' └──────────────────────┐ │ InlineEntry '(1)' │ - │ │ ▼ │ - │ ┌─────────────────────┐ │ ┌────────────────────────────┐ │ - └─────────────────────▶ │ 4 │ └─────────────────────▶ │ 2 │ │ - └─────────────────────┘ └────────────────────────────┘ │ - │ │ │ - │ Ret (Some 0, main) │ Entry foo │ - ▼ ▼ │ - ┌─────────────────────┐ ┌────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' ┌────────────────────────────────┐ Ret (None, foo) ┌───┐ - │ 5 │ │ 10 │ ─────────────────────────────────────────────▶ │ 8 │ ─────────────────▶ │ 9 │ - └─────────────────────┘ └────────────────────────────┘ └────────────────────────────────┘ └───┘ - │ ▲ - │ InlineEntry '(x - 1 < x)' │ InlineReturn - ▼ │ - ┌────────────────────────────┐ ┌────────────────────────────────┐ - │ 12 │ │ 11 │ - └────────────────────────────┘ └────────────────────────────────┘ - │ ▲ - │ Entry __VERIFIER_assert │ Ret (None, __VERIFIER_assert) - ▼ │ - ┌────────────────────────────┐ Test (! cond,false) ┌────────────────────────────────┐ - │ 6 │ ─────────────────────────────────────────────▶ │ 7 │ - └────────────────────────────┘ └────────────────────────────────┘ + ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────┘ │ + │ │ │ + │ InlineReturn │ Entry main │ + ▼ ▼ │ + ┌─────────────────────┐ Inlined Proc 'foo(1)' ┌────────────────────────────┐ │ + │ _ │ ◀─────────────────────────────── │ _ │ │ + └─────────────────────┘ └────────────────────────────┘ │ + │ │ │ + └──────────────────────┐ │ InlineEntry '(1)' │ + │ ▼ │ + ┌─────────────────────┐ │ ┌────────────────────────────┐ │ + ┌────────────▶ │ _ │ └─────────────────────────────▶ │ _ │ │ + │ └─────────────────────┘ └────────────────────────────┘ │ + │ │ │ │ + │ InlineReturn │ Ret (Some 0, main) │ Entry foo │ + │ ▼ ▼ │ + │ ┌─────────────────────┐ ┌────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' ┌───┐ Ret (None, foo) ┌───┐ + │ │ _ │ │ _ │ ─────────────────────────────────────────────▶ │ _ │ ─────────────────▶ │ _ │ + │ └─────────────────────┘ └────────────────────────────┘ └───┘ └───┘ + │ │ ▲ │ + │ │ InlineEntry '(x - 1 < x)' │ │ + │ ▼ │ │ + │ ┌────────────────────────────┐ │ │ + │ │ _ │ │ │ + │ └────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_assert │ │ + │ ▼ │ │ + │ ┌─────────────────────┐ Test (! cond,false) ┌────────────────────────────┐ │ │ + │ │ _ │ ◀─────────────────────────────── │ _ │ │ │ + │ └─────────────────────┘ └────────────────────────────┘ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) ┌────────────────────────────┐ InlineReturn │ │ + │ └────────────────────────────────────────────────────▶ │ _ │ ─────────────────────────────────────────────────┘ │ + │ └────────────────────────────┘ │ + │ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected index ec88f178ac..7291ee1450 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -1,99 +1,99 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 7 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 8 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ │ -│ 9 │ ◀───────────────── │ 3 │ ◀┘ +│ _ │ ◀───────────────── │ _ │ ◀┘ └───┘ └────────────────────────────────────────┘ │ │ │ │ Test (tmp,false) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 10 │ + │ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'x = 2' │ ▼ │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └────────────────────▶ │ 11 │ + └────────────────────▶ │ _ │ └────────────────────────────────────────┘ │ │ Test (1 <= x,true) ▼ ┌────────────────────────────────────────┐ - │ 15 │ + │ _ │ └────────────────────────────────────────┘ │ │ Test (x <= 2,true) ▼ ┌────────────────────────────────────────┐ - │ 16 │ + │ _ │ └────────────────────────────────────────┘ │ │ Assign 'tmp___0 = 1' ▼ ┌────────────────────────────────────────┐ - │ 4 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(tmp___0)' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 5 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 13 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' ▼ │ ┌────────────────────────────────────────┐ │ - │ 14 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 17 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 6 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 12 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected index 44f5f26406..4e1d43bfbb 100644 --- a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 9 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 5 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 6 │ │ + ┌─────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 3,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ ─┼────────────────────────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x < 2,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼─────────────────── │ 14 │ │ │ + ┌────┼─────────────────── │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 15 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 11 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x < 3,false) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 12 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 13 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x < 2,false) │ │ ▼ ▼ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └──────────────────▶ │ 7 │ + │ └──────────────────▶ │ _ │ │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 10 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected index 0efe3e380b..b87f165727 100644 --- a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 9 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 5 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 6 │ │ + ┌─────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 3,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ ─┼────────────────────────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x == 1,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼─────────────────── │ 14 │ │ │ + ┌────┼─────────────────── │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 15 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 11 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x < 3,false) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 12 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 13 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x == 1,false) │ │ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └──────────────────▶ │ 7 │ + │ └──────────────────▶ │ _ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 10 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected index 3f2ddfeffe..82dd1351b7 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected @@ -5,89 +5,89 @@ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 0 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry main │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 1 │ ─┐ │ │ + │ │ │ _ │ ─┐ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 8 │ │ │ │ + │ │ │ _ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Test (x < 2,false) │ │ Entry __VERIFIER_nondet_int │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 9 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 18 │ │ │ │ + │ │ │ _ │ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ │ │ ▼ │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ 10 │ ◀┘ │ │ + │ │ │ _ │ ◀┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 0,false) │ Assign 'x = tmp' │ │ │ ▼ ▼ │ │ │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ - └──────────────────▶ │ 14 │ ─┐ │ 11 │ ──────────────────────────────────────────────────┘ │ + └──────────────────▶ │ _ │ ─┐ │ _ │ ──────────────────────────────────────────────────┘ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineEntry '(1)' │ │ Test (x > 0,true) │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 20 │ │ │ 12 │ ───────────────────────────────────────────────────────┘ + │ _ │ │ │ _ │ ───────────────────────────────────────────────────────┘ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ │ Test (x < 2,true) ▼ │ ▼ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ - │ 15 │ │ │ 13 │ ─┐ + │ _ │ │ │ _ │ ─┐ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(1)' │ InlineEntry '(x == 1)' │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 16 │ │ │ 4 │ │ + │ _ │ │ │ _ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 19 │ │ │ 5 │ │ + │ _ │ │ │ _ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' ▼ │ ▼ │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ 17 │ ◀┘ │ 2 │ │ + │ _ │ ◀┘ │ _ │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 3 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ InlineReturn │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 6 │ ◀┘ + │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ │ │ Ret (Some 0, main) │ ▼ │ Ret (Some 1, main) ┌────────────────────────────────────────┐ - └─────────────────────────────────────────────────────────────────────▶ │ 7 │ + └─────────────────────────────────────────────────────────────────────▶ │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected index e8ea9a36a7..38b2720165 100644 --- a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected @@ -1,93 +1,92 @@ - ┌────────────────────────────────────────┐ - │ 0 │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ 1 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 4 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 5 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 19 │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ 6 │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ 7 │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0,true) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 10 │ │ Test (x > 0,false) - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x < 2,false) │ - │ ▼ │ -┌────────────────────────────────┐ InlineEntry '(1)' │ ┌────────────────────────────────────────┐ │ -│ 2 │ ◀──────────────────────┼────────────────── │ 12 │ ◀┘ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ - │ │ │ - │ Entry __VERIFIER_assert │ Test (x < 2,true) └─────────────────────────────────────────┐ - ▼ │ │ -┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ -│ 3 │ └─────────────────▶ │ 11 │ ─┼────────────────────────────────────────────────┐ -└────────────────────────────────┘ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ Test (! cond,false) │ InlineEntry '(x == 1)' │ │ - ▼ ▼ │ │ -┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ -│ 16 │ │ 15 │ │ │ -└────────────────────────────────┘ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ │ - ▼ ▼ │ │ -┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ -│ 17 │ ───────────────────────┐ │ 8 │ │ │ -└────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ 9 │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ InlineReturn │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ 18 │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(1)' │ Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ ▼ ▼ - │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────▶ │ 13 │ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ 14 │ - └────────────────────────────────────────┘ + + ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ ─┐ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineEntry '()' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Entry __VERIFIER_nondet_int │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ │ │ + │ └────────────────────────────────────────┘ │ │ + │ │ │ │ + │ │ InlineReturn 'tmp' │ │ + │ ▼ │ │ + │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ Test (x < 2,false) │ Assign 'x = tmp' │ + ▼ ▼ │ + ┌────────────────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ │ + ┌─ │ _ │ ◀──────────────────── │ _ │ │ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ InlineEntry '(1)' │ Test (x > 0,true) │ + │ ▼ ▼ │ + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ _ │ ──────────────────────────────────────────────────┘ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ + │ │ │ + │ │ Entry __VERIFIER_assert │ Test (x < 2,true) + │ ▼ ▼ + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ + │ │ _ │ │ _ │ ─┐ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Test (! cond,false) │ InlineEntry '(x == 1)' │ + │ ▼ ▼ │ + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ _ │ │ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ + │ ▼ ▼ │ + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ _ │ │ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Test (! cond,false) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ _ │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ Ret (None, __VERIFIER_assert) │ + │ │ ▼ │ + │ │ ┌────────────────────────────────────────┐ │ + │ │ │ _ │ │ + │ │ └────────────────────────────────────────┘ │ + │ │ │ │ + │ │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ │ ▼ ▼ + │ │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + │ └────────────────────────────────────────────────────▶ │ _ │ + │ └─────────────────────────────────────────────────────────────────────────────────────────┘ + │ │ ▲ + │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(1)' + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └───────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected index 08afea2b9a..33c515c204 100644 --- a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected @@ -1,87 +1,87 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 10 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 5 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ 7 │ │ + ┌─────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x < 2,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ ─┼────────────────────────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 13 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ Test (x < 2,false) │ 11 │ │ │ + │ Test (x < 2,false) │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 12 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 14 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ Test (x > 0,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └──────────────────▶ │ 9 │ + └──────────────────▶ │ _ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 6 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected index 7b54a56ece..4db209decd 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -1,81 +1,81 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 6 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 7 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 14 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 8 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌─────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ - ┌──────────────────▶ │ 12 │ ◀────────────────────── │ 9 │ + ┌──────────────────▶ │ _ │ ◀────────────────────── │ _ │ │ └─────────────────────┘ └────────────────────────────────────────┘ │ │ │ │ Test (x < 2,false) │ │ Test (x > 0,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ - └──────────────────────┼──────────────────────────────────────────── │ 10 │ + └──────────────────────┼──────────────────────────────────────────── │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (x < 2,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 11 │ + │ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Assign 'tmp___0 = 1' │ ▼ │ Assign 'tmp___0 = 0' ┌────────────────────────────────────────┐ - └───────────────────────────────────────────▶ │ 13 │ + └───────────────────────────────────────────▶ │ _ │ └────────────────────────────────────────┘ │ │ Assign 'y = tmp___0' ▼ ┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ - │ 4 │ ◀────────────────────── │ 15 │ + │ _ │ ◀────────────────────── │ _ │ └─────────────────────┘ └────────────────────────────────────────┘ │ │ │ Ret (Some 0, main) │ Test (y,true) ▼ ▼ ┌─────────────────────┐ ┌────────────────────────────────────────┐ - │ 5 │ │ 16 │ + │ _ │ │ _ │ └─────────────────────┘ └────────────────────────────────────────┘ │ │ InlineEntry '()' ▼ ┌────────────────────────────────────────┐ - │ 2 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry __VERIFIER_error ▼ ┌────────────────────────────────────────┐ - │ 3 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected index e8a4c886b1..329220df5d 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -1,75 +1,75 @@ ┌────────────────────────────────────────┐ -│ 0 │ +│ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ -│ 1 │ ─┐ +│ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 2 │ │ +│ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' +│ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 9 │ │ +│ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 5 │ ◀┘ +│ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ -│ 6 │ ─┐ +│ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x > 0,true) │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 7 │ │ Test (x > 0,false) +│ _ │ │ Test (x > 0,false) └────────────────────────────────────────┘ │ │ │ │ Test (x < 0,false) │ ▼ │ ┌────────────────────────────────────────┐ │ -│ 8 │ ◀┘ +│ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'tmp___0 = 0' ▼ ┌────────────────────────────────────────┐ -│ 12 │ +│ _ │ └────────────────────────────────────────┘ │ │ Assign 'y = tmp___0' ▼ ┌────────────────────────────────────────┐ -│ 10 │ +│ _ │ └────────────────────────────────────────┘ │ │ Test (y,false) ▼ ┌────────────────────────────────────────┐ -│ 11 │ +│ _ │ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ -│ 4 │ +│ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected index 2910f985c9..0dfbc18dee 100644 --- a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 6 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 5 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x < 1,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 14 │ │ + ┌────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x > 2,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 15 │ ─┼────────────────────────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x > 1,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼────────────────── │ 10 │ │ │ + ┌────┼────────────────── │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 11 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 8 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 2,true) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 9 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 13 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x > 1,true) │ │ ▼ ▼ ▼ │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └─────────────────▶ │ 12 │ + │ └─────────────────▶ │ _ │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 7 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected index 4198737683..9e2ae0edfd 100644 --- a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected @@ -1,95 +1,95 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 6 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 5 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x < 1,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 14 │ │ + ┌────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x > 2,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 15 │ ─┼────────────────────────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (x != 1,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼────────────────── │ 10 │ │ │ + ┌────┼────────────────── │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 11 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 8 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 2,true) │ Test (! cond,false) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 9 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ 13 │ │ │ + │ │ │ _ │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x != 1,true) │ │ ▼ ▼ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └─────────────────▶ │ 12 │ + │ └─────────────────▶ │ _ │ │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ▲ │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 7 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected index 8a6729bf9d..8ccfffdd65 100644 --- a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected @@ -1,87 +1,87 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ 1 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '()' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 2 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_nondet_int │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 3 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' └────────────────────────────────────────┘ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 7 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineReturn 'tmp' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ ◀┘ + │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 'x = tmp' ▼ ┌────────────────────────────────────────┐ - │ 5 │ ─┐ + │ _ │ ─┐ └────────────────────────────────────────┘ │ │ │ │ Test (x < 1,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - ┌────────────────── │ 14 │ │ + ┌────────────────── │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (x > 1,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 10 │ ─┼────────────────────────────────────────────────┐ + │ │ _ │ ─┼────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == 1)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 11 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ Test (x > 1,true) │ 8 │ │ │ + │ Test (x > 1,true) │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 9 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 13 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ Test (x < 1,true) │ Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────▶ │ 12 │ + └─────────────────▶ │ _ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌────────────────────────────────────────┐ - │ 6 │ + │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index 058f0115b4..2fd27bd99e 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -6,7 +6,7 @@ (target for_fun_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -21,7 +21,7 @@ (target for_odd_vesal_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -36,7 +36,7 @@ (target for_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -51,7 +51,7 @@ (target global_init_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -66,7 +66,7 @@ (target if_det_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -81,7 +81,7 @@ (target if_det_incr_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -96,7 +96,7 @@ (target if_det_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -111,7 +111,7 @@ (target if_mod_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -126,7 +126,7 @@ (target if_mod_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -141,7 +141,7 @@ (target if_nondet_fun_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -156,7 +156,7 @@ (target if_nondet_var_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -171,7 +171,7 @@ (target if_trier_exclude_multiple_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -186,7 +186,7 @@ (target if_trier_exclude_multiple_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -201,7 +201,7 @@ (target if_trier_exclude_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -216,7 +216,7 @@ (target eq_double_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -231,7 +231,7 @@ (target eq_single_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -246,7 +246,7 @@ (target multivar_false-unreach-call1.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -261,7 +261,7 @@ (target multivar_true-unreach-call1.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -276,7 +276,7 @@ (target multicall_context_join_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -291,7 +291,7 @@ (target multicall_context_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -306,7 +306,7 @@ (target multicall_join_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -321,7 +321,7 @@ (target multicall_nested_join_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -336,7 +336,7 @@ (target multicall_nested_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -351,7 +351,7 @@ (target multicall_return_context_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -366,7 +366,7 @@ (target multicall_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -381,7 +381,7 @@ (target join_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -396,7 +396,7 @@ (target builtin_expect_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -411,7 +411,7 @@ (target region_global_init_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -426,7 +426,7 @@ (target local_shadow_fun_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -441,7 +441,7 @@ (target free_spawn_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -456,7 +456,7 @@ (target free_spawn_ub_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -471,7 +471,7 @@ (target and3_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -486,7 +486,7 @@ (target and3dead_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -501,7 +501,7 @@ (target and_copy_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -516,7 +516,7 @@ (target and_join_invariant_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -531,7 +531,7 @@ (target and_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -546,7 +546,7 @@ (target and_var_false-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -561,7 +561,7 @@ (target and_var_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -576,7 +576,7 @@ (target or3_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -591,7 +591,7 @@ (target or3dead_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -606,7 +606,7 @@ (target or_true-unreach-call.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule diff --git a/tests/sv-comp/eq/eq_double_true-unreach-call.expected b/tests/sv-comp/eq/eq_double_true-unreach-call.expected index ab09689b24..ca2079d2e5 100644 --- a/tests/sv-comp/eq/eq_double_true-unreach-call.expected +++ b/tests/sv-comp/eq/eq_double_true-unreach-call.expected @@ -1,141 +1,141 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ InlineReturn ┌────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(a == b)' - ┌─────────────────────────────────────────────────────▶ │ 1 │ ◀─────────────────────────────────────────────────┐ + ┌─────────────────────────────────────────────────────▶ │ _ │ ◀─────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (1,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 14 │ ─┐ │ + │ │ _ │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 22 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 23 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 20 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 16 │ ◀┘ │ + │ │ _ │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 17 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 4 │ ─┐ │ + │ │ _ │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == y)' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 5 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 19 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 18 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (None, __VERIFIER_assert) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 15 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ ┌───────────────────────────────────────────────── │ 6 │ ◀┘ │ + │ ┌───────────────────────────────────────────────── │ _ │ ◀┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' ┌────────────────────────────────────────────────┘ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 21 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ 11 │ │ + │ │ Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ 12 │ │ + │ │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp___0' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ - │ └────────────────────────────────────────────────▶ │ 7 │ │ + │ └────────────────────────────────────────────────▶ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ └────┐ │ Assign 'a = tmp___0' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'b = a' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 13 │ ─┘ + │ │ _ │ ─┘ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(a == b)' │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 9 │ + │ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 10 │ + │ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ 2 │ + │ │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────────────┐ - └───────────────────────────────────────────────── │ 3 │ + └───────────────────────────────────────────────── │ _ │ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/eq_single_true-unreach-call.expected b/tests/sv-comp/eq/eq_single_true-unreach-call.expected index c4b20b3b26..f8b5cdb969 100644 --- a/tests/sv-comp/eq/eq_single_true-unreach-call.expected +++ b/tests/sv-comp/eq/eq_single_true-unreach-call.expected @@ -1,75 +1,75 @@ ┌────────────────────────────────────────┐ - │ 0 │ + │ _ │ └────────────────────────────────────────┘ │ │ Entry main ▼ ┌────────────────────────────────────────┐ InlineReturn - ┌────────────────────────────────────────▶ │ 1 │ ◀─────────────────────────────────────────────────┐ + ┌────────────────────────────────────────▶ │ _ │ ◀─────────────────────────────────────────────────┐ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Test (1,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 6 │ ─┐ │ + │ │ _ │ ─┐ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 7 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 10 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ Inlined Proc '__VERIFIER_assert(x == y)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 2 │ │ │ + │ │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ 3 │ ◀┘ │ + │ │ _ │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' ┌────────────────────────────────────────────────┘ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ 8 │ │ + │ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - └───────────────────────────────────────── │ 9 │ │ + └───────────────────────────────────────── │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x == y)' │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 12 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 4 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Test (! cond,false) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 5 │ │ + │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ Ret (None, __VERIFIER_assert) │ ▼ │ ┌────────────────────────────────────────┐ │ - │ 11 │ ─┘ + │ _ │ ─┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/multivar_false-unreach-call1.expected b/tests/sv-comp/eq/multivar_false-unreach-call1.expected index 348de9666c..cec99f07fd 100644 --- a/tests/sv-comp/eq/multivar_false-unreach-call1.expected +++ b/tests/sv-comp/eq/multivar_false-unreach-call1.expected @@ -2,89 +2,89 @@ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 0 │ │ + │ │ _ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Entry main │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 1 │ ─┐ │ + │ │ _ │ ─┐ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 8 │ │ │ + │ │ _ │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_uint │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 9 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 16 │ │ │ + │ │ _ │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 12 │ ◀┘ │ + │ │ _ │ ◀┘ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 13 │ │ + │ │ _ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌─────────────────────────┐ Test (x < 1024U,true) ┌─────────────────────────────────────────┐ Assign 'y = y + 1U' │ - │ │ 14 │ ◀─────────────────────── │ 19 │ ◀──────────────────────────────────────────────────┘ + │ │ _ │ ◀─────────────────────── │ _ │ ◀──────────────────────────────────────────────────┘ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ - └─ │ 15 │ │ 18 │ ─┐ + └─ │ _ │ │ _ │ ─┐ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x < y)' │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 4 │ │ + │ _ │ │ └─────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ - │ 17 │ ◀─────────────────────── │ 5 │ │ + │ _ │ ◀─────────────────────── │ _ │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 10 │ │ 2 │ │ + │ _ │ │ _ │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 11 │ │ 3 │ │ + │ _ │ │ _ │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 6 │ ◀┘ + │ _ │ ◀┘ └─────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌─────────────────────────────────────────┐ - │ 7 │ + │ _ │ └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/eq/multivar_true-unreach-call1.expected b/tests/sv-comp/eq/multivar_true-unreach-call1.expected index ca2b36923d..345783e41f 100644 --- a/tests/sv-comp/eq/multivar_true-unreach-call1.expected +++ b/tests/sv-comp/eq/multivar_true-unreach-call1.expected @@ -2,89 +2,89 @@ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 0 │ │ + │ │ _ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Entry main │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 1 │ ─┐ │ + │ │ _ │ ─┐ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '()' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 8 │ │ │ + │ │ _ │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Entry __VERIFIER_nondet_uint │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 9 │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 16 │ │ │ + │ │ _ │ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ ▼ │ │ │ ┌─────────────────────────────────────────┐ │ │ - │ │ 12 │ ◀┘ │ + │ │ _ │ ◀┘ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'x = tmp' │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ 13 │ │ + │ │ _ │ │ │ └─────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'y = x' │ │ ▼ │ │ ┌─────────────────────────┐ Test (x < 1024U,true) ┌─────────────────────────────────────────┐ Assign 'y = y + 1U' │ - │ │ 14 │ ◀─────────────────────── │ 19 │ ◀──────────────────────────────────────────────────┘ + │ │ _ │ ◀─────────────────────── │ _ │ ◀──────────────────────────────────────────────────┘ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ - └─ │ 15 │ │ 18 │ ─┐ + └─ │ _ │ │ _ │ ─┐ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x == y)' │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 4 │ │ + │ _ │ │ └─────────────────────────────────────────┘ │ │ │ │ Entry __VERIFIER_assert │ ▼ │ ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ - │ 17 │ ◀─────────────────────── │ 5 │ │ + │ _ │ ◀─────────────────────── │ _ │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 10 │ │ 2 │ │ + │ _ │ │ _ │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ 11 │ │ 3 │ │ + │ _ │ │ _ │ │ └─────────────────────────┘ └─────────────────────────────────────────┘ │ │ │ │ InlineReturn │ ▼ │ ┌─────────────────────────────────────────┐ │ - │ 6 │ ◀┘ + │ _ │ ◀┘ └─────────────────────────────────────────┘ │ │ Ret (Some 0, main) ▼ ┌─────────────────────────────────────────┐ - │ 7 │ + │ _ │ └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index 7aa6602538..73bc48fe57 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -10,7 +10,7 @@ let generate_rule file = (target %s.output) (action (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg --set witness.graphml.id enumerate)) + (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %%{target} (run graph-easy --as=boxart arg.dot))))) (rule From f2f82e4b9943e6d81d4cc847bb2ace0659d71ab1 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 16 May 2024 16:46:57 +0300 Subject: [PATCH 181/689] Fix dune cram test according to complete logging --- tests/regression/29-svcomp/32-no-ov.t | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/regression/29-svcomp/32-no-ov.t b/tests/regression/29-svcomp/32-no-ov.t index c58099b5e4..72978a1fac 100644 --- a/tests/regression/29-svcomp/32-no-ov.t +++ b/tests/regression/29-svcomp/32-no-ov.t @@ -1,4 +1,5 @@ $ goblint --enable ana.int.interval --enable ana.sv-comp.enabled --enable ana.sv-comp.functions --set ana.specification "CHECK( init(main()), LTL(G ! overflow) )" 32-no-ov.c + [Info] Setting "ana.int.interval" to true [Info] SV-COMP specification: CHECK( init(main()), LTL(G ! overflow) ) [Warning][Integer > Overflow][CWE-190] Unsigned integer overflow (32-no-ov.c:5:6-5:159) [Warning][Integer > Overflow][CWE-190] Unsigned integer overflow (32-no-ov.c:5:6-5:159) From 4900fd5a32a89d4084d2b7c23b6391a3b90d7d81 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 10:23:50 +0300 Subject: [PATCH 182/689] Clean up ARG test rule generation, conditional on graph-easy --- tests/sv-comp/dune | 28 +- tests/sv-comp/dune.inc | 1516 ++++++++++++++++++++++---------------- tests/sv-comp/gen/gen.ml | 43 +- 3 files changed, 940 insertions(+), 647 deletions(-) diff --git a/tests/sv-comp/dune b/tests/sv-comp/dune index 07a9f75d62..bf44bb8cb1 100644 --- a/tests/sv-comp/dune +++ b/tests/sv-comp/dune @@ -3,17 +3,17 @@ (rule (alias runtest) (mode promote) - (deps (:files - (glob_files basic/*.c) -(glob_files eq/*.c) -(glob_files cfg/multicall_*.c) -(glob_files cfg/join_true-unreach-call.c) -(glob_files cfg/builtin_expect_true-unreach-call.c) -(glob_files cfg/region_global_init_true-unreach-call.c) -(glob_files cfg/local_shadow_fun_true-unreach-call.c) -(glob_files cfg/free_spawn_*.c) -(glob_files cfg/uncil/*.c) - )) - (action (with-stdout-to - dune.inc - (run gen/gen.exe %{files})))) + (deps + (:files ; patterns from ReachSafety-Basic.set + (glob_files basic/*.c) + (glob_files eq/*.c) + (glob_files cfg/multicall_*.c) + (glob_files cfg/join_true-unreach-call.c) + (glob_files cfg/builtin_expect_true-unreach-call.c) + (glob_files cfg/region_global_init_true-unreach-call.c) + (glob_files cfg/local_shadow_fun_true-unreach-call.c) + (glob_files cfg/free_spawn_*.c) + (glob_files cfg/uncil/*.c))) + (action + (with-stdout-to dune.inc + (run gen/gen.exe %{files})))) diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index 2fd27bd99e..942f24d2b4 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -1,616 +1,902 @@ - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c for_fun_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target for_fun_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff for_fun_true-unreach-call.expected for_fun_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c for_odd_vesal_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target for_odd_vesal_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff for_odd_vesal_true-unreach-call.expected for_odd_vesal_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c for_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target for_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff for_true-unreach-call.expected for_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c global_init_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target global_init_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff global_init_true-unreach-call.expected global_init_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_det_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_det_false-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_det_false-unreach-call.expected if_det_false-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_det_incr_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_det_incr_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_det_incr_true-unreach-call.expected if_det_incr_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_det_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_det_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_det_true-unreach-call.expected if_det_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_mod_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_mod_false-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_mod_false-unreach-call.expected if_mod_false-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_mod_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_mod_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_mod_true-unreach-call.expected if_mod_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_nondet_fun_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_nondet_fun_false-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_nondet_fun_false-unreach-call.expected if_nondet_fun_false-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_nondet_var_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_nondet_var_false-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_nondet_var_false-unreach-call.expected if_nondet_var_false-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_trier_exclude_multiple_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_trier_exclude_multiple_false-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_trier_exclude_multiple_false-unreach-call.expected if_trier_exclude_multiple_false-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_trier_exclude_multiple_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_trier_exclude_multiple_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_trier_exclude_multiple_true-unreach-call.expected if_trier_exclude_multiple_true-unreach-call.output))) - ) - - (subdir basic - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c if_trier_exclude_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target if_trier_exclude_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff if_trier_exclude_true-unreach-call.expected if_trier_exclude_true-unreach-call.output))) - ) - - (subdir eq - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c eq_double_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target eq_double_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff eq_double_true-unreach-call.expected eq_double_true-unreach-call.output))) - ) - - (subdir eq - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c eq_single_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target eq_single_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff eq_single_true-unreach-call.expected eq_single_true-unreach-call.output))) - ) - - (subdir eq - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multivar_false-unreach-call1.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multivar_false-unreach-call1.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multivar_false-unreach-call1.expected multivar_false-unreach-call1.output))) - ) - - (subdir eq - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multivar_true-unreach-call1.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multivar_true-unreach-call1.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multivar_true-unreach-call1.expected multivar_true-unreach-call1.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_context_join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_context_join_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_context_join_true-unreach-call.expected multicall_context_join_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_context_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_context_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_context_true-unreach-call.expected multicall_context_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_join_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_join_true-unreach-call.expected multicall_join_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_nested_join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_nested_join_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_nested_join_true-unreach-call.expected multicall_nested_join_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_nested_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_nested_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_nested_true-unreach-call.expected multicall_nested_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_return_context_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_return_context_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_return_context_true-unreach-call.expected multicall_return_context_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c multicall_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target multicall_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff multicall_true-unreach-call.expected multicall_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c join_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target join_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff join_true-unreach-call.expected join_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c builtin_expect_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target builtin_expect_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff builtin_expect_true-unreach-call.expected builtin_expect_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c region_global_init_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target region_global_init_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff region_global_init_true-unreach-call.expected region_global_init_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c local_shadow_fun_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target local_shadow_fun_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff local_shadow_fun_true-unreach-call.expected local_shadow_fun_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c free_spawn_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target free_spawn_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff free_spawn_true-unreach-call.expected free_spawn_true-unreach-call.output))) - ) - - (subdir cfg - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c free_spawn_ub_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target free_spawn_ub_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff free_spawn_ub_true-unreach-call.expected free_spawn_ub_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and3_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and3_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and3_true-unreach-call.expected and3_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and3dead_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and3dead_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and3dead_true-unreach-call.expected and3dead_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and_copy_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and_copy_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and_copy_true-unreach-call.expected and_copy_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and_join_invariant_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and_join_invariant_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and_join_invariant_true-unreach-call.expected and_join_invariant_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and_true-unreach-call.expected and_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and_var_false-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and_var_false-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and_var_false-unreach-call.expected and_var_false-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c and_var_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target and_var_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff and_var_true-unreach-call.expected and_var_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c or3_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target or3_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff or3_true-unreach-call.expected or3_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c or3dead_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target or3dead_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff or3dead_true-unreach-call.expected or3dead_true-unreach-call.output))) - ) - - (subdir cfg/uncil - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c or_true-unreach-call.c) (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target or_true-unreach-call.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) - - (rule - (alias runtest) - (action (diff or_true-unreach-call.expected or_true-unreach-call.output))) - ) - \ No newline at end of file +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c for_fun_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target for_fun_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff for_fun_true-unreach-call.expected for_fun_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c for_odd_vesal_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target for_odd_vesal_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff for_odd_vesal_true-unreach-call.expected for_odd_vesal_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c for_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target for_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff for_true-unreach-call.expected for_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c global_init_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target global_init_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff global_init_true-unreach-call.expected global_init_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_det_false-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_det_false-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_det_false-unreach-call.expected if_det_false-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_det_incr_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_det_incr_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_det_incr_true-unreach-call.expected if_det_incr_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_det_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_det_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_det_true-unreach-call.expected if_det_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_mod_false-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_mod_false-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_mod_false-unreach-call.expected if_mod_false-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_mod_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_mod_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_mod_true-unreach-call.expected if_mod_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_nondet_fun_false-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_nondet_fun_false-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_nondet_fun_false-unreach-call.expected if_nondet_fun_false-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_nondet_var_false-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_nondet_var_false-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_nondet_var_false-unreach-call.expected if_nondet_var_false-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_trier_exclude_multiple_false-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_trier_exclude_multiple_false-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_trier_exclude_multiple_false-unreach-call.expected if_trier_exclude_multiple_false-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_trier_exclude_multiple_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_trier_exclude_multiple_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_trier_exclude_multiple_true-unreach-call.expected if_trier_exclude_multiple_true-unreach-call.output)))) + +(subdir basic + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c if_trier_exclude_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target if_trier_exclude_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff if_trier_exclude_true-unreach-call.expected if_trier_exclude_true-unreach-call.output)))) + +(subdir eq + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c eq_double_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target eq_double_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff eq_double_true-unreach-call.expected eq_double_true-unreach-call.output)))) + +(subdir eq + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c eq_single_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target eq_single_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff eq_single_true-unreach-call.expected eq_single_true-unreach-call.output)))) + +(subdir eq + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multivar_false-unreach-call1.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multivar_false-unreach-call1.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multivar_false-unreach-call1.expected multivar_false-unreach-call1.output)))) + +(subdir eq + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multivar_true-unreach-call1.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multivar_true-unreach-call1.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multivar_true-unreach-call1.expected multivar_true-unreach-call1.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_context_join_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_context_join_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_context_join_true-unreach-call.expected multicall_context_join_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_context_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_context_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_context_true-unreach-call.expected multicall_context_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_join_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_join_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_join_true-unreach-call.expected multicall_join_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_nested_join_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_nested_join_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_nested_join_true-unreach-call.expected multicall_nested_join_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_nested_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_nested_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_nested_true-unreach-call.expected multicall_nested_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_return_context_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_return_context_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_return_context_true-unreach-call.expected multicall_return_context_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c multicall_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target multicall_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff multicall_true-unreach-call.expected multicall_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c join_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target join_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff join_true-unreach-call.expected join_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c builtin_expect_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target builtin_expect_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff builtin_expect_true-unreach-call.expected builtin_expect_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c region_global_init_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target region_global_init_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff region_global_init_true-unreach-call.expected region_global_init_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c local_shadow_fun_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target local_shadow_fun_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff local_shadow_fun_true-unreach-call.expected local_shadow_fun_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c free_spawn_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target free_spawn_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff free_spawn_true-unreach-call.expected free_spawn_true-unreach-call.output)))) + +(subdir cfg + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c free_spawn_ub_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target free_spawn_ub_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff free_spawn_ub_true-unreach-call.expected free_spawn_ub_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and3_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and3_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and3_true-unreach-call.expected and3_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and3dead_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and3dead_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and3dead_true-unreach-call.expected and3dead_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and_copy_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_copy_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and_copy_true-unreach-call.expected and_copy_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and_join_invariant_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_join_invariant_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and_join_invariant_true-unreach-call.expected and_join_invariant_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and_true-unreach-call.expected and_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and_var_false-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_var_false-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and_var_false-unreach-call.expected and_var_false-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c and_var_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target and_var_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff and_var_true-unreach-call.expected and_var_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c or3_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target or3_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff or3_true-unreach-call.expected or3_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c or3dead_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target or3dead_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff or3dead_true-unreach-call.expected or3dead_true-unreach-call.output)))) + +(subdir cfg/uncil + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c or_true-unreach-call.c) + (:prop %{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target or_true-unreach-call.output) + (enabled_if %{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %{target} + (run graph-easy --as=boxart arg.dot))))) + + (rule + (alias runtest) + (enabled_if %{bin-available:graph-easy}) + (action + (diff or_true-unreach-call.expected or_true-unreach-call.output)))) diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index 73bc48fe57..e94af33e00 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -1,23 +1,30 @@ -let generate_rule file = - let dir = Filename.dirname file in - let file'' = Filename.basename file in - let file' = Filename.chop_extension file'' in +let generate_rule c_dir_file = + let dir = Filename.dirname c_dir_file in + let c_file = Filename.basename c_dir_file in + let file = Filename.chop_extension c_file in Printf.printf {| - (subdir %s - (rule - (alias runtest) - (deps (sandbox always) (package goblint) (:c %s) (:prop %%{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) - (target %s.output) - (action - (progn - (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %%{target} (run graph-easy --as=boxart arg.dot))))) +(subdir %s + (rule + (deps + (sandbox always) ; must sandbox to prevent arg.dot-s from parallel runs from interfering + (package goblint) ; depend on entire goblint package for svcomp21 conf + (:c %s) + (:prop %%{project_root}/tests/sv-comp/unreach-call-__VERIFIER_error.prp)) + (target %s.output) + (enabled_if %%{bin-available:graph-easy}) + (action + (progn + (ignore-outputs + (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (with-stdout-to %%{target} + (run graph-easy --as=boxart arg.dot))))) - (rule - (alias runtest) - (action (diff %s.expected %s.output))) - ) - |} dir file'' file' file' file' + (rule + (alias runtest) + (enabled_if %%{bin-available:graph-easy}) + (action + (diff %s.expected %s.output)))) +|} dir c_file file file file let () = Sys.argv From 374f1a4cefe9c1dae24490c3f309a2976c5f4910 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 11:04:59 +0300 Subject: [PATCH 183/689] Use dotted edges for ARG InlinedEdge --- src/witness/argTools.ml | 8 +- .../basic/for_fun_true-unreach-call.expected | 106 ++-- .../for_odd_vesal_true-unreach-call.expected | 130 ++--- .../basic/for_true-unreach-call.expected | 60 +- .../global_init_true-unreach-call.expected | 60 +- .../basic/if_mod_false-unreach-call.expected | 48 +- .../basic/if_mod_true-unreach-call.expected | 48 +- .../if_nondet_fun_false-unreach-call.expected | 48 +- ...clude_multiple_false-unreach-call.expected | 124 ++-- ...xclude_multiple_true-unreach-call.expected | 166 +++--- ...f_trier_exclude_true-unreach-call.expected | 108 ++-- .../cfg/free_spawn_true-unreach-call.expected | 48 +- .../cfg/join_true-unreach-call.expected | 108 ++-- ...ocal_shadow_fun_true-unreach-call.expected | 190 +++---- ...ll_context_join_true-unreach-call.expected | 188 +++---- ...lticall_context_true-unreach-call.expected | 218 +++---- .../multicall_join_true-unreach-call.expected | 170 +++--- ...all_nested_join_true-unreach-call.expected | 386 ++++++------- ...ulticall_nested_true-unreach-call.expected | 530 +++++++++--------- ..._return_context_true-unreach-call.expected | 314 +++++------ .../cfg/multicall_true-unreach-call.expected | 4 +- ...ion_global_init_true-unreach-call.expected | 108 ++-- .../cfg/uncil/and3_true-unreach-call.expected | 128 ++--- .../uncil/and3dead_true-unreach-call.expected | 128 ++--- .../uncil/and_copy_true-unreach-call.expected | 132 ++--- ..._join_invariant_true-unreach-call.expected | 152 ++--- .../cfg/uncil/and_true-unreach-call.expected | 104 ++-- .../uncil/and_var_false-unreach-call.expected | 48 +- .../uncil/and_var_true-unreach-call.expected | 48 +- .../cfg/uncil/or3_true-unreach-call.expected | 128 ++--- .../uncil/or3dead_true-unreach-call.expected | 128 ++--- .../cfg/uncil/or_true-unreach-call.expected | 104 ++-- .../eq/eq_double_true-unreach-call.expected | 218 +++---- .../eq/eq_single_true-unreach-call.expected | 86 +-- .../eq/multivar_false-unreach-call1.expected | 108 ++-- .../eq/multivar_true-unreach-call1.expected | 108 ++-- 36 files changed, 2398 insertions(+), 2392 deletions(-) diff --git a/src/witness/argTools.ml b/src/witness/argTools.ml index 2b21659dd5..1fd1e32e4f 100644 --- a/src/witness/argTools.ml +++ b/src/witness/argTools.ml @@ -26,7 +26,13 @@ struct Format.fprintf ppf "\"%s\"" (Arg.Node.to_string node) let dot_edge ppf from_node (edge, to_node) = - Format.fprintf ppf "@,%a -> %a [label=\"%s\"];" dot_node_name from_node dot_node_name to_node (String.escaped (Arg.Edge.to_string edge)) + let label = [Format.sprintf "label=\"%s\"" (String.escaped (Arg.Edge.to_string edge))] in + let style = match edge with + | MyARG.InlinedEdge _ -> ["style=dotted"] + | _ -> [] + in + let styles = String.concat "," (label @ style) in + Format.fprintf ppf "@,%a -> %a [%s];" dot_node_name from_node dot_node_name to_node styles let dot_node ppf node = let shape = match Arg.Node.cfgnode node with diff --git a/tests/sv-comp/basic/for_fun_true-unreach-call.expected b/tests/sv-comp/basic/for_fun_true-unreach-call.expected index d8e29f44e5..5276bf724b 100644 --- a/tests/sv-comp/basic/for_fun_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_fun_true-unreach-call.expected @@ -5,59 +5,59 @@ │ Entry main ▼ ┌────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Entry fun │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Assign 'i = 0' │ - ▼ │ - ┌────────────────────────────────┐ │ ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ Entry fun : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ Assign 'i = 0' : + ▼ : + ┌────────────────────────────────┐ : ┌───────────────────────┐ Ret (None, fun) ┌─────────────────────┐ ┌──────────────────▶ │ _ │ ─┼──────────────────────────────────────────▶ │ _ │ ─────────────────▶ │ _ │ - │ └────────────────────────────────┘ │ └───────────────────────┘ └─────────────────────┘ - │ │ │ Inlined Proc 'fun()' │ - │ │ Test (i < 1000,true) └───────────────────────────────────────────────────────────────────────┐ │ InlineReturn - │ ▼ │ ▼ - │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ _ │ ─┐ └───────────────▶ │ _ │ - │ └────────────────────────────────┘ │ └─────────────────────┘ - │ │ │ │ - │ │ InlineEntry '(i < 2000)' │ │ Ret (Some 0, main) - │ ▼ │ ▼ - │ ┌────────────────────────────────┐ │ ┌─────────────────────┐ - │ │ _ │ │ │ _ │ - │ └────────────────────────────────┘ │ └─────────────────────┘ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ + │ └────────────────────────────────┘ : └───────────────────────┘ └─────────────────────┘ + │ │ : Inlined Proc 'fun()' │ + │ │ Test (i < 1000,true) └·······································································┐ │ InlineReturn + │ ▼ : ▼ + │ ┌────────────────────────────────┐ : ┌─────────────────────┐ + │ │ _ │ ·┐ └···············▶ │ _ │ + │ └────────────────────────────────┘ : └─────────────────────┘ + │ │ : │ + │ │ InlineEntry '(i < 2000)' : │ Ret (Some 0, main) + │ ▼ : ▼ + │ ┌────────────────────────────────┐ : ┌─────────────────────┐ + │ │ _ │ : │ _ │ + │ └────────────────────────────────┘ : └─────────────────────┘ + │ │ : + │ │ Entry __VERIFIER_assert : + │ ▼ : + │ ┌────────────────────────────────┐ : + │ Assign 'i = i + 1' │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(i < 2000)' + │ ▼ : + │ ┌────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ Ret (None, __VERIFIER_assert) : + │ ▼ : + │ ┌────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ InlineReturn : + │ ▼ : + │ ┌────────────────────────────────┐ : └─────────────────── │ _ │ ◀┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected index 73284ddaeb..ac0cf29bc6 100644 --- a/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_odd_vesal_true-unreach-call.expected @@ -8,72 +8,72 @@ │ │ Entry main │ │ ▼ │ │ ┌────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry fun │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Assign 'i = 1' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌───┐ Test (i < 1000,true) ┌────────────────────────────────┐ │ Assign 'i = i + 2' │ + │ │ _ │ ·┐ │ + │ └────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '()' : │ + │ ▼ : │ + │ ┌────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry fun : │ + │ ▼ : │ + │ ┌────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────┘ : │ + │ │ : │ + │ │ Assign 'i = 1' : │ + │ ▼ : │ + │ ┌────────────────────────────────┐ InlineEntry '(i < 2000)' ┌───┐ Test (i < 1000,true) ┌────────────────────────────────┐ : Assign 'i = i + 2' │ │ │ _ │ ◀──────────────────────────────────────────── │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┼───────────────────────────────────────────────┘ - │ └────────────────────────────────┘ └───┘ └────────────────────────────────┘ │ - │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ Test (i < 1000,false) │ - │ ▼ │ ▼ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────┐ │ - │ │ _ │ │ ┌──────────────────────────────────────────── │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ InlineEntry '(i == 1001)' │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ - │ │ _ │ │ │ │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────┐ │ Test (! cond,true) ┌─────────────────────────┐ - │ │ _ │ │ │ │ _ │ ─┼──────────────────────────────────────────────────────────────────▶ │ _ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ │ │ │ │ - │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) │ │ InlineEntry '()' - │ ▼ │ │ ▼ │ ▼ - │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' │ │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ - └─ │ _ │ ◀───────────────────────────────────────────────┘ │ │ _ │ │ │ _ │ - └────────────────────────────────┘ │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_error - │ ▼ │ ▼ - │ ┌────────────────────────────────┐ │ ┌─────────────────────────┐ - │ │ _ │ │ │ _ │ - │ └────────────────────────────────┘ │ └─────────────────────────┘ - │ │ │ - │ │ InlineReturn │ Inlined Proc 'fun()' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, fun) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ + │ └────────────────────────────────┘ └───┘ └────────────────────────────────┘ : + │ │ : │ : + │ │ Entry __VERIFIER_assert : │ Test (i < 1000,false) : + │ ▼ : ▼ : + │ ┌────────────────────────────────┐ : ┌────────────────────────────────┐ : + │ │ _ │ : ┌············································ │ _ │ : + │ └────────────────────────────────┘ : : └────────────────────────────────┘ : + │ │ : : │ : + │ │ Test (! cond,false) : : │ InlineEntry '(i == 1001)' : + │ ▼ : : ▼ : + │ ┌────────────────────────────────┐ : : ┌────────────────────────────────┐ : + │ │ _ │ : : │ _ │ : + │ └────────────────────────────────┘ : : └────────────────────────────────┘ : + │ │ : : │ : + │ │ Ret (None, __VERIFIER_assert) : : │ Entry __VERIFIER_assert : + │ ▼ : : ▼ : + │ ┌────────────────────────────────┐ : : ┌────────────────────────────────┐ : Test (! cond,true) ┌─────────────────────────┐ + │ │ _ │ : : │ _ │ ─┼──────────────────────────────────────────────────────────────────▶ │ _ │ + │ └────────────────────────────────┘ : : └────────────────────────────────┘ : └─────────────────────────┘ + │ │ : : │ : │ + │ │ InlineReturn : : Inlined Proc '__VERIFIER_assert(i == 1001)' │ Test (! cond,false) : │ InlineEntry '()' + │ ▼ : : ▼ : ▼ + │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(i < 2000)' : : ┌────────────────────────────────┐ : ┌─────────────────────────┐ + └─ │ _ │ ◀···············································┘ : │ _ │ : │ _ │ + └────────────────────────────────┘ : └────────────────────────────────┘ : └─────────────────────────┘ + : │ : │ + : │ Ret (None, __VERIFIER_assert) : │ Entry __VERIFIER_error + : ▼ : ▼ + : ┌────────────────────────────────┐ : ┌─────────────────────────┐ + : │ _ │ : │ _ │ + : └────────────────────────────────┘ : └─────────────────────────┘ + : │ : + : │ InlineReturn : Inlined Proc 'fun()' + : ▼ : + : ┌────────────────────────────────┐ : + └···········································▶ │ _ │ : + └────────────────────────────────┘ : + │ : + │ Ret (None, fun) : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────┘ │ diff --git a/tests/sv-comp/basic/for_true-unreach-call.expected b/tests/sv-comp/basic/for_true-unreach-call.expected index 6a711a84d0..6e71e66a54 100644 --- a/tests/sv-comp/basic/for_true-unreach-call.expected +++ b/tests/sv-comp/basic/for_true-unreach-call.expected @@ -17,35 +17,35 @@ │ │ Test (i < 1000,true) │ ▼ │ ┌────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(i < 2000)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ Assign 'i = i + 1' │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(i < 2000)' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ + │ │ _ │ ·┐ + │ └────────────────────────────────┘ : + │ │ : + │ │ InlineEntry '(i < 2000)' : + │ ▼ : + │ ┌────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ Entry __VERIFIER_assert : + │ ▼ : + │ ┌────────────────────────────────┐ : + │ Assign 'i = i + 1' │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(i < 2000)' + │ ▼ : + │ ┌────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ Ret (None, __VERIFIER_assert) : + │ ▼ : + │ ┌────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────┘ : + │ │ : + │ │ InlineReturn : + │ ▼ : + │ ┌────────────────────────────────┐ : └─────────────────── │ _ │ ◀┘ └────────────────────────────────┘ diff --git a/tests/sv-comp/basic/global_init_true-unreach-call.expected b/tests/sv-comp/basic/global_init_true-unreach-call.expected index 7e87b517d4..dc67ece119 100644 --- a/tests/sv-comp/basic/global_init_true-unreach-call.expected +++ b/tests/sv-comp/basic/global_init_true-unreach-call.expected @@ -5,36 +5,36 @@ │ Entry main ▼ ┌────────────────────────────────┐ -│ _ │ ─┐ -└────────────────────────────────┘ │ - │ │ - │ InlineEntry '(g == 1)' │ - ▼ │ -┌────────────────────────────────┐ │ -│ _ │ │ -└────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ -┌────────────────────────────────┐ │ -│ _ │ │ -└────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(g == 1)' - ▼ │ -┌────────────────────────────────┐ │ -│ _ │ │ -└────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ -┌────────────────────────────────┐ │ -│ _ │ │ -└────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ -┌────────────────────────────────┐ │ +│ _ │ ·┐ +└────────────────────────────────┘ : + │ : + │ InlineEntry '(g == 1)' : + ▼ : +┌────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : +┌────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(g == 1)' + ▼ : +┌────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : +┌────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : +┌────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────┘ │ diff --git a/tests/sv-comp/basic/if_mod_false-unreach-call.expected b/tests/sv-comp/basic/if_mod_false-unreach-call.expected index a8d688ee26..5802a2ea7f 100644 --- a/tests/sv-comp/basic/if_mod_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_false-unreach-call.expected @@ -11,30 +11,30 @@ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '()' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_nondet_int │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 50,false) │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn 'tmp' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ + │ │ _ │ ·┐ + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineEntry '()' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Entry __VERIFIER_nondet_int : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ Test (x >= 50,false) │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Ret (Some val, __VERIFIER_nondet_int) : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineReturn 'tmp' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ diff --git a/tests/sv-comp/basic/if_mod_true-unreach-call.expected b/tests/sv-comp/basic/if_mod_true-unreach-call.expected index d130a4c037..e4fbf41a08 100644 --- a/tests/sv-comp/basic/if_mod_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_mod_true-unreach-call.expected @@ -11,30 +11,30 @@ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '()' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_nondet_int │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ Test (x >= 100,false) │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn 'tmp' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ + │ │ _ │ ·┐ + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineEntry '()' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Entry __VERIFIER_nondet_int : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ Test (x >= 100,false) │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Ret (Some val, __VERIFIER_nondet_int) : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineReturn 'tmp' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ diff --git a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected index 8a713183c5..0e61d769de 100644 --- a/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_nondet_fun_false-unreach-call.expected @@ -11,30 +11,30 @@ │ │ Test (1,true) │ ▼ │ ┌────────────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '()' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_nondet_int │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ Test (x,false) │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn 'tmp' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ + │ │ _ │ ·┐ + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineEntry '()' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Entry __VERIFIER_nondet_int : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ Test (x,false) │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Ret (Some val, __VERIFIER_nondet_int) : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineReturn 'tmp' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected index 89b8c8d42c..53bd068d84 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.expected @@ -1,68 +1,68 @@ - ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┐ │ Entry main │ Inlined Proc '__VERIFIER_assert(x != 1)' - │ │ │ ▼ ▼ - │ ┌────────────────────────────────┐ InlineEntry '(x != 1)' ┌──────────────────────┐ │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ _ │ ◀──────────────────────── │ _ │ └────────────────────────────────────────▶ │ │ - │ └────────────────────────────────┘ └──────────────────────┘ │ │ - │ │ ▲ InlineReturn │ │ InlineReturn - │ │ Entry __VERIFIER_assert ┌──────────────────────────┼────────────────────────────────────────────────────────────────▶ │ _ │ ◀─────────────────┐ - │ ▼ │ │ │ │ │ - │ ┌─────────────────────────┐ Test (! cond,true) ┌────────────────────────────────┐ │ │ │ │ │ - │ │ _ │ ◀──────────────────── │ _ │ │ │ ┌────────────────────────────────────────▶ │ │ ◀┐ │ - │ └─────────────────────────┘ └────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ │ - │ │ InlineEntry '()' │ Test (! cond,false) │ │ │ │ Test (1,true) │ │ - │ ▼ ▼ │ │ │ ▼ │ │ - │ ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ _ │ │ │ │ │ _ │ ─┐ │ │ - │ └─────────────────────────┘ └────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ │ │ │ InlineEntry '()' │ │ │ - │ ▼ ▼ │ │ │ ▼ │ │ │ - │ ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ _ │ │ _ │ ─┘ │ │ │ _ │ │ │ │ - │ └─────────────────────────┘ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - └──────────────────────────────────────────────────────┐ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ ▼ │ │ │ - │ │ Test (x == 2,false) │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x == 2)' │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ _ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ │ - │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ _ │ ◀┘ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Assign 'x = tmp' │ │ - │ │ │ ▼ │ │ - ┌────────────────────────────────┐ Test (x == 0,true) │ │ ┌────────────────────────────────────────┐ │ │ + ┌··············································································································┐ + : : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : │ : + ┌···················································································································┼·······················┐ │ Entry main : Inlined Proc '__VERIFIER_assert(x != 1)' + : : : ▼ ▼ + : ┌────────────────────────────────┐ InlineEntry '(x != 1)' ┌──────────────────────┐ : ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + : │ _ │ ◀──────────────────────── │ _ │ └········································▶ │ │ + : └────────────────────────────────┘ └──────────────────────┘ │ │ + : │ ▲ InlineReturn │ │ InlineReturn + : │ Entry __VERIFIER_assert ┌──────────────────────────┼────────────────────────────────────────────────────────────────▶ │ _ │ ◀─────────────────┐ + : ▼ │ │ │ │ │ + : ┌─────────────────────────┐ Test (! cond,true) ┌────────────────────────────────┐ │ │ │ │ │ + : │ _ │ ◀──────────────────── │ _ │ │ │ ┌········································▶ │ │ ◀┐ │ + : └─────────────────────────┘ └────────────────────────────────┘ │ │ : └─────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + : │ │ │ │ : │ │ │ + : │ InlineEntry '()' │ Test (! cond,false) │ │ : │ Test (1,true) │ │ + : ▼ ▼ │ │ : ▼ │ │ + : ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ : ┌────────────────────────────────────────┐ │ │ + : │ _ │ │ _ │ │ │ : │ _ │ ·┐ │ │ + : └─────────────────────────┘ └────────────────────────────────┘ │ │ : └────────────────────────────────────────┘ : │ │ + : │ │ │ │ : │ : │ │ + : │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ │ : │ InlineEntry '()' : │ │ + : ▼ ▼ │ │ : ▼ : │ │ + : ┌─────────────────────────┐ ┌────────────────────────────────┐ │ │ : ┌────────────────────────────────────────┐ : │ │ + : │ _ │ │ _ │ ─┘ │ : │ _ │ : │ │ + : └─────────────────────────┘ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ : │ │ + : │ : │ : │ │ + └······················································┐ │ : │ Entry __VERIFIER_nondet_int : │ │ + : │ : ▼ : │ │ + : │ Test (x == 2,false) : ┌────────────────────────────────────────┐ : │ │ + : │ : Inlined Proc '__VERIFIER_assert(x == 2)' │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + : │ : └────────────────────────────────────────┘ : │ │ + : │ : │ : │ │ + : │ : │ Ret (Some val, __VERIFIER_nondet_int) : │ │ + : │ : ▼ : │ │ + : │ : ┌────────────────────────────────────────┐ : │ │ + : │ : │ _ │ : │ │ + : │ : └────────────────────────────────────────┘ : │ │ + : │ : │ : │ │ + : │ : │ InlineReturn 'tmp' : │ │ + : │ : ▼ : │ │ + : │ : ┌────────────────────────────────────────┐ : │ │ + : │ : │ _ │ ◀┘ │ │ + : │ : └────────────────────────────────────────┘ │ │ + : │ : │ │ │ + : │ : │ Assign 'x = tmp' │ │ + : │ : ▼ │ │ + ┌────────────────────────────────┐ Test (x == 0,true) │ : ┌────────────────────────────────────────┐ │ │ │ _ │ ◀───────────────────────────┼───────────────────────┼───────────────────────────────────────── │ _ │ │ InlineReturn │ - └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Test (x == 0,false) │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ + └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ │ + │ │ : │ │ │ + │ │ : │ Test (x == 0,false) │ │ + │ │ : ▼ │ │ + │ │ : ┌────────────────────────────────────────┐ │ │ │ └───────────────────────┼───────────────────────────────────────── │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Test (x == 2,true) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ └───────────────────────────────────────── │ _ │ │ │ + │ : └────────────────────────────────────────┘ │ │ + │ : │ │ │ + │ : │ Test (x == 2,true) │ │ + │ : ▼ │ │ + │ : ┌────────────────────────────────────────┐ │ │ + │ └········································· │ _ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ InlineEntry '(x == 2)' │ │ diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index 3bcca8a6d5..4a17e9c38c 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -1,89 +1,89 @@ - ┌───────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ + ┌·······················································································┐ + : : + : : ┌─────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ ┌─────────────────────────────────────────────────────────────┘ │ Entry main │ Inlined Proc '__VERIFIER_assert(x == 0)' │ - │ │ ▼ ▼ │ - │ │ InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ - │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀────────────────────────────────────────── │ _ │ - │ │ │ │ │ └─────────────────────┘ - │ │ │ InlineReturn │ │ ▲ - │ │ │ ┌─────────────────────────────────────────────────────────────────────▶ │ _ │ │ Test (x == 2,true) - │ │ │ │ │ │ │ - │ │ │ │ │ │ │ - │ │ │ │ ┌─────────────────────────────────────────▶ │ │ ◀┐ │ - │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Test (1,true) │ InlineReturn │ - │ │ │ │ │ ▼ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ │ │ _ │ ─┐ ┌────┼────────────────────────────────────────────┘ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineEntry '()' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ _ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ InlineEntry '(x == 2)' │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ Inlined Proc '__VERIFIER_assert(tmp___0)' │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ _ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ _ │ ◀┘ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Assign 'x = tmp' │ │ - │ │ │ │ │ ▼ │ │ - │ │ ┌────────────────────────────────┐ │ Test (x == 0,true) │ ┌────────────────────────────────────────┐ │ │ + │ : : │ + │ : ┌────────────────────────────────────────┐ : │ + │ : │ _ │ : │ + │ : └────────────────────────────────────────┘ : │ + │ : │ : │ + │ ┌·····························································┘ │ Entry main : Inlined Proc '__VERIFIER_assert(x == 0)' │ + │ : ▼ ▼ │ + │ : InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ + │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀·········································· │ _ │ + │ │ : │ │ └─────────────────────┘ + │ │ : InlineReturn │ │ ▲ + │ │ : ┌─────────────────────────────────────────────────────────────────────▶ │ _ │ │ Test (x == 2,true) + │ │ : │ │ │ │ + │ │ : │ │ │ │ + │ │ : │ ┌·········································▶ │ │ ◀┐ │ + │ │ : │ : └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ + │ │ : │ : │ │ │ + │ │ : │ : │ Test (1,true) │ InlineReturn │ + │ │ : │ : ▼ │ │ + │ │ : │ : ┌────────────────────────────────────────┐ │ │ + │ │ : │ : │ _ │ ·┐ ┌────┼────────────────────────────────────────────┘ + │ │ : │ : └────────────────────────────────────────┘ : │ │ + │ │ : │ : │ : │ │ + │ │ : │ : │ InlineEntry '()' : │ │ + │ │ : │ : ▼ : │ │ + │ │ : │ : ┌────────────────────────────────────────┐ : │ │ + │ │ : │ : │ _ │ : │ │ + │ │ : │ : └────────────────────────────────────────┘ : │ │ + │ InlineEntry '(x == 2)' │ : │ : │ : │ │ + │ │ : │ : │ Entry __VERIFIER_nondet_int : │ │ + │ │ : │ : ▼ : │ │ + │ │ : │ : ┌────────────────────────────────────────┐ : │ │ + │ │ : │ : Inlined Proc '__VERIFIER_assert(tmp___0)' │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ : │ : └────────────────────────────────────────┘ : │ │ + │ │ : │ : │ : │ │ + │ │ : │ : │ Ret (Some val, __VERIFIER_nondet_int) : │ │ + │ │ : │ : ▼ : │ │ + │ │ : │ : ┌────────────────────────────────────────┐ : │ │ + │ │ : │ : │ _ │ : │ │ + │ │ : │ : └────────────────────────────────────────┘ : │ │ + │ │ : │ : │ : │ │ + │ │ : │ : │ InlineReturn 'tmp' : │ │ + │ │ : │ : ▼ : │ │ + │ │ : │ : ┌────────────────────────────────────────┐ : │ │ + │ │ : │ : │ _ │ ◀┘ │ │ + │ │ : │ : └────────────────────────────────────────┘ │ │ + │ │ : │ : │ │ │ + │ │ : │ : │ Assign 'x = tmp' │ │ + │ │ : │ : ▼ │ │ + │ │ ┌────────────────────────────────┐ │ Test (x == 0,true) : ┌────────────────────────────────────────┐ │ │ │ │ │ _ │ ◀┼───────────────────────────┼────────────────────────────────────────── │ _ │ │ │ - │ │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ InlineEntry '(x == 0)' │ │ │ Test (x == 0,false) │ │ - │ │ ▼ │ │ ▼ │ │ - │ │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - └──────────────────────────┼▶ │ _ │ │ │ │ _ │ ──────────────────────────────────────────────────┘ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ │ Test (x == 2,false) │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ │ │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ Test (x != 0,true) │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ │ │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Test (x != 2,true) │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - └─ │ _ │ ─┘ │ │ _ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'tmp___0 = 1' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - └────────────────────────────────────────── │ _ │ │ + │ │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ │ + │ │ │ │ : │ │ │ + │ │ │ InlineEntry '(x == 0)' │ : │ Test (x == 0,false) │ │ + │ │ ▼ │ : ▼ │ │ + │ │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ │ + └──────────────────────────┼▶ │ _ │ │ : │ _ │ ──────────────────────────────────────────────────┘ │ + │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ + │ │ │ : │ │ + │ │ Entry __VERIFIER_assert │ : │ Test (x == 2,false) │ + │ ▼ │ : ▼ │ + │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ + │ │ _ │ │ : │ _ │ │ + │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ + │ │ │ : │ │ + │ │ Test (! cond,false) │ : │ Test (x != 0,true) │ + │ ▼ │ : ▼ │ + │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ + │ │ _ │ │ : │ _ │ │ + │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ + │ │ │ : │ │ + │ │ Ret (None, __VERIFIER_assert) │ : │ Test (x != 2,true) │ + │ ▼ │ : ▼ │ + │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ + └─ │ _ │ ─┘ : │ _ │ │ + └────────────────────────────────┘ : └────────────────────────────────────────┘ │ + : │ │ + : │ Assign 'tmp___0 = 1' │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + └·········································· │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(tmp___0)' │ diff --git a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected index 08a583459b..cad63798c9 100644 --- a/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_true-unreach-call.expected @@ -1,59 +1,59 @@ - ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry main │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x != 0)' - │ │ ▼ ▼ ▼ - │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ ┌────────────────────────────────────────▶ │ _ │ ◀┐ - │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ Test (1,true) │ - │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ - │ │ │ │ _ │ ─┐ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ _ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ Inlined Proc '__VERIFIER_assert(x == 0)' │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ _ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ - │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ _ │ ◀┘ │ - │ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ Assign 'x = tmp' │ InlineReturn - │ │ │ ▼ │ -┌────────────────────────────────┐ │ Test (x == 0,false) │ ┌────────────────────────────────────────┐ │ + ┌······································································································································································································┐ + : : + : : + : ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : + : │ │ : + : │ ┌────────────────────────────────────────┐ │ : + : │ │ _ │ │ : + : │ └────────────────────────────────────────┘ │ : + : │ │ │ : + : │ │ Entry main │ InlineReturn : Inlined Proc '__VERIFIER_assert(x != 0)' + : │ ▼ ▼ ▼ + : │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + : │ ┌········································▶ │ _ │ ◀┐ + : │ : └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + : │ : │ │ + : │ : │ Test (1,true) │ + : │ : ▼ │ + : │ : ┌────────────────────────────────────────┐ │ + : │ : │ _ │ ·┐ │ + : │ : └────────────────────────────────────────┘ : │ + : │ : │ : │ + : │ : │ InlineEntry '()' : │ + : │ : ▼ : │ + : │ : ┌────────────────────────────────────────┐ : │ + : │ : │ _ │ : │ + : │ : └────────────────────────────────────────┘ : │ + : │ : │ : │ + : │ : │ Entry __VERIFIER_nondet_int : │ + : │ : ▼ : │ + : │ : ┌────────────────────────────────────────┐ : │ + : │ : Inlined Proc '__VERIFIER_assert(x == 0)' │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + : │ : └────────────────────────────────────────┘ : │ + : │ : │ : │ + : │ : │ Ret (Some val, __VERIFIER_nondet_int) : │ + : │ : ▼ : │ + : │ : ┌────────────────────────────────────────┐ : │ + : │ : │ _ │ : │ + : │ : └────────────────────────────────────────┘ : │ + : │ : │ : │ + : │ : │ InlineReturn 'tmp' : │ + : │ : ▼ : │ + : │ : ┌────────────────────────────────────────┐ : │ + : │ : │ _ │ ◀┘ │ + : │ : └────────────────────────────────────────┘ │ + : │ : │ │ + : │ : │ Assign 'x = tmp' │ InlineReturn + : │ : ▼ │ +┌────────────────────────────────┐ │ Test (x == 0,false) : ┌────────────────────────────────────────┐ │ │ _ │ ◀┼────────────────────────────┼───────────────────────────────────────── │ _ │ │ -└────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ InlineEntry '(x != 0)' │ │ │ Test (x == 0,true) │ - ▼ │ │ ▼ │ -┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ -│ _ │ │ └───────────────────────────────────────── │ _ │ │ +└────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ + │ │ : │ │ + │ InlineEntry '(x != 0)' │ : │ Test (x == 0,true) │ + ▼ │ : ▼ │ +┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ +│ _ │ │ └········································· │ _ │ │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ InlineEntry '(x == 0)' │ diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected index 8e9d9e6d42..1588ba179b 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected @@ -11,30 +11,30 @@ │ Assign 'p = (void *)0' ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected index 7291ee1450..9ecc6aef41 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : │ _ │ ◀───────────────── │ _ │ ◀┘ └───┘ └────────────────────────────────────────┘ │ │ @@ -59,36 +59,36 @@ │ Assign 'tmp___0 = 1' ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(tmp___0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected index f491e8b8da..1d7efcacfe 100644 --- a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected +++ b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected @@ -8,114 +8,114 @@ │ │ Entry main │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_nondet_int │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn 'tmp' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ Assign 'i = i + 1' + │ │ _ │ ·┐ │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '()' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_nondet_int : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (Some val, __VERIFIER_nondet_int) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn 'tmp' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ Assign 'i = i + 1' │ │ _ │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ Assign 'n = tmp' │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(n)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry sum │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Assign 'sum___0 = 0' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Assign 'i = 0' │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ │ │ + │ │ _ │ ·┐ │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '(n)' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry sum : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Assign 'sum___0 = 0' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Assign 'i = 0' : │ + │ ▼ : │ + │ ┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ : │ │ │ _ │ ◀──────────────────── │ _ │ ◀┼────────────────────────────────────────────────┘ - │ └─────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) │ - │ ▼ ▼ │ - │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - └─ │ _ │ │ _ │ │ - └─────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some sum___0, sum) │ Inlined Proc 'tmp___0 = sum(n)' - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp___0' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ └─────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ │ : + │ │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) : + │ ▼ ▼ : + │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : + └─ │ _ │ │ _ │ : + └─────────────────────────────────┘ └────────────────────────────────────────┘ : + │ : + │ Ret (Some sum___0, sum) : Inlined Proc 'tmp___0 = sum(n)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp___0' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Assign 's = tmp___0' ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(s >= 0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌─────────────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ │ - │ _ │ ◀──────────────────── │ _ │ │ - └─────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ - │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(s >= 0)' - ▼ ▼ │ - ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ _ │ │ _ │ │ - └─────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ - │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ - ▼ ▼ │ - ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ _ │ │ _ │ │ - └─────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(s >= 0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌─────────────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ : + │ _ │ ◀──────────────────── │ _ │ : + └─────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ InlineEntry '()' │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(s >= 0)' + ▼ ▼ : + ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └─────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) : + ▼ ▼ : + ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └─────────────────────────────────┘ └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected index b15191797f..f0df0ef706 100644 --- a/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_context_join_true-unreach-call.expected @@ -5,97 +5,97 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ - ┌─────────────────────────────────────────────────────────────────────────────────── │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┘ - │ └────────────────────┘ └────────────────────────────────────────┘ - │ │ │ - │ │ InlineEntry '(2)' │ Test (tmp,true) - │ ▼ ▼ - │ ┌────────────────────┐ ┌────────────────────────────────────────┐ - │ │ _ │ │ _ │ ─┐ - │ └────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Entry foo │ InlineEntry '(1)' │ - │ ▼ ▼ │ - │ ┌────────────────────────────────┐ InlineEntry '(x - 1 < x)' ┌────────────────────┐ ┌────────────────────────────────────────┐ │ - │ │ _ │ ◀───────────────────────────────────────────── │ _ │ │ _ │ │ - │ └────────────────────────────────┘ └────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ Entry foo │ - │ ▼ │ ▼ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ ┌──────────────────────────────────────────── │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Test (! cond,false) │ │ │ InlineEntry '(x - 1 < x)' │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ │ │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Entry __VERIFIER_assert │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ │ │ _ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ │ - │ │ InlineReturn │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ - │ ▼ │ │ ▼ │ - │ ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ◀────────────────────────────────────────────────┘ │ │ _ │ │ - │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ Ret (None, foo) │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ ▼ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ │ _ │ │ - │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ │ InlineReturn │ - │ │ │ ▼ │ - │ │ │ ┌────────────────────────────────────────┐ │ - │ │ └───────────────────────────────────────────▶ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Ret (None, foo) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineReturn │ Inlined Proc 'foo(1)' - │ │ ▼ ▼ - │ │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ _ │ - │ └─────────────────────────────────────────────────────────────────────────────────────────┘ - │ │ ▲ - │ │ Ret (Some 0, main) │ Inlined Proc 'foo(2)' - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────┐ Test (tmp,false) ┌────────────────────────────────────────┐ : + ┌··················································································· │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┘ + : └────────────────────┘ └────────────────────────────────────────┘ + : │ │ + : │ InlineEntry '(2)' │ Test (tmp,true) + : ▼ ▼ + : ┌────────────────────┐ ┌────────────────────────────────────────┐ + : │ _ │ │ _ │ ·┐ + : └────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Entry foo │ InlineEntry '(1)' : + : ▼ ▼ : + : ┌────────────────────────────────┐ InlineEntry '(x - 1 < x)' ┌────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ ◀───────────────────────────────────────────── │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────┘ └────────────────────────────────────────┘ : + : │ : │ : + : │ Entry __VERIFIER_assert : │ Entry foo : + : ▼ : ▼ : + : ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : + : │ _ │ : ┌············································ │ _ │ : + : └────────────────────────────────┘ : : └────────────────────────────────────────┘ : + : │ : : │ : + : │ Test (! cond,false) : : │ InlineEntry '(x - 1 < x)' : + : ▼ : : ▼ : + : ┌────────────────────────────────┐ : : ┌────────────────────────────────────────┐ : + : │ _ │ : : │ _ │ : + : └────────────────────────────────┘ : : └────────────────────────────────────────┘ : + : │ : : │ : + : │ Ret (None, __VERIFIER_assert) : : │ Entry __VERIFIER_assert : + : ▼ : : ▼ : + : ┌────────────────────────────────┐ : : ┌────────────────────────────────────────┐ : + : │ _ │ : : │ _ │ : + : └────────────────────────────────┘ : : └────────────────────────────────────────┘ : + : │ : : │ : + : │ InlineReturn : : Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) : + : ▼ : : ▼ : + : ┌────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' : : ┌────────────────────────────────────────┐ : + : │ _ │ ◀················································┘ : │ _ │ : + : └────────────────────────────────┘ : └────────────────────────────────────────┘ : + : │ : │ : + : │ Ret (None, foo) : │ Ret (None, __VERIFIER_assert) : + : ▼ : ▼ : + : ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : + : │ _ │ : │ _ │ : + : └────────────────────────────────┘ : └────────────────────────────────────────┘ : + : │ : │ : + : │ : │ InlineReturn : + : │ : ▼ : + : │ : ┌────────────────────────────────────────┐ : + : │ └···········································▶ │ _ │ : + : │ └────────────────────────────────────────┘ : + : │ │ : + : │ │ Ret (None, foo) : + : │ ▼ : + : │ ┌────────────────────────────────────────┐ : + : │ │ _ │ : + : │ └────────────────────────────────────────┘ : + : │ │ : + : │ │ InlineReturn : Inlined Proc 'foo(1)' + : │ ▼ ▼ + : │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + : └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ _ │ + : └─────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc 'foo(2)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └······································································································································································································┘ diff --git a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected index 2a7118873d..e520689b19 100644 --- a/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_context_true-unreach-call.expected @@ -5,115 +5,115 @@ │ Entry main ▼ ┌────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────┘ │ - │ │ - │ InlineEntry '(1)' │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Entry foo │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────────── │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(x - 1 < x)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────────▶ │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, foo) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────────── │ _ │ ◀┘ - │ └────────────────────────────────┘ - │ │ - │ │ InlineEntry '(2)' - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ Entry foo - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(x - 1 < x)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry __VERIFIER_assert │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ Inlined Proc 'foo(2)' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ ◀┘ - │ └────────────────────────────────┘ - │ │ - │ │ Ret (None, foo) - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ InlineReturn - │ ▼ - │ ┌────────────────────────────────┐ - └───────────────────────────────────────────▶ │ _ │ + │ _ │ ·┐ + └────────────────────────────────┘ : + │ : + │ InlineEntry '(1)' : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ Entry foo : + ▼ : + ┌────────────────────────────────┐ : + ┌············································ │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineEntry '(x - 1 < x)' : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Entry __VERIFIER_assert : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) : Inlined Proc 'foo(1)' + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Ret (None, __VERIFIER_assert) : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌────────────────────────────────┐ : + └···········································▶ │ _ │ : + └────────────────────────────────┘ : + │ : + │ Ret (None, foo) : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────┐ : + ┌············································ │ _ │ ◀┘ + : └────────────────────────────────┘ + : │ + : │ InlineEntry '(2)' + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ + : └────────────────────────────────┘ + : │ + : │ Entry foo + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ ·┐ + : └────────────────────────────────┘ : + : │ : + : │ InlineEntry '(x - 1 < x)' : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Entry __VERIFIER_assert : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : Inlined Proc 'foo(2)' │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x - 1 < x)' + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Ret (None, __VERIFIER_assert) : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ ◀┘ + : └────────────────────────────────┘ + : │ + : │ Ret (None, foo) + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ + : └────────────────────────────────┘ + : │ + : │ InlineReturn + : ▼ + : ┌────────────────────────────────┐ + └···········································▶ │ _ │ └────────────────────────────────┘ │ │ Ret (Some 0, main) diff --git a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected index 66a088602a..de0d379bc7 100644 --- a/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_join_true-unreach-call.expected @@ -5,91 +5,91 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌───┐ Test (tmp,false) ┌────────────────────────────────────────┐ │ - ┌─ │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┘ - │ └───┘ └────────────────────────────────────────┘ - │ │ │ - │ │ │ Test (tmp,true) - │ │ ▼ - │ │ ┌────────────────────────────────────────┐ - │ │ │ _ │ ─┐ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineEntry '(1)' │ - │ │ ▼ │ - │ │ InlineEntry '(1)' ┌────────────────────────────────────────┐ │ - │ └────────────────────────────────────────────────▶ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry foo │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ ┌──────────────────────────────────────────── │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineEntry '(x - 1 < x)' │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) │ Inlined Proc 'foo(1)' - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineReturn │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ └───────────────────────────────────────────▶ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, foo) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ Inlined Proc 'foo(1)' ┌────────────────────────────────────────┐ │ - └─────────────────────────────────────────────────────▶ │ _ │ ◀┘ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌───┐ Test (tmp,false) ┌────────────────────────────────────────┐ : + ┌· │ _ │ ◀───────────────────────────────────────────── │ _ │ ◀┘ + : └───┘ └────────────────────────────────────────┘ + : │ │ + : │ │ Test (tmp,true) + : │ ▼ + : │ ┌────────────────────────────────────────┐ + : │ │ _ │ ·┐ + : │ └────────────────────────────────────────┘ : + : │ │ : + : │ │ InlineEntry '(1)' : + : │ ▼ : + : │ InlineEntry '(1)' ┌────────────────────────────────────────┐ : + : └────────────────────────────────────────────────▶ │ _ │ : + : └────────────────────────────────────────┘ : + : │ : + : │ Entry foo : + : ▼ : + : ┌────────────────────────────────────────┐ : + : ┌············································ │ _ │ : + : : └────────────────────────────────────────┘ : + : : │ : + : : │ InlineEntry '(x - 1 < x)' : + : : ▼ : + : : ┌────────────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────────────┘ : + : : │ : + : : │ Entry __VERIFIER_assert : + : : ▼ : + : : ┌────────────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────────────┘ : + : : │ : + : : Inlined Proc '__VERIFIER_assert(x - 1 < x)' │ Test (! cond,false) : Inlined Proc 'foo(1)' + : : ▼ : + : : ┌────────────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────────────┘ : + : : │ : + : : │ Ret (None, __VERIFIER_assert) : + : : ▼ : + : : ┌────────────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────────────┘ : + : : │ : + : : │ InlineReturn : + : : ▼ : + : : ┌────────────────────────────────────────┐ : + : └···········································▶ │ _ │ : + : └────────────────────────────────────────┘ : + : │ : + : │ Ret (None, foo) : + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : Inlined Proc 'foo(1)' ┌────────────────────────────────────────┐ : + └·····················································▶ │ _ │ ◀┘ └────────────────────────────────────────┘ │ │ Ret (Some 0, main) diff --git a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected index 7b902edb11..7bfaa476b1 100644 --- a/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_nested_join_true-unreach-call.expected @@ -1,194 +1,194 @@ - ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - ┌──────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ┌────┼────────────────────────────────────────────────────────────────┐ │ Inlined Proc 'foo(x, 4)' ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ ▼ ▼ │ │ │ - │ │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ ┌───────────────────────────────────────▶ │ _ │ │ │ _ │ │ │ - │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ ▲ │ │ │ │ - │ │ │ │ │ Ret (None, bar) │ Inlined Proc 'foo(x, 3)' │ │ Entry main │ │ - │ │ │ │ ▼ │ │ ▼ │ │ - │ │ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ InlineReturn │ _ │ ──────────────────────────────────────────────────┼────────────────────────────┘ │ _ │ ─┐ │ │ - │ │ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ └────────────────────────────┐ │ InlineEntry '()' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ └────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ _ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ │ │ _ │ │ │ │ - │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ │ │ │ │ InlineReturn 'tmp' │ │ │ - │ │ │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ InlineEntry '(2)' ┌───────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ _ │ ◀────────────────────────────────────────────── │ _ │ ◀┼────────────────────── │ _ │ ◀┘ │ │ - │ │ │ └────────────────────────────────────────┘ └───────────────────────────┘ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ - │ │ │ │ Entry bar ┌────────────────────────────┘ │ Test (tmp,true) │ │ - │ │ │ ▼ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ _ │ ─┐ │ ┌────────────────────── │ _ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineEntry '()' │ │ │ │ InlineEntry '(1)' │ │ - │ │ │ ▼ │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ _ │ │ │ │ │ _ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ │ Entry bar │ │ - │ │ │ ▼ │ │ │ ▼ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ │ _ │ ─┐ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ │ InlineEntry '()' │ │ │ - │ │ │ ▼ │ │ │ ▼ │ │ │ - │ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ - │ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ - │ │ │ │ InlineReturn 'tmp' │ │ │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ │ ▼ │ │ │ ▼ │ │ │ - ┌────────────────────────────────┐ │ Test (tmp,false) │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ _ │ ◀┼─────────────────────────┼──────────────────────────────────────── │ _ │ ◀┘ │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ - │ InlineEntry '(x, 4)' │ │ │ Test (tmp,true) │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - ▼ │ │ ▼ │ │ ▼ │ │ │ - ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ _ │ │ │ │ _ │ ──────────────────────────────────────────────────┘ │ │ _ │ │ │ │ - └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ - │ Entry foo │ │ │ InlineEntry '(x, 3)' │ │ InlineReturn 'tmp' │ │ │ - ▼ │ │ ▼ │ ▼ │ │ │ - ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ │ - ┌──────────────────────────────────────── │ _ │ │ │ │ _ │ ┌────────────────────────────┼────────────────────── │ _ │ ◀┘ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ │ │ │ │ │ - │ │ InlineEntry '(x < y)' │ │ │ Entry foo │ │ │ Test (tmp,true) │ │ - │ ▼ │ │ ▼ │ │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ │ _ │ ─┐ │ │ │ _ │ ─┐ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ │ InlineEntry '(x < y)' │ │ │ │ InlineEntry '(x, 3)' │ │ │ - │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ _ │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ - │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ │ Entry __VERIFIER_assert │ │ │ │ Entry foo │ │ │ - │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ _ │ │ │ │ _ │ │ │ │ │ _ │ ─┼────────────────────────────────────────────────┐ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ │ InlineEntry '(x < y)' │ │ │ │ - │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ _ │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ │ - │ └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ │ - │ │ InlineReturn │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ Entry __VERIFIER_assert │ │ │ │ - │ ▼ │ │ ▼ │ │ │ ▼ │ │ │ │ - │ ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - └───────────────────────────────────────▶ │ _ │ │ │ │ _ │ │ │ │ │ _ │ │ │ │ │ - └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ │ │ │ - │ Ret (None, foo) │ │ │ InlineReturn │ │ │ │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ │ - ▼ │ │ ▼ │ │ │ ▼ │ │ │ │ - ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ _ │ ─┘ │ │ _ │ ◀┘ │ │ │ _ │ │ │ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ │ │ - │ │ Ret (None, foo) │ │ │ Ret (None, __VERIFIER_assert) │ │ │ │ - │ ▼ │ │ ▼ │ │ │ │ - │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ │ - └──────────────────────────────────────── │ _ │ │ │ │ _ │ │ │ │ │ - └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ │ - │ │ │ │ │ │ │ - │ │ │ InlineReturn │ │ │ │ - │ │ ▼ │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ │ - │ │ │ _ │ ◀┼────────────────────────────────────────────────┘ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ │ Ret (None, foo) │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ _ │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - Test (tmp,false) │ │ │ │ │ │ - ┌──────────────────────────────────────────────────────────────────────────────────────────┘ │ │ InlineReturn │ Inlined Proc 'foo(x, 3)' │ │ - ▼ │ ▼ ▼ │ │ - ┌────────────────────────────────────────┐ InlineReturn │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ - ┌───────────────────────────────────────────────────────────── │ _ │ ┌─────────────────────────────────────────────────────────────────────────────┼─────────────────────▶ │ _ │ ◀┼─────────────────────────┐ │ - │ └────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ │ - │ │ InlineEntry '(x, 4)' │ │ │ Ret (None, bar) │ │ │ - │ ▼ │ │ ▼ │ │ │ - │ ┌────────────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ _ │ │ │ Inlined Proc 'bar(1)' │ _ │ │ InlineReturn │ │ - │ └────────────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ │ Inlined Proc 'foo(x, 4)' │ - │ │ Entry foo │ │ │ InlineReturn │ │ │ - │ ▼ │ │ ▼ │ │ │ - │ ┌────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ - │ ┌──────────────────────────────────────── │ _ │ │ └─────────────────────▶ │ _ │ ◀┘ │ │ - │ │ └────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ - │ │ │ │ │ ▲ Inlined Proc 'bar(2)' │ │ - │ │ │ InlineEntry '(x < y)' │ │ Ret (Some 0, main) └─────────────────────────────────────────────────────────────────────┼────────────────────────────┘ - │ │ ▼ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineReturn │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ └───────────────────────────────────────▶ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, foo) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ ─┘ │ - │ └────────────────────────────────────────┘ │ - │ │ - └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + ┌················································································································································································································································································································································································································┐ + : : + : : + ┌······································┼··········································································································┐ : + : : : : + : : InlineReturn : : + : ┌────┼────────────────────────────────────────────────────────────────┐ : Inlined Proc 'foo(x, 4)' ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : + : │ : ▼ ▼ │ │ : + : │ : ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ : + : │ : ┌───────────────────────────────────────▶ │ _ │ │ │ _ │ │ : + : │ : │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────────┘ │ : + : │ : │ │ ▲ │ │ │ : + : │ : │ │ Ret (None, bar) : Inlined Proc 'foo(x, 3)' │ │ Entry main │ : + : │ : │ ▼ : │ ▼ │ : + : │ : │ ┌────────────────────────────────────────┐ : │ ┌────────────────────────────────────────┐ │ : + : │ : │ InlineReturn │ _ │ ──────────────────────────────────────────────────┼────────────────────────────┘ │ _ │ ·┐ │ : + : │ : │ └────────────────────────────────────────┘ : └────────────────────────────────────────┘ : │ : + : │ : │ : │ : │ : + : │ : │ └····························┐ │ InlineEntry '()' : │ : + : │ : │ : ▼ : │ : + : │ : │ : ┌────────────────────────────────────────┐ : │ : + : │ └····················┼······································································································································┐ : │ _ │ : │ : + : │ │ : : └────────────────────────────────────────┘ : │ : + : │ │ : : │ : │ : + : │ │ : : │ Entry __VERIFIER_nondet_int : │ : + : │ │ : : ▼ : │ : + : │ │ : : ┌────────────────────────────────────────┐ : │ : + : │ │ : : │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ : + : │ │ : : └────────────────────────────────────────┘ : │ : + : │ │ : : │ : │ : + : │ │ : : │ Ret (Some val, __VERIFIER_nondet_int) : │ : + : │ │ : : ▼ : │ : + : │ │ : : ┌────────────────────────────────────────┐ : │ : + : │ │ : : │ _ │ : │ : + : │ │ : : └────────────────────────────────────────┘ : │ : + : │ │ : : │ : │ : + : │ │ : : │ InlineReturn 'tmp' : │ : + : │ │ : : ▼ : │ : + : │ │ ┌────────────────────────────────────────┐ InlineEntry '(2)' ┌───────────────────────────┐ : ┌────────────────────────────────────────┐ : │ : + : │ │ │ _ │ ◀────────────────────────────────────────────── │ _ │ ◀┼────────────────────── │ _ │ ◀┘ │ : + : │ │ └────────────────────────────────────────┘ └───────────────────────────┘ : └────────────────────────────────────────┘ │ : + : │ │ │ : │ │ : + : │ │ │ Entry bar ┌····························┘ │ Test (tmp,true) │ : + : │ │ ▼ : ▼ │ : + : │ │ ┌────────────────────────────────────────┐ : ┌────────────────────────────────────────┐ │ : + : │ │ │ _ │ ·┐ : ┌······················ │ _ │ │ : + : │ │ └────────────────────────────────────────┘ : : : └────────────────────────────────────────┘ │ : + : │ │ │ : : : │ │ : + : │ │ │ InlineEntry '()' : : : │ InlineEntry '(1)' │ : + : │ │ ▼ : : : ▼ │ : + : │ │ ┌────────────────────────────────────────┐ : : : ┌────────────────────────────────────────┐ │ : + : │ │ │ _ │ : : : │ _ │ │ : + : │ │ └────────────────────────────────────────┘ : : : └────────────────────────────────────────┘ │ : + : │ │ │ : : : │ │ : + : │ │ │ Entry __VERIFIER_nondet_int : : : │ Entry bar │ : + : │ │ ▼ : : : ▼ │ : + : │ │ ┌────────────────────────────────────────┐ : : : ┌────────────────────────────────────────┐ │ : + : │ │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' : : │ _ │ ·┐ │ : + : │ │ └────────────────────────────────────────┘ : : : └────────────────────────────────────────┘ : │ : + : │ │ │ : : : │ : │ : + : │ │ │ Ret (Some val, __VERIFIER_nondet_int) : : : │ InlineEntry '()' : │ : + : │ │ ▼ : : : ▼ : │ : + : │ │ ┌────────────────────────────────────────┐ : : : ┌────────────────────────────────────────┐ : │ : + : │ │ │ _ │ : : : │ _ │ : │ : + : │ │ └────────────────────────────────────────┘ : : : └────────────────────────────────────────┘ : │ : + : │ │ │ : : : │ : │ : + : │ │ │ InlineReturn 'tmp' : : : │ Entry __VERIFIER_nondet_int : │ : + : │ │ ▼ : : : ▼ : │ : + ┌────────────────────────────────┐ │ Test (tmp,false) │ ┌────────────────────────────────────────┐ : : : ┌────────────────────────────────────────┐ : │ : + │ _ │ ◀┼─────────────────────────┼──────────────────────────────────────── │ _ │ ◀┘ : : │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ : + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : : └────────────────────────────────────────┘ : │ : + │ │ │ │ : : │ : │ : + │ InlineEntry '(x, 4)' │ │ │ Test (tmp,true) : : │ Ret (Some val, __VERIFIER_nondet_int) : │ : + ▼ │ │ ▼ : : ▼ : │ : + ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : : ┌────────────────────────────────────────┐ : │ : + │ _ │ │ │ │ _ │ ··················································┘ : │ _ │ : │ : + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : └────────────────────────────────────────┘ : │ : + │ │ │ │ : │ : │ : + │ Entry foo │ │ │ InlineEntry '(x, 3)' : │ InlineReturn 'tmp' : │ : + ▼ │ │ ▼ : ▼ : │ : + ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : ┌────────────────────────────────────────┐ : │ : + ┌········································ │ _ │ │ │ │ _ │ ┌────────────────────────────┼────────────────────── │ _ │ ◀┘ │ : + : └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ : + : │ │ │ │ │ : │ │ : + : │ InlineEntry '(x < y)' │ │ │ Entry foo │ : │ Test (tmp,true) │ : + : ▼ │ │ ▼ │ : ▼ │ : + : ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ : + : │ _ │ │ │ │ _ │ ·┐ │ : │ _ │ ·┐ │ : + : └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : │ : └────────────────────────────────────────┘ : │ : + : │ │ │ │ : │ : │ : │ : + : │ Entry __VERIFIER_assert │ │ │ InlineEntry '(x < y)' : │ : │ InlineEntry '(x, 3)' : │ : + : ▼ │ │ ▼ : │ : ▼ : │ : + : ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : │ : ┌────────────────────────────────────────┐ : │ : + : │ _ │ │ │ │ _ │ : │ : │ _ │ : │ : + : └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : │ : └────────────────────────────────────────┘ : │ : + : │ │ │ │ : │ : │ : │ : + : Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ │ Entry __VERIFIER_assert : │ : │ Entry foo : │ : + : ▼ │ │ ▼ : │ : ▼ : │ : + : ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : │ : ┌────────────────────────────────────────┐ : │ : + : │ _ │ │ │ │ _ │ : │ : │ _ │ ·┼················································┐ │ : + : └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : │ : └────────────────────────────────────────┘ : : │ : + : │ │ │ │ : │ : │ : : │ : + : │ Ret (None, __VERIFIER_assert) │ │ │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x < y)' │ : │ InlineEntry '(x < y)' : : │ : + : ▼ │ │ ▼ : │ : ▼ : : │ : + : ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : │ : ┌────────────────────────────────────────┐ : : │ : + : │ _ │ │ │ │ _ │ : │ : │ _ │ : : │ : + : └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : │ : └────────────────────────────────────────┘ : : │ : + : │ │ │ │ : │ : │ : : │ : + : │ InlineReturn │ │ │ Ret (None, __VERIFIER_assert) : │ : │ Entry __VERIFIER_assert : : │ : + : ▼ │ │ ▼ : │ : ▼ : : │ : + : ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : │ : ┌────────────────────────────────────────┐ : : │ : + └·······································▶ │ _ │ │ │ │ _ │ : │ : │ _ │ : : │ : + └────────────────────────────────┘ │ │ └────────────────────────────────────────┘ : │ : └────────────────────────────────────────┘ : : │ : + │ │ │ │ : │ : │ : : │ : + │ Ret (None, foo) │ │ │ InlineReturn : │ : │ Test (! cond,false) : : Inlined Proc '__VERIFIER_assert(x < y)' │ : + ▼ │ │ ▼ : │ : ▼ : : │ : + ┌────────────────────────────────┐ │ │ ┌────────────────────────────────────────┐ : │ : ┌────────────────────────────────────────┐ : : │ : + │ _ │ ─┘ │ │ _ │ ◀┘ │ : │ _ │ : : │ : + └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ : └────────────────────────────────────────┘ : : │ : + │ │ │ : │ : : │ : + │ │ Ret (None, foo) │ : │ Ret (None, __VERIFIER_assert) : : │ : + │ ▼ │ : ▼ : : │ : + │ ┌────────────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ : : │ : + └──────────────────────────────────────── │ _ │ │ : │ _ │ : : │ : + └────────────────────────────────────────┘ │ : └────────────────────────────────────────┘ : : │ : + │ : │ : : │ : + │ : │ InlineReturn : : │ : + │ : ▼ : : │ : + │ : ┌────────────────────────────────────────┐ : : │ : + │ : │ _ │ ◀┼················································┘ │ : + │ : └────────────────────────────────────────┘ : │ : + │ : │ : │ : + │ : │ Ret (None, foo) : │ : + │ : ▼ : │ : + │ : ┌────────────────────────────────────────┐ : │ : + │ : │ _ │ : │ : + │ : └────────────────────────────────────────┘ : │ : + Test (tmp,false) │ : │ : │ : + ┌──────────────────────────────────────────────────────────────────────────────────────────┘ : │ InlineReturn : Inlined Proc 'foo(x, 3)' │ : + ▼ : ▼ ▼ │ : + ┌────────────────────────────────────────┐ InlineReturn : ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ : + ┌····························································· │ _ │ ┌─────────────────────────────────────────────────────────────────────────────┼─────────────────────▶ │ _ │ ◀┼·························┐ : + : └────────────────────────────────────────┘ │ : └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ : : + : │ │ : │ │ : : + : │ InlineEntry '(x, 4)' │ : │ Ret (None, bar) │ : : + : ▼ │ : ▼ │ : : + : ┌────────────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ : : + : │ _ │ │ : Inlined Proc 'bar(1)' │ _ │ │ InlineReturn : : + : └────────────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ : : + : │ │ : │ │ : Inlined Proc 'foo(x, 4)' : + : │ Entry foo │ : │ InlineReturn │ : : + : ▼ │ : ▼ │ : : + : ┌────────────────────────────────────────┐ │ : ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ : : + : ┌········································ │ _ │ │ └·····················▶ │ _ │ ◀┘ : : + : : └────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ : : + : : │ │ │ ▲ Inlined Proc 'bar(2)' : : + : : │ InlineEntry '(x < y)' │ │ Ret (Some 0, main) └·····································································┼····························┘ + : : ▼ │ ▼ : + : : ┌────────────────────────────────────────┐ │ ┌────────────────────────────────────────┐ : + : : │ _ │ │ │ _ │ : + : : └────────────────────────────────────────┘ │ └────────────────────────────────────────┘ : + : : │ │ : + : : │ Entry __VERIFIER_assert │ : + : : ▼ │ : + : : ┌────────────────────────────────────────┐ │ : + : : │ _ │ │ : + : : └────────────────────────────────────────┘ │ : + : : │ │ : + : : Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ : + : : ▼ │ : + : : ┌────────────────────────────────────────┐ │ : + : : │ _ │ │ : + : : └────────────────────────────────────────┘ │ : + : : │ │ : + : : │ Ret (None, __VERIFIER_assert) │ : + : : ▼ │ : + : : ┌────────────────────────────────────────┐ │ : + : : │ _ │ │ : + : : └────────────────────────────────────────┘ │ : + : : │ │ : + : : │ InlineReturn │ : + : : ▼ │ : + : : ┌────────────────────────────────────────┐ │ : + : └·······································▶ │ _ │ │ : + : └────────────────────────────────────────┘ │ : + : │ │ : + : │ Ret (None, foo) │ : + : ▼ │ : + : ┌────────────────────────────────────────┐ │ : + : │ _ │ ─┘ : + : └────────────────────────────────────────┘ : + : : + └···················································································································································································································································································································································································┘ diff --git a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected index 1357a744c9..0aa2c0679e 100644 --- a/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_nested_true-unreach-call.expected @@ -5,271 +5,271 @@ │ Entry main ▼ ┌────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────┘ │ - │ │ - │ InlineEntry '(1)' │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Entry bar │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────── │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(x, 3)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry foo │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ ─┼───────────────────────────────────────────┐ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x < y)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ Inlined Proc 'foo(x, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ ◀┼───────────────────────────────────────────┘ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, foo) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └───────────────────────────────────────▶ │ _ │ ─┼───────────────────────────────────────────┐ - └────────────────────────────────┘ │ │ - │ │ │ - │ InlineEntry '(x, 4)' │ │ - ▼ │ │ - ┌────────────────────────────────┐ │ │ - │ _ │ │ │ - └────────────────────────────────┘ │ │ - │ │ │ - │ Entry foo │ │ - ▼ │ │ - ┌────────────────────────────────┐ │ │ - ┌──────────────────────────────────────── │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x < y)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) │ │ Inlined Proc 'foo(x, 4)' - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - └───────────────────────────────────────▶ │ _ │ │ │ - └────────────────────────────────┘ │ │ - │ │ │ - │ Ret (None, foo) │ │ - ▼ │ │ - ┌────────────────────────────────┐ │ │ - │ _ │ │ │ - └────────────────────────────────┘ │ │ - │ │ │ - │ InlineReturn │ │ - ▼ │ │ - ┌────────────────────────────────┐ │ │ - │ _ │ ◀┼───────────────────────────────────────────┘ - └────────────────────────────────┘ │ - │ │ - │ Ret (None, bar) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'bar(1)' - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌──────────────────────────────────────── │ _ │ ◀┘ - │ └────────────────────────────────┘ - │ │ - │ │ InlineEntry '(2)' - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ Entry bar - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(x, 3)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry foo │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ ─┼───────────────────────────────────────────┐ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x < y)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ ◀┼───────────────────────────────────────────┘ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, foo) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ Inlined Proc 'foo(x, 3)' - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - ┌────────────────────────────┼──────────────────────────────────────── │ _ │ ◀┘ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ │ InlineEntry '(x, 4)' - │ │ ▼ - │ │ ┌────────────────────────────────┐ - │ │ │ _ │ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ │ Entry foo - │ │ ▼ - │ │ ┌────────────────────────────────┐ - │ │ │ _ │ ─┐ - │ │ └────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineEntry '(x < y)' │ - │ │ ▼ │ - │ │ ┌────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ - │ │ ▼ │ - │ │ ┌────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────┘ │ - │ │ │ │ - │ Inlined Proc 'foo(x, 4)' │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' - │ │ ▼ │ - │ │ ┌────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineReturn │ - │ │ ▼ │ - │ │ ┌────────────────────────────────┐ │ - │ │ │ _ │ ◀┘ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ │ Ret (None, foo) - │ │ ▼ - │ │ ┌────────────────────────────────┐ - │ │ │ _ │ - │ │ └────────────────────────────────┘ - │ │ │ - │ │ │ InlineReturn - │ │ ▼ - │ │ ┌────────────────────────────────┐ - └────────────────────────────┼───────────────────────────────────────▶ │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ Ret (None, bar) - │ ▼ - │ ┌────────────────────────────────┐ - │ Inlined Proc 'bar(2)' │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ InlineReturn - │ ▼ - │ ┌────────────────────────────────┐ - └───────────────────────────────────────▶ │ _ │ + │ _ │ ·┐ + └────────────────────────────────┘ : + │ : + │ InlineEntry '(1)' : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ Entry bar : + ▼ : + ┌────────────────────────────────┐ : + ┌········································ │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineEntry '(x, 3)' : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Entry foo : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ ·┼···········································┐ + : └────────────────────────────────┘ : : + : │ : : + : │ InlineEntry '(x < y)' : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Entry __VERIFIER_assert : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : Inlined Proc 'foo(x, 3)' │ Test (! cond,false) : : Inlined Proc '__VERIFIER_assert(x < y)' + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Ret (None, __VERIFIER_assert) : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ InlineReturn : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ ◀┼···········································┘ + : └────────────────────────────────┘ : + : │ : + : │ Ret (None, foo) : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌────────────────────────────────┐ : + └·······································▶ │ _ │ ·┼···········································┐ + └────────────────────────────────┘ : : + │ : : + │ InlineEntry '(x, 4)' : : + ▼ : : + ┌────────────────────────────────┐ : : + │ _ │ : : + └────────────────────────────────┘ : : + │ : : + │ Entry foo : : + ▼ : : + ┌────────────────────────────────┐ : : + ┌········································ │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ InlineEntry '(x < y)' : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Entry __VERIFIER_assert : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : Inlined Proc '__VERIFIER_assert(x < y)' │ Test (! cond,false) : : Inlined Proc 'foo(x, 4)' + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Ret (None, __VERIFIER_assert) : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ InlineReturn : : + : ▼ : : + : ┌────────────────────────────────┐ : : + └·······································▶ │ _ │ : : + └────────────────────────────────┘ : : + │ : : + │ Ret (None, foo) : : + ▼ : : + ┌────────────────────────────────┐ : : + │ _ │ : : + └────────────────────────────────┘ : : + │ : : + │ InlineReturn : : + ▼ : : + ┌────────────────────────────────┐ : : + │ _ │ ◀┼···········································┘ + └────────────────────────────────┘ : + │ : + │ Ret (None, bar) : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : Inlined Proc 'bar(1)' + └────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────┐ : + ┌········································ │ _ │ ◀┘ + : └────────────────────────────────┘ + : │ + : │ InlineEntry '(2)' + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ + : └────────────────────────────────┘ + : │ + : │ Entry bar + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ ·┐ + : └────────────────────────────────┘ : + : │ : + : │ InlineEntry '(x, 3)' : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Entry foo : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ ·┼···········································┐ + : └────────────────────────────────┘ : : + : │ : : + : │ InlineEntry '(x < y)' : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Entry __VERIFIER_assert : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Test (! cond,false) : : Inlined Proc '__VERIFIER_assert(x < y)' + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Ret (None, __VERIFIER_assert) : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ InlineReturn : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ ◀┼···········································┘ + : └────────────────────────────────┘ : + : │ : + : │ Ret (None, foo) : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : Inlined Proc 'foo(x, 3)' + : └────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌────────────────────────────────┐ : + ┌····························┼········································ │ _ │ ◀┘ + : : └────────────────────────────────┘ + : : │ + : : │ InlineEntry '(x, 4)' + : : ▼ + : : ┌────────────────────────────────┐ + : : │ _ │ + : : └────────────────────────────────┘ + : : │ + : : │ Entry foo + : : ▼ + : : ┌────────────────────────────────┐ + : : │ _ │ ·┐ + : : └────────────────────────────────┘ : + : : │ : + : : │ InlineEntry '(x < y)' : + : : ▼ : + : : ┌────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────┘ : + : : │ : + : : │ Entry __VERIFIER_assert : + : : ▼ : + : : ┌────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────┘ : + : : │ : + : Inlined Proc 'foo(x, 4)' : │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x < y)' + : : ▼ : + : : ┌────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────┘ : + : : │ : + : : │ Ret (None, __VERIFIER_assert) : + : : ▼ : + : : ┌────────────────────────────────┐ : + : : │ _ │ : + : : └────────────────────────────────┘ : + : : │ : + : : │ InlineReturn : + : : ▼ : + : : ┌────────────────────────────────┐ : + : : │ _ │ ◀┘ + : : └────────────────────────────────┘ + : : │ + : : │ Ret (None, foo) + : : ▼ + : : ┌────────────────────────────────┐ + : : │ _ │ + : : └────────────────────────────────┘ + : : │ + : : │ InlineReturn + : : ▼ + : : ┌────────────────────────────────┐ + └····························┼·······································▶ │ _ │ + : └────────────────────────────────┘ + : │ + : │ Ret (None, bar) + : ▼ + : ┌────────────────────────────────┐ + : Inlined Proc 'bar(2)' │ _ │ + : └────────────────────────────────┘ + : │ + : │ InlineReturn + : ▼ + : ┌────────────────────────────────┐ + └·······································▶ │ _ │ └────────────────────────────────┘ │ │ Ret (Some 0, main) diff --git a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected index 183936016b..cd3c9cf767 100644 --- a/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_return_context_true-unreach-call.expected @@ -5,163 +5,163 @@ │ Entry main ▼ ┌────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────┘ │ - │ │ - │ InlineEntry '(1)' │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ Entry bar │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌───────────────────────── │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(1, 3)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry foo │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────┐ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x < y)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ Inlined Proc 'foo(1, 3)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ ◀┼────────────────────────────┘ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, foo) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - └────────────────────────▶ │ _ │ │ Inlined Proc 'bar(1)' - └────────────────────────────────┘ │ - │ │ - │ Ret (None, bar) │ - ▼ │ - ┌────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────┐ │ - ┌───────────────────────── │ _ │ ◀┘ - │ └────────────────────────────────┘ - │ │ - │ │ InlineEntry '(2)' - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ Entry bar - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ ─┐ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineEntry '(1, 3)' │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Entry foo │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────┐ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x < y)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ Inlined Proc 'bar(2)' │ Test (! cond,false) │ │ Inlined Proc '__VERIFIER_assert(x < y)' - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ▼ │ │ - │ ┌────────────────────────────────┐ │ │ - │ │ _ │ ◀┼────────────────────────────┘ - │ └────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, foo) │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ │ Inlined Proc 'foo(1, 3)' - │ └────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────┐ │ - │ │ _ │ ◀┘ - │ └────────────────────────────────┘ - │ │ - │ │ Ret (None, bar) - │ ▼ - │ ┌────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────┘ - │ │ - │ │ InlineReturn - │ ▼ - │ ┌────────────────────────────────┐ - └────────────────────────▶ │ _ │ + │ _ │ ·┐ + └────────────────────────────────┘ : + │ : + │ InlineEntry '(1)' : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ Entry bar : + ▼ : + ┌────────────────────────────────┐ : + ┌························· │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineEntry '(1, 3)' : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Entry foo : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ ·┼····························┐ + : └────────────────────────────────┘ : : + : │ : : + : │ InlineEntry '(x < y)' : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Entry __VERIFIER_assert : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : Inlined Proc 'foo(1, 3)' │ Test (! cond,false) : : Inlined Proc '__VERIFIER_assert(x < y)' + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Ret (None, __VERIFIER_assert) : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ InlineReturn : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ ◀┼····························┘ + : └────────────────────────────────┘ : + : │ : + : │ Ret (None, foo) : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌────────────────────────────────┐ : + └························▶ │ _ │ : Inlined Proc 'bar(1)' + └────────────────────────────────┘ : + │ : + │ Ret (None, bar) : + ▼ : + ┌────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────┐ : + ┌························· │ _ │ ◀┘ + : └────────────────────────────────┘ + : │ + : │ InlineEntry '(2)' + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ + : └────────────────────────────────┘ + : │ + : │ Entry bar + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ ·┐ + : └────────────────────────────────┘ : + : │ : + : │ InlineEntry '(1, 3)' : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────┘ : + : │ : + : │ Entry foo : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ ·┼····························┐ + : └────────────────────────────────┘ : : + : │ : : + : │ InlineEntry '(x < y)' : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Entry __VERIFIER_assert : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : Inlined Proc 'bar(2)' │ Test (! cond,false) : : Inlined Proc '__VERIFIER_assert(x < y)' + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ Ret (None, __VERIFIER_assert) : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ : : + : └────────────────────────────────┘ : : + : │ : : + : │ InlineReturn : : + : ▼ : : + : ┌────────────────────────────────┐ : : + : │ _ │ ◀┼····························┘ + : └────────────────────────────────┘ : + : │ : + : │ Ret (None, foo) : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ : Inlined Proc 'foo(1, 3)' + : └────────────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌────────────────────────────────┐ : + : │ _ │ ◀┘ + : └────────────────────────────────┘ + : │ + : │ Ret (None, bar) + : ▼ + : ┌────────────────────────────────┐ + : │ _ │ + : └────────────────────────────────┘ + : │ + : │ InlineReturn + : ▼ + : ┌────────────────────────────────┐ + └························▶ │ _ │ └────────────────────────────────┘ │ │ Ret (Some 0, main) diff --git a/tests/sv-comp/cfg/multicall_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_true-unreach-call.expected index ecdff7eb2c..c5e54da634 100644 --- a/tests/sv-comp/cfg/multicall_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_true-unreach-call.expected @@ -8,7 +8,7 @@ │ InlineReturn │ Entry main │ ▼ ▼ │ ┌─────────────────────┐ Inlined Proc 'foo(1)' ┌────────────────────────────┐ │ - │ _ │ ◀─────────────────────────────── │ _ │ │ + │ _ │ ◀······························· │ _ │ │ └─────────────────────┘ └────────────────────────────┘ │ │ │ │ └──────────────────────┐ │ InlineEntry '(1)' │ @@ -20,7 +20,7 @@ │ InlineReturn │ Ret (Some 0, main) │ Entry foo │ │ ▼ ▼ │ │ ┌─────────────────────┐ ┌────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x - 1 < x)' ┌───┐ Ret (None, foo) ┌───┐ - │ │ _ │ │ _ │ ─────────────────────────────────────────────▶ │ _ │ ─────────────────▶ │ _ │ + │ │ _ │ │ _ │ ·············································▶ │ _ │ ─────────────────▶ │ _ │ │ └─────────────────────┘ └────────────────────────────┘ └───┘ └───┘ │ │ ▲ │ │ │ InlineEntry '(x - 1 < x)' │ │ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected index 7291ee1450..9ecc6aef41 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : │ _ │ ◀───────────────── │ _ │ ◀┘ └───┘ └────────────────────────────────────────┘ │ │ @@ -59,36 +59,36 @@ │ Assign 'tmp___0 = 1' ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(tmp___0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected index 4e1d43bfbb..15955ccdc5 100644 --- a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ @@ -53,43 +53,43 @@ │ │ Test (x < 2,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼─────────────────── │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineEntry '(x == 1)' │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Test (x < 3,false) │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x < 2,false) - │ │ ▼ ▼ ▼ - │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └──────────────────▶ │ _ │ - │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ │ ▲ - │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ - └─────────────────────────────────────────────────────────────────────┘ + ┌····┼··················· │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineEntry '(x == 1)' │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Entry __VERIFIER_assert │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ Test (x < 3,false) │ Test (! cond,false) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Ret (None, __VERIFIER_assert) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineReturn │ Test (x > 0,false) │ Test (x < 2,false) + : │ ▼ ▼ ▼ + : │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + : └──────────────────▶ │ _ │ + : └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └·····································································┘ diff --git a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected index b87f165727..c11ffee6b7 100644 --- a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ @@ -53,43 +53,43 @@ │ │ Test (x == 1,true) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼─────────────────── │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineEntry '(x == 1)' │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Test (x < 3,false) │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineReturn │ Test (x > 0,false) │ Test (x == 1,false) - │ │ ▼ ▼ ▼ - │ │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └──────────────────▶ │ _ │ - │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ │ ▲ - │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ - └─────────────────────────────────────────────────────────────────────┘ + ┌····┼··················· │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineEntry '(x == 1)' │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Entry __VERIFIER_assert │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ Test (x < 3,false) │ Test (! cond,false) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Ret (None, __VERIFIER_assert) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineReturn │ Test (x > 0,false) │ Test (x == 1,false) + : │ ▼ ▼ ▼ + : │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + : └──────────────────▶ │ _ │ + : └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └·····································································┘ diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected index 82dd1351b7..6b2faf9b64 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected @@ -11,78 +11,78 @@ │ │ │ Entry main │ │ │ │ ▼ │ │ │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ ─┐ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ │ InlineEntry '()' │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ _ │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ Test (x < 2,false) │ │ Entry __VERIFIER_nondet_int │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ - │ │ │ _ │ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ │ - │ │ │ │ │ │ - │ │ │ InlineReturn 'tmp' │ │ │ - │ │ ▼ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ │ + │ │ │ _ │ ·┐ │ │ + │ │ └────────────────────────────────────────┘ : │ │ + │ │ │ : │ │ + │ │ │ InlineEntry '()' : │ │ + │ │ ▼ : │ │ + │ │ ┌────────────────────────────────────────┐ : │ │ + │ │ │ _ │ : │ │ + │ │ └────────────────────────────────────────┘ : │ │ + │ │ │ : │ │ + │ Test (x < 2,false) │ │ Entry __VERIFIER_nondet_int : │ │ + │ │ ▼ : │ │ + │ │ ┌────────────────────────────────────────┐ : │ │ + │ │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ + │ │ └────────────────────────────────────────┘ : │ │ + │ │ │ : │ │ + │ │ │ Ret (Some val, __VERIFIER_nondet_int) : │ │ + │ │ ▼ : │ │ + │ │ ┌────────────────────────────────────────┐ : │ │ + │ │ │ _ │ : │ │ + │ │ └────────────────────────────────────────┘ : │ │ + │ │ │ : │ │ + │ │ │ InlineReturn 'tmp' : │ │ + │ │ ▼ : │ │ + │ │ ┌────────────────────────────────────────┐ : │ │ │ │ │ _ │ ◀┘ │ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ Test (x > 0,false) │ Assign 'x = tmp' │ │ │ ▼ ▼ │ │ │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ - └──────────────────▶ │ _ │ ─┐ │ _ │ ──────────────────────────────────────────────────┘ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ InlineEntry '(1)' │ │ Test (x > 0,true) │ - ▼ │ ▼ │ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ _ │ │ │ _ │ ───────────────────────────────────────────────────────┘ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ - │ │ │ - │ Entry __VERIFIER_assert │ │ Test (x < 2,true) - ▼ │ ▼ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ - │ _ │ │ │ _ │ ─┐ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(1)' │ InlineEntry '(x == 1)' │ - ▼ │ ▼ │ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ _ │ │ │ _ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ Ret (None, __VERIFIER_assert) │ │ Entry __VERIFIER_assert │ - ▼ │ ▼ │ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ _ │ │ │ _ │ │ - └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ InlineReturn │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' - ▼ │ ▼ │ - ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ - │ _ │ ◀┘ │ _ │ │ - └────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ InlineReturn │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ + └──────────────────▶ │ _ │ ·┐ │ _ │ ──────────────────────────────────────────────────┘ │ + └────────────────────────────────┘ : └────────────────────────────────────────┘ │ + │ : │ │ + │ InlineEntry '(1)' : │ Test (x > 0,true) │ + ▼ : ▼ │ + ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ │ + │ _ │ : │ _ │ ───────────────────────────────────────────────────────┘ + └────────────────────────────────┘ : └────────────────────────────────────────┘ + │ : │ + │ Entry __VERIFIER_assert : │ Test (x < 2,true) + ▼ : ▼ + ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ + │ _ │ : │ _ │ ·┐ + └────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(1)' │ InlineEntry '(x == 1)' : + ▼ : ▼ : + ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : + │ _ │ : │ _ │ : + └────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ Ret (None, __VERIFIER_assert) : │ Entry __VERIFIER_assert : + ▼ : ▼ : + ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : + │ _ │ : │ _ │ : + └────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ InlineReturn : │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x == 1)' + ▼ : ▼ : + ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ │ _ │ : + └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ │ Ret (None, __VERIFIER_assert) : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineReturn : + │ ▼ : + │ ┌────────────────────────────────────────┐ : │ │ _ │ ◀┘ │ └────────────────────────────────────────┘ │ │ diff --git a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected index 38b2720165..2fd5d66797 100644 --- a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected @@ -8,85 +8,85 @@ │ │ Entry main │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_nondet_int │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn 'tmp' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ + │ │ _ │ ·┐ │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '()' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_nondet_int : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (Some val, __VERIFIER_nondet_int) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn 'tmp' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ │ │ _ │ ◀┘ │ │ └────────────────────────────────────────┘ │ │ │ │ │ Test (x < 2,false) │ Assign 'x = tmp' │ ▼ ▼ │ ┌────────────────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ │ - ┌─ │ _ │ ◀──────────────────── │ _ │ │ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ InlineEntry '(1)' │ Test (x > 0,true) │ - │ ▼ ▼ │ - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ _ │ ──────────────────────────────────────────────────┘ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ - │ │ │ - │ │ Entry __VERIFIER_assert │ Test (x < 2,true) - │ ▼ ▼ - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ - │ │ _ │ │ _ │ ─┐ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Test (! cond,false) │ InlineEntry '(x == 1)' │ - │ ▼ ▼ │ - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ _ │ │ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert │ - │ ▼ ▼ │ - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ _ │ │ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Test (! cond,false) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineReturn │ Inlined Proc '__VERIFIER_assert(x == 1)' - │ │ ▼ ▼ - │ │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ └────────────────────────────────────────────────────▶ │ _ │ - │ └─────────────────────────────────────────────────────────────────────────────────────────┘ - │ │ ▲ - │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(1)' - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ - └───────────────────────────────────────────────────────────────────────────────────────────────────────┘ + ┌· │ _ │ ◀──────────────────── │ _ │ │ + : └────────────────────────────────┘ └────────────────────────────────────────┘ │ + : │ │ │ + : │ InlineEntry '(1)' │ Test (x > 0,true) │ + : ▼ ▼ │ + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ + : │ _ │ │ _ │ ──────────────────────────────────────────────────┘ + : └────────────────────────────────┘ └────────────────────────────────────────┘ + : │ │ + : │ Entry __VERIFIER_assert │ Test (x < 2,true) + : ▼ ▼ + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ + : │ _ │ │ _ │ ·┐ + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Test (! cond,false) │ InlineEntry '(x == 1)' : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ │ Test (! cond,false) : + : │ ▼ : + : │ ┌────────────────────────────────────────┐ : + : │ │ _ │ : + : │ └────────────────────────────────────────┘ : + : │ │ : + : │ │ Ret (None, __VERIFIER_assert) : + : │ ▼ : + : │ ┌────────────────────────────────────────┐ : + : │ │ _ │ : + : │ └────────────────────────────────────────┘ : + : │ │ : + : │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' + : │ ▼ ▼ + : │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + : └────────────────────────────────────────────────────▶ │ _ │ + : └─────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(1)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └·······································································································┘ diff --git a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected index 33c515c204..b1fcfbfd21 100644 --- a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ @@ -47,34 +47,34 @@ │ │ Test (x < 2,true) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x == 1)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ Test (x < 2,false) │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ Test (x > 0,false) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ │ _ │ ·┼················································┐ + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ InlineEntry '(x == 1)' │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ Entry __VERIFIER_assert │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ Test (x < 2,false) │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ Test (! cond,false) │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ Ret (None, __VERIFIER_assert) │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ InlineReturn │ Test (x > 0,false) : Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ └──────────────────▶ │ _ │ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected index 4db209decd..653edd1389 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected index 329220df5d..9b8bc097c3 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ -│ _ │ ─┐ -└────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ -┌────────────────────────────────────────┐ │ -│ _ │ │ -└────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ -┌────────────────────────────────────────┐ │ -│ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' -└────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ -┌────────────────────────────────────────┐ │ -│ _ │ │ -└────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ -┌────────────────────────────────────────┐ │ +│ _ │ ·┐ +└────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' +└────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected index 0dfbc18dee..20a0799cc9 100644 --- a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ @@ -53,43 +53,43 @@ │ │ Test (x > 1,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼────────────────── │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineEntry '(x == 1)' │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Test (x > 2,true) │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x > 1,true) - │ │ ▼ ▼ ▼ - │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └─────────────────▶ │ _ │ - │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ │ ▲ - │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ - └────────────────────────────────────────────────────────────────────┘ + ┌····┼·················· │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineEntry '(x == 1)' │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Entry __VERIFIER_assert │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ Test (x > 2,true) │ Test (! cond,false) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Ret (None, __VERIFIER_assert) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineReturn │ Test (x < 1,true) │ Test (x > 1,true) + : │ ▼ ▼ ▼ + : │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + : └─────────────────▶ │ _ │ + : └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └····································································┘ diff --git a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected index 9e2ae0edfd..8e2585f97c 100644 --- a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ @@ -53,43 +53,43 @@ │ │ Test (x != 1,false) │ │ │ ▼ │ │ │ ┌────────────────────────────────────────┐ │ │ - ┌────┼────────────────── │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineEntry '(x == 1)' │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry __VERIFIER_assert │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Test (x > 2,true) │ Test (! cond,false) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Ret (None, __VERIFIER_assert) │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ InlineReturn │ Test (x < 1,true) │ Test (x != 1,true) - │ │ ▼ ▼ ▼ - │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ └─────────────────▶ │ _ │ - │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ │ ▲ - │ │ Ret (Some 0, main) │ Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ - └────────────────────────────────────────────────────────────────────┘ + ┌····┼·················· │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineEntry '(x == 1)' │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Entry __VERIFIER_assert │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ Test (x > 2,true) │ Test (! cond,false) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ Ret (None, __VERIFIER_assert) │ │ + : │ ▼ │ │ + : │ ┌────────────────────────────────────────┐ │ │ + : │ │ _ │ │ │ + : │ └────────────────────────────────────────┘ │ │ + : │ │ │ │ + : │ │ InlineReturn │ Test (x < 1,true) │ Test (x != 1,true) + : │ ▼ ▼ ▼ + : │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + : └─────────────────▶ │ _ │ + : └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └····································································┘ diff --git a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected index 8ccfffdd65..727d2b0c08 100644 --- a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected @@ -5,30 +5,30 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '()' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_nondet_int │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ │ - │ │ - │ Ret (Some val, __VERIFIER_nondet_int) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineReturn 'tmp' │ - ▼ │ - ┌────────────────────────────────────────┐ │ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : │ _ │ ◀┘ └────────────────────────────────────────┘ │ @@ -47,34 +47,34 @@ │ │ Test (x > 1,false) │ │ ▼ │ │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x == 1)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ Test (x > 1,true) │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ Test (x < 1,true) │ Inlined Proc '__VERIFIER_assert(x == 1)' + │ │ _ │ ·┼················································┐ + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ InlineEntry '(x == 1)' │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ Entry __VERIFIER_assert │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ Test (x > 1,true) │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ Test (! cond,false) │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ Ret (None, __VERIFIER_assert) │ : + │ ▼ │ : + │ ┌────────────────────────────────────────┐ │ : + │ │ _ │ │ : + │ └────────────────────────────────────────┘ │ : + │ │ │ : + │ │ InlineReturn │ Test (x < 1,true) : Inlined Proc '__VERIFIER_assert(x == 1)' │ ▼ ▼ ▼ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ └─────────────────▶ │ _ │ diff --git a/tests/sv-comp/eq/eq_double_true-unreach-call.expected b/tests/sv-comp/eq/eq_double_true-unreach-call.expected index ca2079d2e5..9779fbd085 100644 --- a/tests/sv-comp/eq/eq_double_true-unreach-call.expected +++ b/tests/sv-comp/eq/eq_double_true-unreach-call.expected @@ -5,115 +5,115 @@ │ Entry main ▼ InlineReturn ┌────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(a == b)' - ┌─────────────────────────────────────────────────────▶ │ _ │ ◀─────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (1,true) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_nondet_int │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn 'tmp' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ ◀┘ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'x = tmp' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'y = x' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '(x == y)' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_assert │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (None, __VERIFIER_assert) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ ┌───────────────────────────────────────────────── │ _ │ ◀┘ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineEntry '()' ┌────────────────────────────────────────────────┘ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Entry __VERIFIER_nondet_int │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ Ret (Some val, __VERIFIER_nondet_int) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ │ │ _ │ │ - │ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ │ InlineReturn 'tmp___0' │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ └────────────────────────────────────────────────▶ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - └────┐ │ Assign 'a = tmp___0' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'b = a' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┘ + ┌─────────────────────────────────────────────────────▶ │ _ │ ◀·················································┐ + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Test (1,true) : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ ·┐ : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ InlineEntry '()' : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ Entry __VERIFIER_nondet_int : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ Ret (Some val, __VERIFIER_nondet_int) : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ InlineReturn 'tmp' : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ ◀┘ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Assign 'x = tmp' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Assign 'y = x' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ ·┐ : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ InlineEntry '(x == y)' : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ Entry __VERIFIER_assert : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x == y)' : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ Ret (None, __VERIFIER_assert) : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ │ _ │ : : + │ └────────────────────────────────────────┘ : : + │ │ : : + │ │ InlineReturn : : + │ ▼ : : + │ ┌────────────────────────────────────────┐ : : + │ ┌················································· │ _ │ ◀┘ : + │ : └────────────────────────────────────────┘ : + │ : │ : + │ : │ InlineEntry '()' ┌················································┘ + │ : ▼ : + │ : ┌────────────────────────────────────────┐ : + │ : │ _ │ : + │ : └────────────────────────────────────────┘ : + │ : │ : + │ : │ Entry __VERIFIER_nondet_int : + │ : ▼ : + │ : ┌────────────────────────────────────────┐ : + │ : Inlined Proc 'tmp___0 = __VERIFIER_nondet_int()' │ _ │ : + │ : └────────────────────────────────────────┘ : + │ : │ : + │ : │ Ret (Some val, __VERIFIER_nondet_int) : + │ : ▼ : + │ : ┌────────────────────────────────────────┐ : + │ : │ _ │ : + │ : └────────────────────────────────────────┘ : + │ : │ : + │ : │ InlineReturn 'tmp___0' : + │ : ▼ : + │ : ┌────────────────────────────────────────┐ : + │ └················································▶ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + └────┐ │ Assign 'a = tmp___0' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ : + │ └────────────────────────────────────────┘ : + │ │ : + │ │ Assign 'b = a' : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ ·┘ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(a == b)' diff --git a/tests/sv-comp/eq/eq_single_true-unreach-call.expected b/tests/sv-comp/eq/eq_single_true-unreach-call.expected index f8b5cdb969..395c01ce71 100644 --- a/tests/sv-comp/eq/eq_single_true-unreach-call.expected +++ b/tests/sv-comp/eq/eq_single_true-unreach-call.expected @@ -5,49 +5,49 @@ │ Entry main ▼ ┌────────────────────────────────────────┐ InlineReturn - ┌────────────────────────────────────────▶ │ _ │ ◀─────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (1,true) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_nondet_int │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ Inlined Proc '__VERIFIER_assert(x == y)' │ Ret (Some val, __VERIFIER_nondet_int) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn 'tmp' │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - │ │ _ │ ◀┘ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'x = tmp' ┌────────────────────────────────────────────────┘ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'y = x' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - └───────────────────────────────────────── │ _ │ │ + ┌········································▶ │ _ │ ◀─────────────────────────────────────────────────┐ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Test (1,true) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ ·┐ │ + : └────────────────────────────────────────┘ : │ + : │ : │ + : │ InlineEntry '()' : │ + : ▼ : │ + : ┌────────────────────────────────────────┐ : │ + : │ _ │ : │ + : └────────────────────────────────────────┘ : │ + : │ : │ + : │ Entry __VERIFIER_nondet_int : │ + : ▼ : │ + : ┌────────────────────────────────────────┐ : │ + : │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + : └────────────────────────────────────────┘ : │ + : │ : │ + : Inlined Proc '__VERIFIER_assert(x == y)' │ Ret (Some val, __VERIFIER_nondet_int) : │ + : ▼ : │ + : ┌────────────────────────────────────────┐ : │ + : │ _ │ : │ + : └────────────────────────────────────────┘ : │ + : │ : │ + : │ InlineReturn 'tmp' : │ + : ▼ : │ + : ┌────────────────────────────────────────┐ : │ + : │ _ │ ◀┘ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Assign 'x = tmp' ┌────────────────────────────────────────────────┘ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Assign 'y = x' │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + └········································· │ _ │ │ └────────────────────────────────────────┘ │ │ │ │ InlineEntry '(x == y)' │ diff --git a/tests/sv-comp/eq/multivar_false-unreach-call1.expected b/tests/sv-comp/eq/multivar_false-unreach-call1.expected index cec99f07fd..018b0e06fe 100644 --- a/tests/sv-comp/eq/multivar_false-unreach-call1.expected +++ b/tests/sv-comp/eq/multivar_false-unreach-call1.expected @@ -8,30 +8,30 @@ │ │ Entry main │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_nondet_uint │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ - │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn 'tmp' │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ + │ │ _ │ ·┐ │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '()' : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_nondet_uint : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ + │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (Some val, __VERIFIER_nondet_uint) : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn 'tmp' : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ │ │ _ │ ◀┘ │ │ └─────────────────────────────────────────┘ │ │ │ │ @@ -50,36 +50,36 @@ │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ - └─ │ _ │ │ _ │ ─┐ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(x < y)' │ - ▼ │ - ┌─────────────────────────────────────────┐ │ - │ _ │ │ - └─────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ - │ _ │ ◀─────────────────────── │ _ │ │ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ │ - │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x < y)' - ▼ ▼ │ - ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ _ │ │ _ │ │ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ │ - │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ - ▼ ▼ │ - ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ _ │ │ _ │ │ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌─────────────────────────────────────────┐ │ + └─ │ _ │ │ _ │ ·┐ + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ : + │ InlineEntry '(x < y)' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ : + │ _ │ ◀─────────────────────── │ _ │ : + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ │ : + │ InlineEntry '()' │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x < y)' + ▼ ▼ : + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ │ : + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) : + ▼ ▼ : + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌─────────────────────────────────────────┐ : │ _ │ ◀┘ └─────────────────────────────────────────┘ │ diff --git a/tests/sv-comp/eq/multivar_true-unreach-call1.expected b/tests/sv-comp/eq/multivar_true-unreach-call1.expected index 345783e41f..f1217ef669 100644 --- a/tests/sv-comp/eq/multivar_true-unreach-call1.expected +++ b/tests/sv-comp/eq/multivar_true-unreach-call1.expected @@ -8,30 +8,30 @@ │ │ Entry main │ │ ▼ │ │ ┌─────────────────────────────────────────┐ │ - │ │ _ │ ─┐ │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineEntry '()' │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Entry __VERIFIER_nondet_uint │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ - │ │ _ │ │ Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Ret (Some val, __VERIFIER_nondet_uint) │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ - │ │ _ │ │ │ - │ └─────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ InlineReturn 'tmp' │ │ - │ ▼ │ │ - │ ┌─────────────────────────────────────────┐ │ │ + │ │ _ │ ·┐ │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '()' : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_nondet_uint : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ + │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_uint()' │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (Some val, __VERIFIER_nondet_uint) : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └─────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn 'tmp' : │ + │ ▼ : │ + │ ┌─────────────────────────────────────────┐ : │ │ │ _ │ ◀┘ │ │ └─────────────────────────────────────────┘ │ │ │ │ @@ -50,36 +50,36 @@ │ │ Assign 'x = x + 1U' │ Test (x < 1024U,false) │ ▼ ▼ │ ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ - └─ │ _ │ │ _ │ ─┐ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(x == y)' │ - ▼ │ - ┌─────────────────────────────────────────┐ │ - │ _ │ │ - └─────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ │ - │ _ │ ◀─────────────────────── │ _ │ │ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ │ - │ InlineEntry '()' │ Test (! cond,false) │ Inlined Proc '__VERIFIER_assert(x == y)' - ▼ ▼ │ - ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ _ │ │ _ │ │ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ │ - │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) │ - ▼ ▼ │ - ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ │ - │ _ │ │ _ │ │ - └─────────────────────────┘ └─────────────────────────────────────────┘ │ - │ │ - │ InlineReturn │ - ▼ │ - ┌─────────────────────────────────────────┐ │ + └─ │ _ │ │ _ │ ·┐ + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ : + │ InlineEntry '(x == y)' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌─────────────────────────┐ Test (! cond,true) ┌─────────────────────────────────────────┐ : + │ _ │ ◀─────────────────────── │ _ │ : + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ │ : + │ InlineEntry '()' │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x == y)' + ▼ ▼ : + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ │ : + │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) : + ▼ ▼ : + ┌─────────────────────────┐ ┌─────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └─────────────────────────┘ └─────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌─────────────────────────────────────────┐ : │ _ │ ◀┘ └─────────────────────────────────────────┘ │ From 9a49db60a449bdb14bab3a89583bd1723975e045 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 11:05:26 +0300 Subject: [PATCH 184/689] Add TODOs to sv-comp/basic/if_trier_exclude_multiple tests --- .../sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.c | 1 + .../sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.c b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.c index e021ff930d..7af8b4e967 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.c +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_false-unreach-call.c @@ -25,5 +25,6 @@ int main() __VERIFIER_assert(x != 1); } } + // TODO: double InlineReturn edge in two first cases? return 0; } \ No newline at end of file diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c index 83994c2be7..434b6b29fb 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c @@ -25,5 +25,6 @@ int main() __VERIFIER_assert(x != 0 && x != 2); } } + // TODO: double InlineReturn edge in two first cases? return 0; } \ No newline at end of file From 74615c6e84704cbb2ff1d14a2c947d35ebb30779 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 11:34:07 +0300 Subject: [PATCH 185/689] Enable uncil transformation in ARG tests --- ...trier_exclude_multiple_true-unreach-call.c | 2 +- ...xclude_multiple_true-unreach-call.expected | 63 +++--- .../cfg/free_spawn_true-unreach-call.c | 1 + .../cfg/free_spawn_true-unreach-call.expected | 164 +++++++-------- tests/sv-comp/cfg/join_true-unreach-call.c | 2 +- .../cfg/join_true-unreach-call.expected | 192 +++++++++--------- .../region_global_init_true-unreach-call.c | 2 +- ...ion_global_init_true-unreach-call.expected | 192 +++++++++--------- .../cfg/uncil/and3_true-unreach-call.expected | 176 ++++++++-------- .../uncil/and3dead_true-unreach-call.expected | 176 ++++++++-------- .../cfg/uncil/and_copy_true-unreach-call.c | 1 + .../uncil/and_copy_true-unreach-call.expected | 172 ++++++++-------- ..._join_invariant_true-unreach-call.expected | 173 ++++++++-------- .../cfg/uncil/and_true-unreach-call.expected | 168 ++++++++------- .../cfg/uncil/and_var_false-unreach-call.c | 2 +- .../cfg/uncil/and_var_true-unreach-call.c | 2 +- .../cfg/uncil/or3_true-unreach-call.expected | 176 ++++++++-------- .../uncil/or3dead_true-unreach-call.expected | 176 ++++++++-------- .../cfg/uncil/or_true-unreach-call.expected | 168 ++++++++------- tests/sv-comp/dune.inc | 82 ++++---- tests/sv-comp/gen/gen.ml | 2 +- 21 files changed, 989 insertions(+), 1103 deletions(-) diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c index 434b6b29fb..05b57988ee 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c @@ -22,7 +22,7 @@ int main() } else { - __VERIFIER_assert(x != 0 && x != 2); + __VERIFIER_assert(x != 0 && x != 2); // TODO: uncil broken } } // TODO: double InlineReturn edge in two first cases? diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index 4a17e9c38c..0bfd036693 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -74,38 +74,35 @@ │ │ _ │ │ : │ _ │ │ │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ │ │ │ : │ │ - │ │ Ret (None, __VERIFIER_assert) │ : │ Test (x != 2,true) │ + │ │ Ret (None, __VERIFIER_assert) │ : │ Assign 'tmp___0 = x != 2' │ │ ▼ │ : ▼ │ - │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ - └─ │ _ │ ─┘ : │ _ │ │ - └────────────────────────────────┘ : └────────────────────────────────────────┘ │ - : │ │ - : │ Assign 'tmp___0 = 1' │ - : ▼ │ - : ┌────────────────────────────────────────┐ │ - └·········································· │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ InlineEntry '(tmp___0)' │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Entry __VERIFIER_assert │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Test (! cond,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ │ - └────────────────────────────────────────┘ │ - │ │ - │ Ret (None, __VERIFIER_assert) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - │ _ │ ───────────────────────────────────────────────────────┘ + │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ Assign 'tmp___0 = 1' │ + └─ │ _ │ ─┘ └·········································· │ _ │ ◀──────────────────────────────────────────────────────┼────────────────────────────────────────────┐ + └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ + │ │ │ + │ InlineEntry '(tmp___0)' │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Entry __VERIFIER_assert │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Test (! cond,false) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ │ │ + └────────────────────────────────────────┘ │ │ + │ │ │ + │ Ret (None, __VERIFIER_assert) │ │ + ▼ │ │ + ┌────────────────────────────────────────┐ │ │ + │ _ │ ───────────────────────────────────────────────────────┘ │ + └────────────────────────────────────────┘ │ + ┌────────────────────────────────────────┐ │ + │ _ │ ────────────────────────────────────────────────────────────────────────────────────────────────────┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.c b/tests/sv-comp/cfg/free_spawn_true-unreach-call.c index 115f252481..d05d83e337 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.c +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.c @@ -15,6 +15,7 @@ int main() else p = &foo; // actually dead + // TODO: uncil false branch missing free(p); // TODO: free shouldn't spawn return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected index 1588ba179b..90b4f2140f 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected @@ -1,87 +1,77 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'p = (void *)0' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp ' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x == 0,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x == 1,false) │ Test (x == 0,true) - │ ▼ │ -┌───┐ Test (x == -1,false) │ ┌────────────────────────────────────────┐ │ -│ _ │ ◀─────────────────────────────────┼─────────────────── │ _ │ │ -└───┘ │ └────────────────────────────────────────┘ │ - │ │ │ │ - │ │ Test (x == 1,true) │ Test (x == -1,true) │ - │ │ ▼ │ - │ │ ┌────────────────────────────────────────┐ │ - │ └──────────────────▶ │ _ │ ◀┘ - │ └────────────────────────────────────────┘ - │ │ - │ │ Proc 'tmp___0 = malloc(1)' - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'p = (void *)tmp___0' - │ ▼ - │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────┐ - └────────────────────────────────────────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Proc 'free(p)' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ + │ + │ Assign 'p = (void *)0' + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────────┘ + │ + │ Assign 'x = tmp ' + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ + │ + │ Test (x == 0 || (x == 1 || x == -1),true) + ▼ + ┌─────────────────────────────────┐ Test (x == 1 || x == -1,true) ┌────────────────────────────────────────────┐ Test (x == -1,true) ┌───┐ + │ _ │ ───────────────────────────────▶ │ _ │ ◀────────────────────────────────────────────── │ _ │ + └─────────────────────────────────┘ └────────────────────────────────────────────┘ └───┘ + │ │ │ + │ Test (x == 1 || x == -1,false) │ Proc 'tmp___0 = malloc(1)' │ + ▼ ▼ │ + ┌─────────────────────────────────┐ ┌────────────────────────────────────────────┐ │ + ┌────────────────────▶ │ _ │ │ _ │ │ + │ └─────────────────────────────────┘ └────────────────────────────────────────────┘ │ + │ │ │ │ + │ Test (x == -1,false) │ │ Assign 'p = (void *)tmp___0' │ + │ │ ▼ │ + │ │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────────┐ │ + │ └────────────────────────────────────────────────────────────────▶ │ _ │ │ + │ └────────────────────────────────────────────┘ │ + │ │ │ + │ │ Proc 'free(p)' │ + │ ▼ │ + │ ┌────────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (Some 0, main) │ + │ ▼ │ + │ ┌────────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────────┘ │ + │ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.c b/tests/sv-comp/cfg/join_true-unreach-call.c index 999e0cd578..b7f4d05506 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.c +++ b/tests/sv-comp/cfg/join_true-unreach-call.c @@ -14,6 +14,6 @@ int main() x = 1; else x = 2; - __VERIFIER_assert(1 <= x && x <= 2); + __VERIFIER_assert(1 <= x && x <= 2); // TODO: uncil broken return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected index 9ecc6aef41..10ebb0e289 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -1,99 +1,93 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : -│ _ │ ◀───────────────── │ _ │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,false) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 2' - │ ▼ - │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (x <= 2,true) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '(tmp___0)' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (None, __VERIFIER_assert) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀────────────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └─────────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = x <= 2' + ▼ +┌───┐ Assign 'tmp___0 = 1' ┌────────────────────────────────────────┐ +│ _ │ ──────────────────────▶ │ _ │ ·┐ +└───┘ └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(tmp___0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.c b/tests/sv-comp/cfg/region_global_init_true-unreach-call.c index 8db9193806..5c4a5a0b27 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.c +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.c @@ -22,6 +22,6 @@ int main() x = 1; else x = 2; - __VERIFIER_assert(1 <= x && x <= 2); + __VERIFIER_assert(1 <= x && x <= 2); // TODO: uncil broken return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected index 9ecc6aef41..10ebb0e289 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -1,99 +1,93 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : -│ _ │ ◀───────────────── │ _ │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,false) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 2' - │ ▼ - │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (x <= 2,true) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '(tmp___0)' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (None, __VERIFIER_assert) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀────────────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └─────────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (1 <= x,true) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = x <= 2' + ▼ +┌───┐ Assign 'tmp___0 = 1' ┌────────────────────────────────────────┐ +│ _ │ ──────────────────────▶ │ _ │ ·┐ +└───┘ └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(tmp___0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected index 15955ccdc5..a6a12c4c2f 100644 --- a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected @@ -1,95 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0,true) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x < 3,true) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (x < 2,true) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - ┌····┼··················· │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineEntry '(x == 1)' │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Entry __VERIFIER_assert │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ Test (x < 3,false) │ Test (! cond,false) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Ret (None, __VERIFIER_assert) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineReturn │ Test (x > 0,false) │ Test (x < 2,false) - : │ ▼ ▼ ▼ - : │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - : └──────────────────▶ │ _ │ - : └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - : │ ▲ - : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' - : ▼ : - : ┌────────────────────────────────────────┐ : - : │ _ │ : - : └────────────────────────────────────────┘ : - : : - └·····································································┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ─────────────────────────────────────────────────────────────────────────┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0 && (x < 3 && x < 2),true) │ + ▼ │ +┌───┐ Test (x < 3 && x < 2,true) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ +│ _ │ ─────────────────────────────▶ │ _ │ │ +└───┘ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ : ▲ │ + │ │ InlineEntry '(x == 1)' : │ Test (x < 2,true) │ + │ ▼ : │ │ + │ ┌────────────────────────────────────────┐ : ┌─────────────────────┐ │ + │ │ _ │ : │ _ │ │ + │ └────────────────────────────────────────┘ : └─────────────────────┘ │ + │ │ : │ │ + │ │ Entry __VERIFIER_assert : │ │ + │ ▼ : │ │ + │ ┌────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ Test (x > 0 && (x < 3 && x < 2),false) + │ └────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Test (! cond,false) : │ │ + │ ▼ : │ │ + │ ┌────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Ret (None, __VERIFIER_assert) : │ │ + │ ▼ : │ │ + │ ┌────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x < 2,false) │ + │ ▼ ▼ ▼ │ + │ Test (x < 3 && x < 2,false) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + └────────────────────────────────▶ │ _ │ ◀┘ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected index c11ffee6b7..19d7e2fb3d 100644 --- a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected @@ -1,95 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0,true) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x < 3,true) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (x == 1,true) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - ┌····┼··················· │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineEntry '(x == 1)' │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Entry __VERIFIER_assert │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ Test (x < 3,false) │ Test (! cond,false) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Ret (None, __VERIFIER_assert) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineReturn │ Test (x > 0,false) │ Test (x == 1,false) - : │ ▼ ▼ ▼ - : │ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - : └──────────────────▶ │ _ │ - : └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - : │ ▲ - : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' - : ▼ : - : ┌────────────────────────────────────────┐ : - : │ _ │ : - : └────────────────────────────────────────┘ : - : : - └·····································································┘ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ·┐ + └─────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └─────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ──────────────────────────────────────────────────────────────────────────┐ + └─────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0 && (x < 3 && x == 1),true) │ + ▼ │ +┌───┐ Test (x < 3 && x == 1,true) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ +│ _ │ ──────────────────────────────▶ │ _ │ │ +└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ : ▲ │ + │ │ InlineEntry '(x == 1)' : │ Test (x == 1,true) │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : ┌──────────────────────┐ │ + │ │ _ │ : │ _ │ │ + │ └─────────────────────────────────────────┘ : └──────────────────────┘ │ + │ │ : │ │ + │ │ Entry __VERIFIER_assert : │ │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ Test (x > 0 && (x < 3 && x == 1),false) + │ └─────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Test (! cond,false) : │ │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └─────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Ret (None, __VERIFIER_assert) : │ │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └─────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x == 1,false) │ + │ ▼ ▼ ▼ │ + │ Test (x < 3 && x == 1,false) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + └─────────────────────────────────▶ │ _ │ ◀┘ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c index b924f4cd8b..7b7f151489 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c @@ -18,5 +18,6 @@ int main() __VERIFIER_assert(1); return 1; } + // TODO: uncil false branch missing return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected index 6b2faf9b64..c7be30aff3 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected @@ -1,93 +1,81 @@ - - ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - │ │ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ │ Entry main │ │ - │ │ ▼ │ │ - │ │ ┌────────────────────────────────────────┐ │ │ - │ │ │ _ │ ·┐ │ │ - │ │ └────────────────────────────────────────┘ : │ │ - │ │ │ : │ │ - │ │ │ InlineEntry '()' : │ │ - │ │ ▼ : │ │ - │ │ ┌────────────────────────────────────────┐ : │ │ - │ │ │ _ │ : │ │ - │ │ └────────────────────────────────────────┘ : │ │ - │ │ │ : │ │ - │ Test (x < 2,false) │ │ Entry __VERIFIER_nondet_int : │ │ - │ │ ▼ : │ │ - │ │ ┌────────────────────────────────────────┐ : │ │ - │ │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ │ - │ │ └────────────────────────────────────────┘ : │ │ - │ │ │ : │ │ - │ │ │ Ret (Some val, __VERIFIER_nondet_int) : │ │ - │ │ ▼ : │ │ - │ │ ┌────────────────────────────────────────┐ : │ │ - │ │ │ _ │ : │ │ - │ │ └────────────────────────────────────────┘ : │ │ - │ │ │ : │ │ - │ │ │ InlineReturn 'tmp' : │ │ - │ │ ▼ : │ │ - │ │ ┌────────────────────────────────────────┐ : │ │ - │ │ │ _ │ ◀┘ │ │ - │ │ └────────────────────────────────────────┘ │ │ - │ │ │ │ │ - │ │ Test (x > 0,false) │ Assign 'x = tmp' │ │ - │ ▼ ▼ │ │ - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ │ - └──────────────────▶ │ _ │ ·┐ │ _ │ ──────────────────────────────────────────────────┘ │ - └────────────────────────────────┘ : └────────────────────────────────────────┘ │ - │ : │ │ - │ InlineEntry '(1)' : │ Test (x > 0,true) │ - ▼ : ▼ │ - ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ │ - │ _ │ : │ _ │ ───────────────────────────────────────────────────────┘ - └────────────────────────────────┘ : └────────────────────────────────────────┘ - │ : │ - │ Entry __VERIFIER_assert : │ Test (x < 2,true) - ▼ : ▼ - ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ - │ _ │ : │ _ │ ·┐ - └────────────────────────────────┘ : └────────────────────────────────────────┘ : - │ : │ : - │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(1)' │ InlineEntry '(x == 1)' : - ▼ : ▼ : - ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : - │ _ │ : │ _ │ : - └────────────────────────────────┘ : └────────────────────────────────────────┘ : - │ : │ : - │ Ret (None, __VERIFIER_assert) : │ Entry __VERIFIER_assert : - ▼ : ▼ : - ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : - │ _ │ : │ _ │ : - └────────────────────────────────┘ : └────────────────────────────────────────┘ : - │ : │ : - │ InlineReturn : │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x == 1)' - ▼ : ▼ : - ┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ │ _ │ : - └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ │ Ret (None, __VERIFIER_assert) : - │ ▼ : - │ ┌────────────────────────────────────────┐ : - │ │ _ │ : - │ └────────────────────────────────────────┘ : - │ │ : - │ │ InlineReturn : - │ ▼ : - │ ┌────────────────────────────────────────┐ : - │ │ _ │ ◀┘ - │ └────────────────────────────────────────┘ - │ │ - │ │ Ret (Some 0, main) - │ ▼ - │ Ret (Some 1, main) ┌────────────────────────────────────────┐ - └─────────────────────────────────────────────────────────────────────▶ │ _ │ + ┌────────────────────────────────────────┐ + │ _ │ └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (x > 0 && x < 2,true) + ▼ + ┌────────────────────────────────┐ Test (x < 2,true) ┌────────────────────────────────────────┐ + │ _ │ ────────────────────▶ │ _ │ ·┐ + └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ Test (x < 2,false) │ InlineEntry '(x == 1)' : + ▼ ▼ : + ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + ┌···································· │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ InlineEntry '(1)' │ Entry __VERIFIER_assert : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Entry __VERIFIER_assert │ Test (! cond,false) : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Test (! cond,false) │ Ret (None, __VERIFIER_assert) : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Ret (None, __VERIFIER_assert) │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ ◀┘ + : └────────────────────────────────┘ └────────────────────────────────────────┘ + : │ │ + : Inlined Proc '__VERIFIER_assert(1)' │ InlineReturn │ Ret (Some 0, main) + : ▼ ▼ + : ┌────────────────────────────────┐ Ret (Some 1, main) ┌────────────────────────────────────────┐ + └···································▶ │ _ │ ────────────────────▶ │ _ │ + └────────────────────────────────┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected index 2fd5d66797..2aa0dc7973 100644 --- a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected @@ -1,92 +1,81 @@ - - ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry main │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ·┐ │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineEntry '()' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Entry __VERIFIER_nondet_int : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Ret (Some val, __VERIFIER_nondet_int) : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineReturn 'tmp' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ ◀┘ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ Test (x < 2,false) │ Assign 'x = tmp' │ - ▼ ▼ │ - ┌────────────────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ │ - ┌· │ _ │ ◀──────────────────── │ _ │ │ - : └────────────────────────────────┘ └────────────────────────────────────────┘ │ - : │ │ │ - : │ InlineEntry '(1)' │ Test (x > 0,true) │ - : ▼ ▼ │ - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ - : │ _ │ │ _ │ ──────────────────────────────────────────────────┘ - : └────────────────────────────────┘ └────────────────────────────────────────┘ - : │ │ - : │ Entry __VERIFIER_assert │ Test (x < 2,true) - : ▼ ▼ - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ - : │ _ │ │ _ │ ·┐ - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ Test (! cond,false) │ InlineEntry '(x == 1)' : - : ▼ ▼ : - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - : │ _ │ │ _ │ : - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ Ret (None, __VERIFIER_assert) │ Entry __VERIFIER_assert : - : ▼ ▼ : - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - : │ _ │ │ _ │ : - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ │ Test (! cond,false) : - : │ ▼ : - : │ ┌────────────────────────────────────────┐ : - : │ │ _ │ : - : │ └────────────────────────────────────────┘ : - : │ │ : - : │ │ Ret (None, __VERIFIER_assert) : - : │ ▼ : - : │ ┌────────────────────────────────────────┐ : - : │ │ _ │ : - : │ └────────────────────────────────────────┘ : - : │ │ : - : │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' - : │ ▼ ▼ - : │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - : └────────────────────────────────────────────────────▶ │ _ │ - : └─────────────────────────────────────────────────────────────────────────────────────────┘ - : │ ▲ - : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(1)' - : ▼ : - : ┌────────────────────────────────────────┐ : - : │ _ │ : - : └────────────────────────────────────────┘ : - : : - └·······································································································┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + ┌──────────────────────────────────────────────────────────────────────────────────── │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (x > 0 && x < 2,true) + │ ▼ + │ ┌────────────────────────────────┐ Test (x < 2,true) ┌────────────────────────────────────────┐ + │ │ _ │ ───────────────────▶ │ _ │ ·┐ + │ └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ │ : + │ Test (x > 0 && x < 2,false) │ Test (x < 2,false) │ InlineEntry '(x == 1)' : + │ ▼ ▼ : + │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + └───────────────────────────▶ │ _ │ │ _ │ : + └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ InlineEntry '(1)' │ Entry __VERIFIER_assert : + ▼ ▼ : + ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ Entry __VERIFIER_assert │ Test (! cond,false) : + ▼ ▼ : + ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ Test (! cond,false) │ Ret (None, __VERIFIER_assert) : + ▼ ▼ : + ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + │ _ │ │ _ │ : + └────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ Ret (None, __VERIFIER_assert) │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' + ▼ ▼ ▼ + ┌────────────────────────────────┐ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + │ _ │ ───────────────────▶ │ _ │ + └────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected index b1fcfbfd21..0da5ff4129 100644 --- a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected @@ -1,87 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0,true) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌─────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x < 2,true) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ·┼················································┐ - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ InlineEntry '(x == 1)' │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ Entry __VERIFIER_assert │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ Test (x < 2,false) │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ Test (! cond,false) │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ Ret (None, __VERIFIER_assert) │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ InlineReturn │ Test (x > 0,false) : Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ ▼ ▼ - │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └──────────────────▶ │ _ │ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ──────────────────────────────────────────────────┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0 && x < 2,true) │ + ▼ │ +┌───┐ Test (x < 2,true) ┌────────────────────────────────────────┐ │ +│ _ │ ────────────────────▶ │ _ │ ·┐ │ +└───┘ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '(x == 1)' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_assert : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Test (! cond,false) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (None, __VERIFIER_assert) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x > 0 && x < 2,false) + │ ▼ ▼ ▼ + │ Test (x < 2,false) ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + └───────────────────────▶ │ _ │ + └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c index ab5a339d19..11fa23dbdc 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c @@ -10,7 +10,7 @@ void __VERIFIER_assert(int cond) { int main() { int x = __VERIFIER_nondet_int(); - int y = x > 0 && x < 2; + int y = x > 0 && x < 2; // TODO: uncil broken if (y) __VERIFIER_error(); return 0; diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c index 4437139c87..a43228214c 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c @@ -10,7 +10,7 @@ void __VERIFIER_assert(int cond) { int main() { int x = __VERIFIER_nondet_int(); - int y = x > 0 && x < 0; + int y = x > 0 && x < 0; // TODO: uncil broken if (y) __VERIFIER_error(); return 0; diff --git a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected index 20a0799cc9..cb14942893 100644 --- a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected @@ -1,95 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x < 1,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x > 2,false) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (x > 1,false) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - ┌····┼·················· │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineEntry '(x == 1)' │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Entry __VERIFIER_assert │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ Test (x > 2,true) │ Test (! cond,false) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Ret (None, __VERIFIER_assert) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineReturn │ Test (x < 1,true) │ Test (x > 1,true) - : │ ▼ ▼ ▼ - : │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - : └─────────────────▶ │ _ │ - : └───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - : │ ▲ - : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' - : ▼ : - : ┌────────────────────────────────────────┐ : - : │ _ │ : - : └────────────────────────────────────────┘ : - : : - └····································································┘ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ·┐ + └─────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └─────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ──────────────────────────────────────────────────────────────────────────────────┐ + └─────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1 || (x > 2 || x > 1),false) │ + ▼ │ +┌───┐ Test (x > 1,false) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ +│ _ │ ────────────────────▶ │ _ │ │ +└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ : ▲ │ + │ │ InlineEntry '(x == 1)' : │ Test (x > 2 || x > 1,false) │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : ┌──────────────────────────────┐ │ + │ │ _ │ : │ _ │ │ + │ └─────────────────────────────────────────┘ : └──────────────────────────────┘ │ + │ │ : │ │ + │ │ Entry __VERIFIER_assert : │ │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ Test (x < 1 || (x > 2 || x > 1),true) + │ └─────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Test (! cond,false) : │ │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └─────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Ret (None, __VERIFIER_assert) : │ │ + │ ▼ : │ │ + │ ┌─────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └─────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x > 2 || x > 1,true) │ + │ ▼ ▼ ▼ │ + │ Test (x > 1,true) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + └───────────────────────▶ │ _ │ ◀┘ + └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected index 8e2585f97c..0cc7108b55 100644 --- a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected @@ -1,95 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x < 1,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x > 2,false) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ─┼────────────────────────────────────────────────┐ - │ └────────────────────────────────────────┘ │ │ - │ │ │ │ - │ │ Test (x != 1,false) │ │ - │ ▼ │ │ - │ ┌────────────────────────────────────────┐ │ │ - ┌····┼·················· │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineEntry '(x == 1)' │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Entry __VERIFIER_assert │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ Test (x > 2,true) │ Test (! cond,false) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ Ret (None, __VERIFIER_assert) │ │ - : │ ▼ │ │ - : │ ┌────────────────────────────────────────┐ │ │ - : │ │ _ │ │ │ - : │ └────────────────────────────────────────┘ │ │ - : │ │ │ │ - : │ │ InlineReturn │ Test (x < 1,true) │ Test (x != 1,true) - : │ ▼ ▼ ▼ - : │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - : └─────────────────▶ │ _ │ - : └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - : │ ▲ - : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(x == 1)' - : ▼ : - : ┌────────────────────────────────────────┐ : - : │ _ │ : - : └────────────────────────────────────────┘ : - : : - └····································································┘ + ┌──────────────────────────────────────────┐ + │ _ │ + └──────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌──────────────────────────────────────────┐ + │ _ │ ·┐ + └──────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ : + └──────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └──────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ : + └──────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ ◀┘ + └──────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌──────────────────────────────────────────┐ + │ _ │ ───────────────────────────────────────────────────────────────────────────────────┐ + └──────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1 || (x > 2 || x != 1),false) │ + ▼ │ +┌───┐ Test (x != 1,false) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ +│ _ │ ─────────────────────▶ │ _ │ │ +└───┘ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ + │ │ : ▲ │ + │ │ InlineEntry '(x == 1)' : │ Test (x > 2 || x != 1,false) │ + │ ▼ : │ │ + │ ┌──────────────────────────────────────────┐ : ┌───────────────────────────────┐ │ + │ │ _ │ : │ _ │ │ + │ └──────────────────────────────────────────┘ : └───────────────────────────────┘ │ + │ │ : │ │ + │ │ Entry __VERIFIER_assert : │ │ + │ ▼ : │ │ + │ ┌──────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ Test (x < 1 || (x > 2 || x != 1),true) + │ └──────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Test (! cond,false) : │ │ + │ ▼ : │ │ + │ ┌──────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └──────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ Ret (None, __VERIFIER_assert) : │ │ + │ ▼ : │ │ + │ ┌──────────────────────────────────────────┐ : │ │ + │ │ _ │ : │ │ + │ └──────────────────────────────────────────┘ : │ │ + │ │ : │ │ + │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x > 2 || x != 1,true) │ + │ ▼ ▼ ▼ │ + │ Test (x != 1,true) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ + └────────────────────────▶ │ _ │ ◀┘ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌──────────────────────────────────────────┐ + │ _ │ + └──────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected index 727d2b0c08..8f7dfe911b 100644 --- a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected @@ -1,87 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x < 1,false) │ - ▼ │ - ┌────────────────────────────────────────┐ │ - ┌────────────────── │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Test (x > 1,false) │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ·┼················································┐ - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ InlineEntry '(x == 1)' │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ Entry __VERIFIER_assert │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ Test (x > 1,true) │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ Test (! cond,false) │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ Ret (None, __VERIFIER_assert) │ : - │ ▼ │ : - │ ┌────────────────────────────────────────┐ │ : - │ │ _ │ │ : - │ └────────────────────────────────────────┘ │ : - │ │ │ : - │ │ InlineReturn │ Test (x < 1,true) : Inlined Proc '__VERIFIER_assert(x == 1)' - │ ▼ ▼ ▼ - │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────▶ │ _ │ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ──────────────────────────────────────────────────┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1 || x > 1,false) │ + ▼ │ +┌───┐ Test (x > 1,false) ┌────────────────────────────────────────┐ │ +│ _ │ ────────────────────▶ │ _ │ ·┐ │ +└───┘ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '(x == 1)' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_assert : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Test (! cond,false) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (None, __VERIFIER_assert) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x < 1 || x > 1,true) + │ ▼ ▼ ▼ + │ Test (x > 1,true) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + └───────────────────────▶ │ _ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index 942f24d2b4..fbc51e76e9 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -11,7 +11,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -33,7 +33,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -55,7 +55,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -77,7 +77,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -99,7 +99,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -121,7 +121,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -143,7 +143,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -165,7 +165,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -187,7 +187,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -209,7 +209,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -231,7 +231,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -253,7 +253,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -275,7 +275,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -297,7 +297,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -319,7 +319,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -341,7 +341,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -363,7 +363,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -385,7 +385,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -407,7 +407,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -429,7 +429,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -451,7 +451,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -473,7 +473,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -495,7 +495,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -517,7 +517,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -539,7 +539,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -561,7 +561,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -583,7 +583,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -605,7 +605,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -627,7 +627,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -649,7 +649,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -671,7 +671,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -693,7 +693,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -715,7 +715,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -737,7 +737,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -759,7 +759,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -781,7 +781,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -803,7 +803,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -825,7 +825,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -847,7 +847,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -869,7 +869,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -891,7 +891,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %{target} (run graph-easy --as=boxart arg.dot))))) diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index e94af33e00..a18b99f2ea 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -15,7 +15,7 @@ let generate_rule c_dir_file = (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) (with-stdout-to %%{target} (run graph-easy --as=boxart arg.dot))))) From f2d89a76b07dd7ecd47f212cd957b92c8d8e302e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 12:07:11 +0300 Subject: [PATCH 186/689] Fix some broke ARG uncil transformation due to location equality --- src/witness/myARG.ml | 4 +- ...trier_exclude_multiple_true-unreach-call.c | 2 +- ...xclude_multiple_true-unreach-call.expected | 32 ++-- tests/sv-comp/cfg/join_true-unreach-call.c | 2 +- .../cfg/join_true-unreach-call.expected | 180 +++++++++--------- .../region_global_init_true-unreach-call.c | 2 +- ...ion_global_init_true-unreach-call.expected | 180 +++++++++--------- .../uncil/and_var_false-unreach-call.expected | 156 ++++++++------- .../uncil/and_var_true-unreach-call.expected | 144 +++++++------- 9 files changed, 336 insertions(+), 366 deletions(-) diff --git a/src/witness/myARG.ml b/src/witness/myARG.ml index 373a66d3d6..8b00328ed9 100644 --- a/src/witness/myARG.ml +++ b/src/witness/myARG.ml @@ -312,7 +312,7 @@ struct (* TODO: need to handle longer loops? *) begin match if_true_next_n, if_false_next_n with (* && *) - | Statement {sid=sid2; skind=If (_, _, _, loc2, eloc2); _}, _ when sid <> sid2 && loc = loc2 -> + | Statement {sid=sid2; skind=If (_, _, _, loc2, eloc2); _}, _ when sid <> sid2 && CilType.Location.equal loc loc2 -> (* get e2 from edge because recursive next returns it there *) let (e2, if_true_next_true_next_n, if_true_next_false_next_n) = partition_if_next (next if_true_next_n) in if is_equiv_chain if_false_next_n if_true_next_false_next_n then @@ -360,7 +360,7 @@ struct let next_opt' n = match n with | 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 + if CilType.Location.equal (Node.location if_true_next_n) loc && CilType.Location.equal (Node.location if_false_next_n) loc then match Arg.next if_true_next_n, Arg.next if_false_next_n with | [(Assign (v_true, e_true), if_true_next_next_n)], [(Assign (v_false, e_false), if_false_next_next_n)] when v_true = v_false && Node.equal if_true_next_next_n if_false_next_next_n -> let exp = ternary e_cond e_true e_false in diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c index 05b57988ee..434b6b29fb 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.c @@ -22,7 +22,7 @@ int main() } else { - __VERIFIER_assert(x != 0 && x != 2); // TODO: uncil broken + __VERIFIER_assert(x != 0 && x != 2); } } // TODO: double InlineReturn edge in two first cases? diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index 0bfd036693..07211fbc93 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -10,9 +10,9 @@ │ : │ : │ │ ┌·····························································┘ │ Entry main : Inlined Proc '__VERIFIER_assert(x == 0)' │ │ : ▼ ▼ │ - │ : InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ - │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀·········································· │ _ │ - │ │ : │ │ └─────────────────────┘ + │ : InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌────────────────────────────┐ + │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀·········································· │ _ │ + │ │ : │ │ └────────────────────────────┘ │ │ : InlineReturn │ │ ▲ │ │ : ┌─────────────────────────────────────────────────────────────────────▶ │ _ │ │ Test (x == 2,true) │ │ : │ │ │ │ @@ -68,23 +68,17 @@ │ │ _ │ │ : │ _ │ │ │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ │ │ │ : │ │ - │ │ Test (! cond,false) │ : │ Test (x != 0,true) │ + │ │ Test (! cond,false) │ : │ Assign 'tmp___0 = x != 0 && x != 2' │ │ ▼ │ : ▼ │ - │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ - │ │ _ │ │ : │ _ │ │ - │ └────────────────────────────────┘ │ : └────────────────────────────────────────┘ │ - │ │ │ : │ │ - │ │ Ret (None, __VERIFIER_assert) │ : │ Assign 'tmp___0 = x != 2' │ - │ ▼ │ : ▼ │ - │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ Assign 'tmp___0 = 1' │ - └─ │ _ │ ─┘ └·········································· │ _ │ ◀──────────────────────────────────────────────────────┼────────────────────────────────────────────┐ + │ ┌────────────────────────────────┐ │ : ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │ Assign 'tmp___0 = 1' ┌───┐ + │ │ _ │ │ └·········································· │ _ │ ◀┼──────────────────────────────────────────────────────────────────────────── │ _ │ + │ └────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ └───┘ + │ │ │ │ ▲ │ + │ │ Ret (None, __VERIFIER_assert) │ │ InlineEntry '(tmp___0)' └────┼────────────────────────────────────────────┐ + │ ▼ │ ▼ │ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ + └─ │ _ │ ─┘ │ _ │ │ │ └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ - │ │ │ - │ InlineEntry '(tmp___0)' │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ _ │ │ │ - └────────────────────────────────────────┘ │ │ │ │ │ │ Entry __VERIFIER_assert │ │ ▼ │ │ @@ -92,7 +86,7 @@ │ _ │ │ │ └────────────────────────────────────────┘ │ │ │ │ │ - │ Test (! cond,false) │ │ + │ Test (! cond,false) │ │ Assign 'tmp___0 = x != 2' ▼ │ │ ┌────────────────────────────────────────┐ │ │ │ _ │ │ │ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.c b/tests/sv-comp/cfg/join_true-unreach-call.c index b7f4d05506..999e0cd578 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.c +++ b/tests/sv-comp/cfg/join_true-unreach-call.c @@ -14,6 +14,6 @@ int main() x = 1; else x = 2; - __VERIFIER_assert(1 <= x && x <= 2); // TODO: uncil broken + __VERIFIER_assert(1 <= x && x <= 2); return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected index 10ebb0e289..c8224ce3f2 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -1,93 +1,87 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : -│ _ │ ◀────────────────────── │ _ │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,false) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 2' - │ ▼ - │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └─────────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = x <= 2' - ▼ -┌───┐ Assign 'tmp___0 = 1' ┌────────────────────────────────────────┐ -│ _ │ ──────────────────────▶ │ _ │ ·┐ -└───┘ └────────────────────────────────────────┘ : - │ : - │ InlineEntry '(tmp___0)' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (None, __VERIFIER_assert) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀─────────────────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └──────────────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1 <= x && x <= 2' + ▼ +┌───┐ Assign 'tmp___0 = x <= 2' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ _ │ ───────────────────────────▶ │ _ │ +└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ : ▲ + │ InlineEntry '(tmp___0)' : │ Assign 'tmp___0 = 1' + ▼ : │ + ┌────────────────────────────────────────┐ : ┌───────────────────────┐ + │ _ │ : │ _ │ + └────────────────────────────────────────┘ : └───────────────────────┘ + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : + ▼ : + ┌────────────────────────────────────────┐ : Inlined Proc '__VERIFIER_assert(tmp___0)' + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.c b/tests/sv-comp/cfg/region_global_init_true-unreach-call.c index 5c4a5a0b27..8db9193806 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.c +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.c @@ -22,6 +22,6 @@ int main() x = 1; else x = 2; - __VERIFIER_assert(1 <= x && x <= 2); // TODO: uncil broken + __VERIFIER_assert(1 <= x && x <= 2); return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected index 10ebb0e289..c8224ce3f2 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -1,93 +1,87 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : -│ _ │ ◀────────────────────── │ _ │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,false) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 2' - │ ▼ - │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └─────────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (1 <= x,true) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = x <= 2' - ▼ -┌───┐ Assign 'tmp___0 = 1' ┌────────────────────────────────────────┐ -│ _ │ ──────────────────────▶ │ _ │ ·┐ -└───┘ └────────────────────────────────────────┘ : - │ : - │ InlineEntry '(tmp___0)' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (None, __VERIFIER_assert) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀─────────────────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └──────────────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1 <= x && x <= 2' + ▼ +┌───┐ Assign 'tmp___0 = x <= 2' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ _ │ ───────────────────────────▶ │ _ │ +└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ : ▲ + │ InlineEntry '(tmp___0)' : │ Assign 'tmp___0 = 1' + ▼ : │ + ┌────────────────────────────────────────┐ : ┌───────────────────────┐ + │ _ │ : │ _ │ + └────────────────────────────────────────┘ : └───────────────────────┘ + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : + ▼ : + ┌────────────────────────────────────────┐ : Inlined Proc '__VERIFIER_assert(tmp___0)' + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected index 653edd1389..ed5148ae0b 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -1,81 +1,75 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌─────────────────────┐ Test (x > 0,false) ┌────────────────────────────────────────┐ - ┌──────────────────▶ │ _ │ ◀────────────────────── │ _ │ - │ └─────────────────────┘ └────────────────────────────────────────┘ - │ │ │ - │ Test (x < 2,false) │ │ Test (x > 0,true) - │ │ ▼ - │ │ ┌────────────────────────────────────────┐ - └──────────────────────┼──────────────────────────────────────────── │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Test (x < 2,true) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'tmp___0 = 1' - │ ▼ - │ Assign 'tmp___0 = 0' ┌────────────────────────────────────────┐ - └───────────────────────────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'y = tmp___0' - ▼ - ┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ - │ _ │ ◀────────────────────── │ _ │ - └─────────────────────┘ └────────────────────────────────────────┘ - │ │ - │ Ret (Some 0, main) │ Test (y,true) - ▼ ▼ - ┌─────────────────────┐ ┌────────────────────────────────────────┐ - │ _ │ │ _ │ - └─────────────────────┘ └────────────────────────────────────────┘ - │ - │ InlineEntry '()' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry __VERIFIER_error - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + ┌──────────────────────────────────────────────────────────────────────────── │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Test (x > 0 && x < 2,true) + │ ▼ + │ ┌─────────────────────┐ Test (x < 2,true) ┌────────────────────────────────────────┐ + │ Test (x > 0 && x < 2,false) │ _ │ ──────────────────────▶ │ _ │ + │ └─────────────────────┘ └────────────────────────────────────────┘ + │ │ │ + │ │ Test (x < 2,false) │ Assign 'tmp___0 = 1' + │ ▼ ▼ + │ ┌─────────────────────┐ Assign 'tmp___0 = 0' ┌────────────────────────────────────────┐ + └───────────────────────────▶ │ _ │ ──────────────────────▶ │ _ │ + └─────────────────────┘ └────────────────────────────────────────┘ + │ + │ Assign 'y = tmp___0' + ▼ + ┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ + │ _ │ ◀────────────────────── │ _ │ + └─────────────────────┘ └────────────────────────────────────────┘ + │ │ + │ Ret (Some 0, main) │ Test (y,true) + ▼ ▼ + ┌─────────────────────┐ ┌────────────────────────────────────────┐ + │ _ │ │ _ │ + └─────────────────────┘ └────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected index 9b8bc097c3..1a5a3ea163 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -1,75 +1,69 @@ -┌────────────────────────────────────────┐ -│ _ │ -└────────────────────────────────────────┘ - │ - │ Entry main - ▼ -┌────────────────────────────────────────┐ -│ _ │ ·┐ -└────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : -┌────────────────────────────────────────┐ : -│ _ │ : -└────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : -┌────────────────────────────────────────┐ : -│ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' -└────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : -┌────────────────────────────────────────┐ : -│ _ │ : -└────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌────────────────────────────────────────┐ : -│ _ │ ◀┘ -└────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ -┌────────────────────────────────────────┐ -│ _ │ ─┐ -└────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0,true) │ - ▼ │ -┌────────────────────────────────────────┐ │ -│ _ │ │ Test (x > 0,false) -└────────────────────────────────────────┘ │ - │ │ - │ Test (x < 0,false) │ - ▼ │ -┌────────────────────────────────────────┐ │ -│ _ │ ◀┘ -└────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 0' - ▼ -┌────────────────────────────────────────┐ -│ _ │ -└────────────────────────────────────────┘ - │ - │ Assign 'y = tmp___0' - ▼ -┌────────────────────────────────────────┐ -│ _ │ -└────────────────────────────────────────┘ - │ - │ Test (y,false) - ▼ -┌────────────────────────────────────────┐ -│ _ │ -└────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ -┌────────────────────────────────────────┐ -│ _ │ -└────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (x > 0 && x < 0,false) + ▼ +┌───┐ Test (x < 0,false) ┌────────────────────────────────────────┐ +│ _ │ ────────────────────▶ │ _ │ +└───┘ └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 0' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'y = tmp___0' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (y,false) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ From d2492516bcd3a11a091a46e69b42a4baa38f8fbd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 12:14:53 +0300 Subject: [PATCH 187/689] Fix more broken ARG uncil transformation due to location equality Was comparing loc with eloc. --- src/witness/myARG.ml | 10 +- .../cfg/uncil/and_var_false-unreach-call.c | 2 +- .../uncil/and_var_false-unreach-call.expected | 144 +++++++++--------- .../cfg/uncil/and_var_true-unreach-call.c | 2 +- .../uncil/and_var_true-unreach-call.expected | 132 ++++++++-------- 5 files changed, 140 insertions(+), 150 deletions(-) diff --git a/src/witness/myARG.ml b/src/witness/myARG.ml index 8b00328ed9..a4ab524a0e 100644 --- a/src/witness/myARG.ml +++ b/src/witness/myARG.ml @@ -305,14 +305,15 @@ struct let rec next_opt' n = match n with - | Statement {sid; skind=If (_, _, _, loc, eloc); _} when GobConfig.get_bool "witness.graphml.uncil" -> (* TODO: use elocs instead? *) + | Statement {sid; skind=If _; _} when GobConfig.get_bool "witness.graphml.uncil" -> 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? *) (* TODO: need to handle longer loops? *) + let loc = Node.location n in begin match if_true_next_n, if_false_next_n with (* && *) - | Statement {sid=sid2; skind=If (_, _, _, loc2, eloc2); _}, _ when sid <> sid2 && CilType.Location.equal loc loc2 -> + | Statement {sid=sid2; skind=If _; _}, _ when sid <> sid2 && CilType.Location.equal loc (Node.location if_true_next_n) -> (* get e2 from edge because recursive next returns it there *) let (e2, if_true_next_true_next_n, if_true_next_false_next_n) = partition_if_next (next if_true_next_n) in if is_equiv_chain if_false_next_n if_true_next_false_next_n then @@ -324,7 +325,7 @@ struct else None (* || *) - | _, Statement {sid=sid2; skind=If (_, _, _, loc2, eloc2); _} when sid <> sid2 && loc = loc2 -> + | _, Statement {sid=sid2; skind=If _; _} when sid <> sid2 && CilType.Location.equal loc (Node.location if_false_next_n) -> (* get e2 from edge because recursive next returns it there *) let (e2, if_false_next_true_next_n, if_false_next_false_next_n) = partition_if_next (next if_false_next_n) in if is_equiv_chain if_true_next_n if_false_next_true_next_n then @@ -358,8 +359,9 @@ 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.graphml.uncil" -> (* TODO: use eloc instead? *) + | Statement {skind=If _; _} when GobConfig.get_bool "witness.graphml.uncil" -> let (e_cond, if_true_next_n, if_false_next_n) = partition_if_next (Arg.next n) in + let loc = Node.location n in if CilType.Location.equal (Node.location if_true_next_n) loc && CilType.Location.equal (Node.location if_false_next_n) loc then match Arg.next if_true_next_n, Arg.next if_false_next_n with | [(Assign (v_true, e_true), if_true_next_next_n)], [(Assign (v_false, e_false), if_false_next_next_n)] when v_true = v_false && Node.equal if_true_next_next_n if_false_next_next_n -> diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c index 11fa23dbdc..ab5a339d19 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.c @@ -10,7 +10,7 @@ void __VERIFIER_assert(int cond) { int main() { int x = __VERIFIER_nondet_int(); - int y = x > 0 && x < 2; // TODO: uncil broken + int y = x > 0 && x < 2; if (y) __VERIFIER_error(); return 0; diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected index ed5148ae0b..f760dec0c8 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -1,75 +1,69 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - ┌──────────────────────────────────────────────────────────────────────────── │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Test (x > 0 && x < 2,true) - │ ▼ - │ ┌─────────────────────┐ Test (x < 2,true) ┌────────────────────────────────────────┐ - │ Test (x > 0 && x < 2,false) │ _ │ ──────────────────────▶ │ _ │ - │ └─────────────────────┘ └────────────────────────────────────────┘ - │ │ │ - │ │ Test (x < 2,false) │ Assign 'tmp___0 = 1' - │ ▼ ▼ - │ ┌─────────────────────┐ Assign 'tmp___0 = 0' ┌────────────────────────────────────────┐ - └───────────────────────────▶ │ _ │ ──────────────────────▶ │ _ │ - └─────────────────────┘ └────────────────────────────────────────┘ - │ - │ Assign 'y = tmp___0' - ▼ - ┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ - │ _ │ ◀────────────────────── │ _ │ - └─────────────────────┘ └────────────────────────────────────────┘ - │ │ - │ Ret (Some 0, main) │ Test (y,true) - ▼ ▼ - ┌─────────────────────┐ ┌────────────────────────────────────────┐ - │ _ │ │ _ │ - └─────────────────────┘ └────────────────────────────────────────┘ - │ - │ InlineEntry '()' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry __VERIFIER_error - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = x > 0 && x < 2' + ▼ +┌─────────────────────┐ Assign 'tmp___0 = 1' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ Assign 'tmp___0 = 0' ┌───┐ +│ _ │ ──────────────────────▶ │ _ │ ◀────────────────────── │ _ │ +└─────────────────────┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └───┘ + │ ▲ + │ Assign 'y = tmp___0' │ Assign 'tmp___0 = x < 2' + ▼ │ +┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ ┌───────────────────────────┐ +│ _ │ ◀────────────────────── │ _ │ │ _ │ +└─────────────────────┘ └────────────────────────────────────────┘ └───────────────────────────┘ + │ │ + │ Ret (Some 0, main) │ Test (y,true) + ▼ ▼ +┌─────────────────────┐ ┌────────────────────────────────────────┐ +│ _ │ │ _ │ +└─────────────────────┘ └────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c index a43228214c..4437139c87 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.c @@ -10,7 +10,7 @@ void __VERIFIER_assert(int cond) { int main() { int x = __VERIFIER_nondet_int(); - int y = x > 0 && x < 0; // TODO: uncil broken + int y = x > 0 && x < 0; if (y) __VERIFIER_error(); return 0; diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected index 1a5a3ea163..8256383932 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -1,69 +1,63 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (x > 0 && x < 0,false) - ▼ -┌───┐ Test (x < 0,false) ┌────────────────────────────────────────┐ -│ _ │ ────────────────────▶ │ _ │ -└───┘ └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 0' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'y = tmp___0' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (y,false) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = x > 0 && x < 0' + ▼ +┌───┐ Assign 'tmp___0 = x < 0' ┌────────────────────────────────────────┐ Assign 'tmp___0 = 0' ┌───┐ +│ _ │ ──────────────────────────▶ │ _ │ ◀────────────────────────────────────────────── │ _ │ +└───┘ └────────────────────────────────────────┘ └───┘ + │ + │ Assign 'y = tmp___0' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Test (y,false) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ From 407ad5f93611dd72a16b45d55fbe26df05db0fec Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 17 May 2024 11:36:02 +0200 Subject: [PATCH 188/689] Union: `meet` in `Field`: Do not raise `Uncomparable` when one arg is `Top` --- src/cdomain/value/cdomains/unionDomain.ml | 5 +++- tests/regression/13-privatized/90-union.c | 29 +++++++++++++++++++ .../13-privatized/91-union-direct.c | 26 +++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/regression/13-privatized/90-union.c create mode 100644 tests/regression/13-privatized/91-union-direct.c diff --git a/src/cdomain/value/cdomains/unionDomain.ml b/src/cdomain/value/cdomains/unionDomain.ml index ad5c531061..b5e1b3bae0 100644 --- a/src/cdomain/value/cdomains/unionDomain.ml +++ b/src/cdomain/value/cdomains/unionDomain.ml @@ -26,7 +26,10 @@ module Field = struct if equal f g then f else - raise Lattice.Uncomparable + match f, g with + | `Top, f + | f, `Top -> f + | _ -> raise Lattice.Uncomparable end module Simple (Values: Arg) = diff --git a/tests/regression/13-privatized/90-union.c b/tests/regression/13-privatized/90-union.c new file mode 100644 index 0000000000..df5990d7a4 --- /dev/null +++ b/tests/regression/13-privatized/90-union.c @@ -0,0 +1,29 @@ +// PARAM: --set ana.base.privatization write +#include +#include +#include +union g { + int h; + int i; +}; +struct j { + union g data; +}; + + +void* af(void* arg) { + int top; + struct j* jptr = (struct j*) malloc(sizeof(struct j)); + memset(jptr, 0, sizeof(struct j)); + + while (top) { + if (jptr->data.i); + + __goblint_check(jptr->data.i == 0); // Should alo work for write! + } +} + +void main() { + pthread_t ah; + pthread_create(&ah, 0, af, 0); +} diff --git a/tests/regression/13-privatized/91-union-direct.c b/tests/regression/13-privatized/91-union-direct.c new file mode 100644 index 0000000000..bf1127d389 --- /dev/null +++ b/tests/regression/13-privatized/91-union-direct.c @@ -0,0 +1,26 @@ +// PARAM: --set ana.base.privatization write +#include +#include +#include +union g { + int h; + int i; +}; + +void* af(void* arg) { + // Go MT +} + +void main() { + pthread_t ah; + pthread_create(&ah, 0, af, 0); + + int top; + union g* jptr = (union g*) malloc(sizeof(union g)); + memset(jptr, 0, sizeof(union g)); + + while (top) { + if (jptr->i); + __goblint_check(jptr->i == 0); // Should alo work for write! + } +} From 0c1fb487ee144ec782902b5cde7e155823372be2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 12:42:01 +0300 Subject: [PATCH 189/689] Prune unreachable nodes from ARG after uncil --- src/witness/argTools.ml | 22 ++- ...xclude_multiple_true-unreach-call.expected | 61 +++--- .../cfg/free_spawn_true-unreach-call.c | 1 - .../cfg/free_spawn_true-unreach-call.expected | 152 ++++++++------- .../cfg/join_true-unreach-call.expected | 174 +++++++++--------- ...ion_global_init_true-unreach-call.expected | 174 +++++++++--------- .../cfg/uncil/and3_true-unreach-call.expected | 162 ++++++++-------- .../uncil/and3dead_true-unreach-call.expected | 162 ++++++++-------- .../cfg/uncil/and_copy_true-unreach-call.c | 1 - .../uncil/and_copy_true-unreach-call.expected | 165 +++++++++-------- ..._join_invariant_true-unreach-call.expected | 164 +++++++++-------- .../cfg/uncil/and_true-unreach-call.expected | 162 ++++++++-------- .../uncil/and_var_false-unreach-call.expected | 138 +++++++------- .../uncil/and_var_true-unreach-call.expected | 126 ++++++------- .../cfg/uncil/or3_true-unreach-call.expected | 162 ++++++++-------- .../uncil/or3dead_true-unreach-call.expected | 162 ++++++++-------- .../cfg/uncil/or_true-unreach-call.expected | 162 ++++++++-------- 17 files changed, 1080 insertions(+), 1070 deletions(-) diff --git a/src/witness/argTools.ml b/src/witness/argTools.ml index 1fd1e32e4f..ae9276be97 100644 --- a/src/witness/argTools.ml +++ b/src/witness/argTools.ml @@ -162,11 +162,23 @@ struct include Intra (ArgIntra) (Arg) let prev = witness_prev - let iter_nodes f = - f main_entry; - NHT.iter (fun n _ -> - f n - ) witness_prev_map + + (** Iterate over {e reachable} nodes. *) + let iter_nodes (f: Node.t -> unit): unit = + let reachable = NHT.create (NHT.length witness_prev_map) in + + (* DFS *) + let rec iter_node node = + if not (NHT.mem reachable node) then ( + NHT.replace reachable node (); + f node; + List.iter (fun (edge, to_node) -> + iter_node to_node + ) (next node) (* use included next, not Arg.next, to prune uncilled nodes *) + ) + in + + iter_node main_entry let query ((n, c, i): Node.t) q = R.ask_local (n, c) (PathQuery (i, q)) diff --git a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected index 07211fbc93..b94f7fec7e 100644 --- a/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected +++ b/tests/sv-comp/basic/if_trier_exclude_multiple_true-unreach-call.expected @@ -10,9 +10,9 @@ │ : │ : │ │ ┌·····························································┘ │ Entry main : Inlined Proc '__VERIFIER_assert(x == 0)' │ │ : ▼ ▼ │ - │ : InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌────────────────────────────┐ - │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀·········································· │ _ │ - │ │ : │ │ └────────────────────────────┘ + │ : InlineReturn ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ Inlined Proc '__VERIFIER_assert(x == 2)' ┌─────────────────────┐ + │ ┌────┼───────────────────────────────────────────────────────────────────────────────────────────────────────▶ │ │ ◀·········································· │ _ │ + │ │ : │ │ └─────────────────────┘ │ │ : InlineReturn │ │ ▲ │ │ : ┌─────────────────────────────────────────────────────────────────────▶ │ _ │ │ Test (x == 2,true) │ │ : │ │ │ │ @@ -70,33 +70,30 @@ │ │ │ : │ │ │ │ Test (! cond,false) │ : │ Assign 'tmp___0 = x != 0 && x != 2' │ │ ▼ │ : ▼ │ - │ ┌────────────────────────────────┐ │ : ┌──────────────────────────────────────────────────────────────────────────────────────────────┐ │ Assign 'tmp___0 = 1' ┌───┐ - │ │ _ │ │ └·········································· │ _ │ ◀┼──────────────────────────────────────────────────────────────────────────── │ _ │ - │ └────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────────────────────────────┘ │ └───┘ - │ │ │ │ ▲ │ - │ │ Ret (None, __VERIFIER_assert) │ │ InlineEntry '(tmp___0)' └────┼────────────────────────────────────────────┐ - │ ▼ │ ▼ │ │ - │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ │ - └─ │ _ │ ─┘ │ _ │ │ │ - └────────────────────────────────┘ └────────────────────────────────────────┘ │ │ - │ │ │ - │ Entry __VERIFIER_assert │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ _ │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Test (! cond,false) │ │ Assign 'tmp___0 = x != 2' - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ _ │ │ │ - └────────────────────────────────────────┘ │ │ - │ │ │ - │ Ret (None, __VERIFIER_assert) │ │ - ▼ │ │ - ┌────────────────────────────────────────┐ │ │ - │ _ │ ───────────────────────────────────────────────────────┘ │ - └────────────────────────────────────────┘ │ - ┌────────────────────────────────────────┐ │ - │ _ │ ────────────────────────────────────────────────────────────────────────────────────────────────────┘ + │ ┌────────────────────────────────┐ │ : ┌────────────────────────────────────────┐ │ + │ │ _ │ │ └·········································· │ _ │ │ + │ └────────────────────────────────┘ │ └────────────────────────────────────────┘ │ + │ │ │ │ │ + │ │ Ret (None, __VERIFIER_assert) │ │ InlineEntry '(tmp___0)' │ + │ ▼ │ ▼ │ + │ ┌────────────────────────────────┐ │ ┌────────────────────────────────────────┐ │ + └─ │ _ │ ─┘ │ _ │ │ + └────────────────────────────────┘ └────────────────────────────────────────┘ │ + │ │ + │ Entry __VERIFIER_assert │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Test (! cond,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ │ + └────────────────────────────────────────┘ │ + │ │ + │ Ret (None, __VERIFIER_assert) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + │ _ │ ───────────────────────────────────────────────────────┘ └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.c b/tests/sv-comp/cfg/free_spawn_true-unreach-call.c index d05d83e337..115f252481 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.c +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.c @@ -15,7 +15,6 @@ int main() else p = &foo; // actually dead - // TODO: uncil false branch missing free(p); // TODO: free shouldn't spawn return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected index 90b4f2140f..5b6b9bfe95 100644 --- a/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected +++ b/tests/sv-comp/cfg/free_spawn_true-unreach-call.expected @@ -1,77 +1,75 @@ - ┌────────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────────┘ - │ - │ Assign 'p = (void *)0' - ▼ - ┌────────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - ▼ : - ┌────────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────────┘ - │ - │ Assign 'x = tmp ' - ▼ - ┌────────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────────┘ - │ - │ Test (x == 0 || (x == 1 || x == -1),true) - ▼ - ┌─────────────────────────────────┐ Test (x == 1 || x == -1,true) ┌────────────────────────────────────────────┐ Test (x == -1,true) ┌───┐ - │ _ │ ───────────────────────────────▶ │ _ │ ◀────────────────────────────────────────────── │ _ │ - └─────────────────────────────────┘ └────────────────────────────────────────────┘ └───┘ - │ │ │ - │ Test (x == 1 || x == -1,false) │ Proc 'tmp___0 = malloc(1)' │ - ▼ ▼ │ - ┌─────────────────────────────────┐ ┌────────────────────────────────────────────┐ │ - ┌────────────────────▶ │ _ │ │ _ │ │ - │ └─────────────────────────────────┘ └────────────────────────────────────────────┘ │ - │ │ │ │ - │ Test (x == -1,false) │ │ Assign 'p = (void *)tmp___0' │ - │ │ ▼ │ - │ │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────────┐ │ - │ └────────────────────────────────────────────────────────────────▶ │ _ │ │ - │ └────────────────────────────────────────────┘ │ - │ │ │ - │ │ Proc 'free(p)' │ - │ ▼ │ - │ ┌────────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────────┘ │ - │ │ │ - │ │ Ret (Some 0, main) │ - │ ▼ │ - │ ┌────────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────────┘ │ - │ │ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ + │ + │ Assign 'p = (void *)0' + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────────┘ + │ + │ Assign 'x = tmp ' + ▼ +┌───┐ Test (x == 0 || (x == 1 || x == -1),false) ┌────────────────────────────────────────────┐ +│ _ │ ◀──────────────────────────────────────────── │ _ │ +└───┘ └────────────────────────────────────────────┘ + │ │ + │ │ Test (x == 0 || (x == 1 || x == -1),true) + │ ▼ + │ ┌────────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────────┘ + │ │ + │ │ Proc 'tmp___0 = malloc(1)' + │ ▼ + │ ┌────────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────────┘ + │ │ + │ │ Assign 'p = (void *)tmp___0' + │ ▼ + │ Assign 'p = (void *)(& foo)' ┌────────────────────────────────────────────┐ + └───────────────────────────────────────────────▶ │ _ │ + └────────────────────────────────────────────┘ + │ + │ Proc 'free(p)' + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/join_true-unreach-call.expected b/tests/sv-comp/cfg/join_true-unreach-call.expected index c8224ce3f2..c882471576 100644 --- a/tests/sv-comp/cfg/join_true-unreach-call.expected +++ b/tests/sv-comp/cfg/join_true-unreach-call.expected @@ -1,87 +1,87 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : -│ _ │ ◀─────────────────────────── │ _ │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,false) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 2' - │ ▼ - │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └──────────────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1 <= x && x <= 2' - ▼ -┌───┐ Assign 'tmp___0 = x <= 2' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ _ │ ───────────────────────────▶ │ _ │ -└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ : ▲ - │ InlineEntry '(tmp___0)' : │ Assign 'tmp___0 = 1' - ▼ : │ - ┌────────────────────────────────────────┐ : ┌───────────────────────┐ - │ _ │ : │ _ │ - └────────────────────────────────────────┘ : └───────────────────────┘ - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Test (! cond,false) : - ▼ : - ┌────────────────────────────────────────┐ : Inlined Proc '__VERIFIER_assert(tmp___0)' - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (None, __VERIFIER_assert) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀───────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1 <= x && x <= 2' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(tmp___0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected index c8224ce3f2..c882471576 100644 --- a/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected +++ b/tests/sv-comp/cfg/region_global_init_true-unreach-call.expected @@ -1,87 +1,87 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : -┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : -│ _ │ ◀─────────────────────────── │ _ │ ◀┘ -└───┘ └────────────────────────────────────────┘ - │ │ - │ │ Test (tmp,false) - │ ▼ - │ ┌────────────────────────────────────────┐ - │ │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Assign 'x = 2' - │ ▼ - │ Assign 'x = 1' ┌────────────────────────────────────────┐ - └──────────────────────────────▶ │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = 1 <= x && x <= 2' - ▼ -┌───┐ Assign 'tmp___0 = x <= 2' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ -│ _ │ ───────────────────────────▶ │ _ │ -└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ : ▲ - │ InlineEntry '(tmp___0)' : │ Assign 'tmp___0 = 1' - ▼ : │ - ┌────────────────────────────────────────┐ : ┌───────────────────────┐ - │ _ │ : │ _ │ - └────────────────────────────────────────┘ : └───────────────────────┘ - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Test (! cond,false) : - ▼ : - ┌────────────────────────────────────────┐ : Inlined Proc '__VERIFIER_assert(tmp___0)' - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (None, __VERIFIER_assert) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌───┐ Test (tmp,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀───────────────── │ _ │ ◀┘ +└───┘ └────────────────────────────────────────┘ + │ │ + │ │ Test (tmp,false) + │ ▼ + │ ┌────────────────────────────────────────┐ + │ │ _ │ + │ └────────────────────────────────────────┘ + │ │ + │ │ Assign 'x = 2' + │ ▼ + │ Assign 'x = 1' ┌────────────────────────────────────────┐ + └────────────────────▶ │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = 1 <= x && x <= 2' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(tmp___0)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_assert : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(tmp___0)' + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Ret (None, __VERIFIER_assert) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected index a6a12c4c2f..611e3e8f83 100644 --- a/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3_true-unreach-call.expected @@ -1,81 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ─────────────────────────────────────────────────────────────────────────┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0 && (x < 3 && x < 2),true) │ - ▼ │ -┌───┐ Test (x < 3 && x < 2,true) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ -│ _ │ ─────────────────────────────▶ │ _ │ │ -└───┘ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ : ▲ │ - │ │ InlineEntry '(x == 1)' : │ Test (x < 2,true) │ - │ ▼ : │ │ - │ ┌────────────────────────────────────────┐ : ┌─────────────────────┐ │ - │ │ _ │ : │ _ │ │ - │ └────────────────────────────────────────┘ : └─────────────────────┘ │ - │ │ : │ │ - │ │ Entry __VERIFIER_assert : │ │ - │ ▼ : │ │ - │ ┌────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ Test (x > 0 && (x < 3 && x < 2),false) - │ └────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Test (! cond,false) : │ │ - │ ▼ : │ │ - │ ┌────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Ret (None, __VERIFIER_assert) : │ │ - │ ▼ : │ │ - │ ┌────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x < 2,false) │ - │ ▼ ▼ ▼ │ - │ Test (x < 3 && x < 2,false) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - └────────────────────────────────▶ │ _ │ ◀┘ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0 && (x < 3 && x < 2),true) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌········································· │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ InlineEntry '(x == 1)' │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Entry __VERIFIER_assert │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ Test (x > 0 && (x < 3 && x < 2),false) + : └────────────────────────────────────────┘ │ + : │ │ + : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (! cond,false) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Ret (None, __VERIFIER_assert) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ InlineReturn │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + └········································▶ │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected index 19d7e2fb3d..040699c7f5 100644 --- a/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and3dead_true-unreach-call.expected @@ -1,81 +1,81 @@ - ┌─────────────────────────────────────────┐ - │ _ │ - └─────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌─────────────────────────────────────────┐ - │ _ │ ·┐ - └─────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ : - └─────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └─────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ : - └─────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ ◀┘ - └─────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌─────────────────────────────────────────┐ - │ _ │ ──────────────────────────────────────────────────────────────────────────┐ - └─────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0 && (x < 3 && x == 1),true) │ - ▼ │ -┌───┐ Test (x < 3 && x == 1,true) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ -│ _ │ ──────────────────────────────▶ │ _ │ │ -└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ : ▲ │ - │ │ InlineEntry '(x == 1)' : │ Test (x == 1,true) │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : ┌──────────────────────┐ │ - │ │ _ │ : │ _ │ │ - │ └─────────────────────────────────────────┘ : └──────────────────────┘ │ - │ │ : │ │ - │ │ Entry __VERIFIER_assert : │ │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ Test (x > 0 && (x < 3 && x == 1),false) - │ └─────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Test (! cond,false) : │ │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └─────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Ret (None, __VERIFIER_assert) : │ │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └─────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x == 1,false) │ - │ ▼ ▼ ▼ │ - │ Test (x < 3 && x == 1,false) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - └─────────────────────────────────▶ │ _ │ ◀┘ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌─────────────────────────────────────────┐ - │ _ │ - └─────────────────────────────────────────┘ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ·┐ + └─────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └─────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ─┐ + └─────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0 && (x < 3 && x == 1),true) │ + ▼ │ + ┌─────────────────────────────────────────┐ │ + ┌········································· │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ InlineEntry '(x == 1)' │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ Entry __VERIFIER_assert │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ Test (x > 0 && (x < 3 && x == 1),false) + : └─────────────────────────────────────────┘ │ + : │ │ + : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (! cond,false) │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ Ret (None, __VERIFIER_assert) │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ InlineReturn │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + └········································▶ │ _ │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c index 7b7f151489..b924f4cd8b 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.c @@ -18,6 +18,5 @@ int main() __VERIFIER_assert(1); return 1; } - // TODO: uncil false branch missing return 0; } \ No newline at end of file diff --git a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected index c7be30aff3..277fb8785c 100644 --- a/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_copy_true-unreach-call.expected @@ -1,81 +1,84 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (x > 0 && x < 2,true) - ▼ - ┌────────────────────────────────┐ Test (x < 2,true) ┌────────────────────────────────────────┐ - │ _ │ ────────────────────▶ │ _ │ ·┐ - └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ Test (x < 2,false) │ InlineEntry '(x == 1)' : - ▼ ▼ : - ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - ┌···································· │ _ │ │ _ │ : - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ InlineEntry '(1)' │ Entry __VERIFIER_assert : - : ▼ ▼ : - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - : │ _ │ │ _ │ : - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ Entry __VERIFIER_assert │ Test (! cond,false) : - : ▼ ▼ : - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - : │ _ │ │ _ │ : - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ Test (! cond,false) │ Ret (None, __VERIFIER_assert) : - : ▼ ▼ : - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - : │ _ │ │ _ │ : - : └────────────────────────────────┘ └────────────────────────────────────────┘ : - : │ │ : - : │ Ret (None, __VERIFIER_assert) │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' - : ▼ ▼ : - : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - : │ _ │ │ _ │ ◀┘ - : └────────────────────────────────┘ └────────────────────────────────────────┘ - : │ │ - : Inlined Proc '__VERIFIER_assert(1)' │ InlineReturn │ Ret (Some 0, main) - : ▼ ▼ - : ┌────────────────────────────────┐ Ret (Some 1, main) ┌────────────────────────────────────────┐ - └···································▶ │ _ │ ────────────────────▶ │ _ │ - └────────────────────────────────┘ └────────────────────────────────────────┘ + + ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Entry main │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ ·┐ │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '()' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Entry __VERIFIER_nondet_int : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (Some val, __VERIFIER_nondet_int) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn 'tmp' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ Test (x > 0 && x < 2,false) │ Assign 'x = tmp' │ + ▼ ▼ │ +┌────────────────────────────────┐ ┌────────────────────────────────────────┐ │ +│ _ │ ·┐ │ _ │ ──────────────────────────────────────────────────┘ +└────────────────────────────────┘ : └────────────────────────────────────────┘ + │ : │ + │ InlineEntry '(1)' : │ Test (x > 0 && x < 2,true) + ▼ : ▼ +┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ +│ _ │ : │ _ │ ·┐ +└────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ Entry __VERIFIER_assert : │ InlineEntry '(x == 1)' : + ▼ : ▼ : +┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : +│ _ │ : │ _ │ : +└────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(1)' │ Entry __VERIFIER_assert : + ▼ : ▼ : +┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : +│ _ │ : │ _ │ : +└────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ Ret (None, __VERIFIER_assert) : │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(x == 1)' + ▼ : ▼ : +┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : +│ _ │ : │ _ │ : +└────────────────────────────────┘ : └────────────────────────────────────────┘ : + │ : │ : + │ InlineReturn : │ Ret (None, __VERIFIER_assert) : + ▼ : ▼ : +┌────────────────────────────────┐ : ┌────────────────────────────────────────┐ : +│ _ │ ◀┘ │ _ │ : +└────────────────────────────────┘ └────────────────────────────────────────┘ : + │ │ : + │ │ InlineReturn : + │ ▼ : + │ ┌────────────────────────────────────────┐ : + │ │ _ │ ◀┘ + │ └────────────────────────────────────────┘ + │ │ + │ │ Ret (Some 0, main) + │ ▼ + │ Ret (Some 1, main) ┌────────────────────────────────────────┐ + └─────────────────────────────────────────────────────────────────────▶ │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected index 2aa0dc7973..b9b2de3852 100644 --- a/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_join_invariant_true-unreach-call.expected @@ -1,81 +1,83 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - ┌──────────────────────────────────────────────────────────────────────────────────── │ _ │ - │ └────────────────────────────────────────┘ - │ │ - │ │ Test (x > 0 && x < 2,true) - │ ▼ - │ ┌────────────────────────────────┐ Test (x < 2,true) ┌────────────────────────────────────────┐ - │ │ _ │ ───────────────────▶ │ _ │ ·┐ - │ └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ │ : - │ Test (x > 0 && x < 2,false) │ Test (x < 2,false) │ InlineEntry '(x == 1)' : - │ ▼ ▼ : - │ ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - └───────────────────────────▶ │ _ │ │ _ │ : - └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ InlineEntry '(1)' │ Entry __VERIFIER_assert : - ▼ ▼ : - ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - │ _ │ │ _ │ : - └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ Entry __VERIFIER_assert │ Test (! cond,false) : - ▼ ▼ : - ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - │ _ │ │ _ │ : - └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ Test (! cond,false) │ Ret (None, __VERIFIER_assert) : - ▼ ▼ : - ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : - │ _ │ │ _ │ : - └────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ Ret (None, __VERIFIER_assert) │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' - ▼ ▼ ▼ - ┌────────────────────────────────┐ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ - │ _ │ ───────────────────▶ │ _ │ - └────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────┐ Test (x > 0 && x < 2,false) ┌────────────────────────────────────────┐ + ┌· │ _ │ ◀───────────────────────────── │ _ │ + : └────────────────────────────────┘ └────────────────────────────────────────┘ + : │ │ + : │ InlineEntry '(1)' │ Test (x > 0 && x < 2,true) + : ▼ ▼ + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ + : │ _ │ │ _ │ ·┐ + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Entry __VERIFIER_assert │ InlineEntry '(x == 1)' : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Test (! cond,false) │ Entry __VERIFIER_assert : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ Ret (None, __VERIFIER_assert) │ Test (! cond,false) : + : ▼ ▼ : + : ┌────────────────────────────────┐ ┌────────────────────────────────────────┐ : + : │ _ │ │ _ │ : + : └────────────────────────────────┘ └────────────────────────────────────────┘ : + : │ │ : + : │ │ Ret (None, __VERIFIER_assert) : + : │ ▼ : + : │ ┌────────────────────────────────────────┐ : + : │ │ _ │ : + : │ └────────────────────────────────────────┘ : + : │ │ : + : │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' + : │ ▼ ▼ + : │ InlineReturn ┌─────────────────────────────────────────────────────────────────────────────────────────┐ + : └─────────────────────────────────────────────────────────────▶ │ _ │ + : └─────────────────────────────────────────────────────────────────────────────────────────┘ + : │ ▲ + : │ Ret (Some 0, main) : Inlined Proc '__VERIFIER_assert(1)' + : ▼ : + : ┌────────────────────────────────────────┐ : + : │ _ │ : + : └────────────────────────────────────────┘ : + : : + └················································································································┘ diff --git a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected index 0da5ff4129..59fc453f85 100644 --- a/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_true-unreach-call.expected @@ -1,81 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ──────────────────────────────────────────────────┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x > 0 && x < 2,true) │ - ▼ │ -┌───┐ Test (x < 2,true) ┌────────────────────────────────────────┐ │ -│ _ │ ────────────────────▶ │ _ │ ·┐ │ -└───┘ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineEntry '(x == 1)' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Entry __VERIFIER_assert : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Test (! cond,false) : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Ret (None, __VERIFIER_assert) : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x > 0 && x < 2,false) - │ ▼ ▼ ▼ - │ Test (x < 2,false) ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └───────────────────────▶ │ _ │ - └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x > 0 && x < 2,true) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌········································· │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ InlineEntry '(x == 1)' │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Entry __VERIFIER_assert │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ Test (x > 0 && x < 2,false) + : └────────────────────────────────────────┘ │ + : │ │ + : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (! cond,false) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Ret (None, __VERIFIER_assert) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ InlineReturn │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + └········································▶ │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected index f760dec0c8..ae3e5e575b 100644 --- a/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_false-unreach-call.expected @@ -1,69 +1,69 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = x > 0 && x < 2' - ▼ -┌─────────────────────┐ Assign 'tmp___0 = 1' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ Assign 'tmp___0 = 0' ┌───┐ -│ _ │ ──────────────────────▶ │ _ │ ◀────────────────────── │ _ │ -└─────────────────────┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └───┘ - │ ▲ - │ Assign 'y = tmp___0' │ Assign 'tmp___0 = x < 2' - ▼ │ -┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ ┌───────────────────────────┐ -│ _ │ ◀────────────────────── │ _ │ │ _ │ -└─────────────────────┘ └────────────────────────────────────────┘ └───────────────────────────┘ - │ │ - │ Ret (Some 0, main) │ Test (y,true) - ▼ ▼ -┌─────────────────────┐ ┌────────────────────────────────────────┐ -│ _ │ │ _ │ -└─────────────────────┘ └────────────────────────────────────────┘ - │ - │ InlineEntry '()' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry __VERIFIER_error - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = x > 0 && x < 2' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Assign 'y = tmp___0' + ▼ +┌─────────────────────┐ Test (y,false) ┌────────────────────────────────────────┐ +│ _ │ ◀──────────────── │ _ │ +└─────────────────────┘ └────────────────────────────────────────┘ + │ │ + │ Ret (Some 0, main) │ Test (y,true) + ▼ ▼ +┌─────────────────────┐ ┌────────────────────────────────────────┐ +│ _ │ │ _ │ +└─────────────────────┘ └────────────────────────────────────────┘ + │ + │ InlineEntry '()' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry __VERIFIER_error + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected index 8256383932..561561fa15 100644 --- a/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/and_var_true-unreach-call.expected @@ -1,63 +1,63 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Assign 'tmp___0 = x > 0 && x < 0' - ▼ -┌───┐ Assign 'tmp___0 = x < 0' ┌────────────────────────────────────────┐ Assign 'tmp___0 = 0' ┌───┐ -│ _ │ ──────────────────────────▶ │ _ │ ◀────────────────────────────────────────────── │ _ │ -└───┘ └────────────────────────────────────────┘ └───┘ - │ - │ Assign 'y = tmp___0' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Test (y,false) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ +┌────────────────────────────────────────┐ +│ _ │ +└────────────────────────────────────────┘ + │ + │ Entry main + ▼ +┌────────────────────────────────────────┐ +│ _ │ ·┐ +└────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' +└────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ : +└────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : +┌────────────────────────────────────────┐ : +│ _ │ ◀┘ +└────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ +┌────────────────────────────────────────┐ +│ _ │ +└────────────────────────────────────────┘ + │ + │ Assign 'tmp___0 = x > 0 && x < 0' + ▼ +┌────────────────────────────────────────┐ +│ _ │ +└────────────────────────────────────────┘ + │ + │ Assign 'y = tmp___0' + ▼ +┌────────────────────────────────────────┐ +│ _ │ +└────────────────────────────────────────┘ + │ + │ Test (y,false) + ▼ +┌────────────────────────────────────────┐ +│ _ │ +└────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ +┌────────────────────────────────────────┐ +│ _ │ +└────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected index cb14942893..08a49830e1 100644 --- a/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3_true-unreach-call.expected @@ -1,81 +1,81 @@ - ┌─────────────────────────────────────────┐ - │ _ │ - └─────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌─────────────────────────────────────────┐ - │ _ │ ·┐ - └─────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ : - └─────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └─────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ : - └─────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌─────────────────────────────────────────┐ : - │ _ │ ◀┘ - └─────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌─────────────────────────────────────────┐ - │ _ │ ──────────────────────────────────────────────────────────────────────────────────┐ - └─────────────────────────────────────────┘ │ - │ │ - │ Test (x < 1 || (x > 2 || x > 1),false) │ - ▼ │ -┌───┐ Test (x > 1,false) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ -│ _ │ ────────────────────▶ │ _ │ │ -└───┘ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ : ▲ │ - │ │ InlineEntry '(x == 1)' : │ Test (x > 2 || x > 1,false) │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : ┌──────────────────────────────┐ │ - │ │ _ │ : │ _ │ │ - │ └─────────────────────────────────────────┘ : └──────────────────────────────┘ │ - │ │ : │ │ - │ │ Entry __VERIFIER_assert : │ │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ Test (x < 1 || (x > 2 || x > 1),true) - │ └─────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Test (! cond,false) : │ │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └─────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Ret (None, __VERIFIER_assert) : │ │ - │ ▼ : │ │ - │ ┌─────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └─────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x > 2 || x > 1,true) │ - │ ▼ ▼ ▼ │ - │ Test (x > 1,true) ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - └───────────────────────▶ │ _ │ ◀┘ - └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌─────────────────────────────────────────┐ - │ _ │ - └─────────────────────────────────────────┘ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ·┐ + └─────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └─────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ : + └─────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌─────────────────────────────────────────┐ : + │ _ │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ ─┐ + └─────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1 || (x > 2 || x > 1),false) │ + ▼ │ + ┌─────────────────────────────────────────┐ │ + ┌········································· │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ InlineEntry '(x == 1)' │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ Entry __VERIFIER_assert │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ Test (x < 1 || (x > 2 || x > 1),true) + : └─────────────────────────────────────────┘ │ + : │ │ + : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (! cond,false) │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ Ret (None, __VERIFIER_assert) │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + : │ _ │ │ + : └─────────────────────────────────────────┘ │ + : │ │ + : │ InlineReturn │ + : ▼ │ + : ┌─────────────────────────────────────────┐ │ + └········································▶ │ _ │ ◀┘ + └─────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌─────────────────────────────────────────┐ + │ _ │ + └─────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected index 0cc7108b55..4bda4ebe45 100644 --- a/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or3dead_true-unreach-call.expected @@ -1,81 +1,81 @@ - ┌──────────────────────────────────────────┐ - │ _ │ - └──────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌──────────────────────────────────────────┐ - │ _ │ ·┐ - └──────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌──────────────────────────────────────────┐ : - │ _ │ : - └──────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌──────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └──────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌──────────────────────────────────────────┐ : - │ _ │ : - └──────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌──────────────────────────────────────────┐ : - │ _ │ ◀┘ - └──────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌──────────────────────────────────────────┐ - │ _ │ ───────────────────────────────────────────────────────────────────────────────────┐ - └──────────────────────────────────────────┘ │ - │ │ - │ Test (x < 1 || (x > 2 || x != 1),false) │ - ▼ │ -┌───┐ Test (x != 1,false) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ -│ _ │ ─────────────────────▶ │ _ │ │ -└───┘ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ - │ │ : ▲ │ - │ │ InlineEntry '(x == 1)' : │ Test (x > 2 || x != 1,false) │ - │ ▼ : │ │ - │ ┌──────────────────────────────────────────┐ : ┌───────────────────────────────┐ │ - │ │ _ │ : │ _ │ │ - │ └──────────────────────────────────────────┘ : └───────────────────────────────┘ │ - │ │ : │ │ - │ │ Entry __VERIFIER_assert : │ │ - │ ▼ : │ │ - │ ┌──────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ Test (x < 1 || (x > 2 || x != 1),true) - │ └──────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Test (! cond,false) : │ │ - │ ▼ : │ │ - │ ┌──────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └──────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ Ret (None, __VERIFIER_assert) : │ │ - │ ▼ : │ │ - │ ┌──────────────────────────────────────────┐ : │ │ - │ │ _ │ : │ │ - │ └──────────────────────────────────────────┘ : │ │ - │ │ : │ │ - │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x > 2 || x != 1,true) │ - │ ▼ ▼ ▼ │ - │ Test (x != 1,true) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ - └────────────────────────▶ │ _ │ ◀┘ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌──────────────────────────────────────────┐ - │ _ │ - └──────────────────────────────────────────┘ + ┌──────────────────────────────────────────┐ + │ _ │ + └──────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌──────────────────────────────────────────┐ + │ _ │ ·┐ + └──────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ : + └──────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └──────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ : + └──────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌──────────────────────────────────────────┐ : + │ _ │ ◀┘ + └──────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌──────────────────────────────────────────┐ + │ _ │ ─┐ + └──────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1 || (x > 2 || x != 1),false) │ + ▼ │ + ┌──────────────────────────────────────────┐ │ + ┌········································· │ _ │ │ + : └──────────────────────────────────────────┘ │ + : │ │ + : │ InlineEntry '(x == 1)' │ + : ▼ │ + : ┌──────────────────────────────────────────┐ │ + : │ _ │ │ + : └──────────────────────────────────────────┘ │ + : │ │ + : │ Entry __VERIFIER_assert │ + : ▼ │ + : ┌──────────────────────────────────────────┐ │ + : │ _ │ │ Test (x < 1 || (x > 2 || x != 1),true) + : └──────────────────────────────────────────┘ │ + : │ │ + : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (! cond,false) │ + : ▼ │ + : ┌──────────────────────────────────────────┐ │ + : │ _ │ │ + : └──────────────────────────────────────────┘ │ + : │ │ + : │ Ret (None, __VERIFIER_assert) │ + : ▼ │ + : ┌──────────────────────────────────────────┐ │ + : │ _ │ │ + : └──────────────────────────────────────────┘ │ + : │ │ + : │ InlineReturn │ + : ▼ │ + : ┌──────────────────────────────────────────┐ │ + └········································▶ │ _ │ ◀┘ + └──────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌──────────────────────────────────────────┐ + │ _ │ + └──────────────────────────────────────────┘ diff --git a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected index 8f7dfe911b..b21a275d14 100644 --- a/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected +++ b/tests/sv-comp/cfg/uncil/or_true-unreach-call.expected @@ -1,81 +1,81 @@ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ - │ - │ Entry main - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '()' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_nondet_int : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' - └────────────────────────────────────────┘ : - │ : - │ Ret (Some val, __VERIFIER_nondet_int) : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 'x = tmp' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ──────────────────────────────────────────────────┐ - └────────────────────────────────────────┘ │ - │ │ - │ Test (x < 1 || x > 1,false) │ - ▼ │ -┌───┐ Test (x > 1,false) ┌────────────────────────────────────────┐ │ -│ _ │ ────────────────────▶ │ _ │ ·┐ │ -└───┘ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineEntry '(x == 1)' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Entry __VERIFIER_assert : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Test (! cond,false) : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Ret (None, __VERIFIER_assert) : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineReturn : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (x < 1 || x > 1,true) - │ ▼ ▼ ▼ - │ Test (x > 1,true) ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - └───────────────────────▶ │ _ │ - └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'x = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ─┐ + └────────────────────────────────────────┘ │ + │ │ + │ Test (x < 1 || x > 1,false) │ + ▼ │ + ┌────────────────────────────────────────┐ │ + ┌········································· │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ InlineEntry '(x == 1)' │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Entry __VERIFIER_assert │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ Test (x < 1 || x > 1,true) + : └────────────────────────────────────────┘ │ + : │ │ + : Inlined Proc '__VERIFIER_assert(x == 1)' │ Test (! cond,false) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ Ret (None, __VERIFIER_assert) │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + : │ _ │ │ + : └────────────────────────────────────────┘ │ + : │ │ + : │ InlineReturn │ + : ▼ │ + : ┌────────────────────────────────────────┐ │ + └········································▶ │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ From a2e48689e9f6d560c20891099ec1cc761d9156dd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 17 May 2024 13:42:12 +0300 Subject: [PATCH 190/689] Pipe graph-easy warnings to file in ARG tests --- .../cfg/multicall_true-unreach-call.expected | 1 + tests/sv-comp/dune.inc | 82 +++++++++---------- tests/sv-comp/gen/gen.ml | 2 +- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/tests/sv-comp/cfg/multicall_true-unreach-call.expected b/tests/sv-comp/cfg/multicall_true-unreach-call.expected index c5e54da634..5b2375dad7 100644 --- a/tests/sv-comp/cfg/multicall_true-unreach-call.expected +++ b/tests/sv-comp/cfg/multicall_true-unreach-call.expected @@ -1,3 +1,4 @@ +Warning: Layouter could only place 13 nodes/15 edges out of 13/16 - giving up at /usr/bin/graph-easy line 144. ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index fbc51e76e9..427033a3ff 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -12,7 +12,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -34,7 +34,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -56,7 +56,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -78,7 +78,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -100,7 +100,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -122,7 +122,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -144,7 +144,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -166,7 +166,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -188,7 +188,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -210,7 +210,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -232,7 +232,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -254,7 +254,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -276,7 +276,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -298,7 +298,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -320,7 +320,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -342,7 +342,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -364,7 +364,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -386,7 +386,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -408,7 +408,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -430,7 +430,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -452,7 +452,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -474,7 +474,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -496,7 +496,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -518,7 +518,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -540,7 +540,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -562,7 +562,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -584,7 +584,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -606,7 +606,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -628,7 +628,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -650,7 +650,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -672,7 +672,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -694,7 +694,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -716,7 +716,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -738,7 +738,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -760,7 +760,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -782,7 +782,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -804,7 +804,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -826,7 +826,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -848,7 +848,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -870,7 +870,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule @@ -892,7 +892,7 @@ (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %{target} + (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) (rule diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index a18b99f2ea..2beeb07dfd 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -16,7 +16,7 @@ let generate_rule c_dir_file = (progn (ignore-outputs (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) - (with-stdout-to %%{target} + (with-outputs-to %%{target} (run graph-easy --as=boxart arg.dot))))) (rule From f572bcd95974c4fdfeaba93ffcbafe41e326bf45 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 17 May 2024 15:05:11 +0300 Subject: [PATCH 191/689] Rename: AutoTuneSvcompSpec -> SvcompSpecConfig --- src/goblint.ml | 4 ++-- src/goblint_lib.ml | 2 +- src/maingoblint.ml | 2 +- src/{autoTuneSvcompSpec.ml => svcompSpecConfig.ml} | 5 ++++- 4 files changed, 8 insertions(+), 5 deletions(-) rename src/{autoTuneSvcompSpec.ml => svcompSpecConfig.ml} (92%) diff --git a/src/goblint.ml b/src/goblint.ml index 4a585e6826..56a7cf3d47 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -36,7 +36,7 @@ let main () = Logs.debug "%s" (GobUnix.localtime ()); Logs.debug "%s" GobSys.command_line; (* When analyzing a termination specification, activate the termination analysis before pre-processing. *) - if get_string "ana.specification" <> "" then AutoTuneSvcompSpec.enableAnalysesForTerminationSpecification (); + if get_string "ana.specification" <> "" then SvcompSpecConfig.enableAnalysesForTerminationSpecification (); if AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( @@ -58,7 +58,7 @@ let main () = in (* This is run independant of the autotuner being enabled or not be sound for programs with longjmp *) AutoTune.activateLongjmpAnalysesWhenRequired (); - if get_string "ana.specification" <> "" then AutoTuneSvcompSpec.enableAnalysesForSpecification (); + if get_string "ana.specification" <> "" then SvcompSpecConfig.enableAnalysesForSpecification (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; file |> do_analyze changeInfo; do_html_output (); diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 3619679dac..b998ccdd47 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -59,7 +59,7 @@ module GobConfig = GobConfig module AfterConfig = AfterConfig module AutoTune = AutoTune -module AutoTuneSvcompSpec = AutoTuneSvcompSpec +module SvcompSpecConfig = SvcompSpecConfig module JsonSchema = JsonSchema module Options = Options diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 2892bdee34..8aa2f81890 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -202,7 +202,7 @@ let handle_options () = check_arguments (); 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 get_string "ana.specification" <> "" then - AutoTuneSvcompSpec.enableAnalysesForMemSafetySpecification (); + SvcompSpecConfig.enableAnalysesForMemSafetySpecification (); if AutoTune.specificationMemSafetyIsActivated () then AutoTune.focusOnMemSafetySpecification (); AfterConfig.run (); diff --git a/src/autoTuneSvcompSpec.ml b/src/svcompSpecConfig.ml similarity index 92% rename from src/autoTuneSvcompSpec.ml rename to src/svcompSpecConfig.ml index 6351ec65af..41628f2b4d 100644 --- a/src/autoTuneSvcompSpec.ml +++ b/src/svcompSpecConfig.ml @@ -1,4 +1,7 @@ -(** Autotuning of the activated analyses for soundness based on SV-COMP specification. *) +(** Selecting sound configurations based on SV-COMP specification. + Activating the analyses and enabling options that are + required for analyzing the property defined in the specification. + **) open GobConfig open AutoTune From e97e26e175ab430dac47e5e92cd42212e6bc83a5 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 17 May 2024 15:28:02 +0200 Subject: [PATCH 192/689] [skip ci] migrated meet_with_one_conj --- .../apron/linearTwoVarEqualityDomain.apron.ml | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 620dd307b2..1793f38de8 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -41,6 +41,14 @@ module Rhs = struct | Some (c,_) -> Z.gcd c gcd | None -> gcd in (BatOption.map (fun (coeff,i) -> (Z.div coeff gcd,i)) v,Z.div o gcd, Z.div d gcd) + + (** Substitute rhs for varx in rhs' *) + let subst rhs varx rhs' = + match rhs,rhs' with + | (Some (c,x),o,d),(Some (c',x'),o',d') when x'=varx -> canonicalize (Some (Z.mul c c',x),Z.((o*c')+(d*o')),Z.mul d d') + | (None ,o,d),(Some (c',x'),o',d') when x'=varx -> canonicalize (None ,Z.((o*c')+(d*o')),Z.mul d d') + | _ -> rhs' + end module EqualitiesConjunction = struct @@ -67,6 +75,9 @@ module EqualitiesConjunction = struct (** trivial equalities are of the form var_i = var_i and are not kept explicitely in the sparse representation of EquanlitiesConjunction *) let nontrivial (_,econmap) lhs = IntMap.mem lhs econmap + (** turn x = (cy+o)/d into y = (dx-o)/c*) + let reverse x (c,y,o,d) = (y,(Some (d,x),Z.neg o,c)) + (** sparse implementation of get rhs for lhs, but will default to no mapping for sparse entries *) let get_rhs (_,econmap) lhs = IntMap.find_default (Rhs.var_zero lhs) lhs econmap @@ -181,29 +192,52 @@ module EqualitiesConjunction = struct exception Contradiction - let meet_with_one_conj ts i (var, b) = + let meet_with_one_conj ts i (var, offs, divi) = + let (var,offs,divi) = Rhs.canonicalize (var,offs,divi) in (* make sure that the one new conj is properly canonicalized *) let res = - let subst_var tsi x (vart, bt) = + let subst_var tsi x (vary, o, d) = + (* [[x substby (cy+o)/d ]] ((c'x+o')/d') *) + (* =====> (c'cy + c'o+o'd)/(dd') *) let adjust = function - | (Some vare, b') when vare = x -> (vart, Z.(b' + bt)) + | (Some (c',varx), o',d') when varx = x -> Rhs.canonicalize (BatOption.map (fun (c,y)->(Z.mul c c',y)) vary, Z.((c'*o)+(o'*d)),Z.(d'*d)) | e -> e in - (fst tsi, IntMap.add x (vart, bt) @@ IntMap.map adjust (snd tsi)) (* in case of sparse representation, make sure that the equality is now included in the conjunction *) + (fst tsi, IntMap.add x (vary, o, d) @@ IntMap.map adjust (snd tsi)) (* in case of sparse representation, make sure that the equality is now included in the conjunction *) in - let (var1, b1) = get_rhs ts i in - (match var, var1 with - | None , None -> if not @@ Z.equal b b1 then raise Contradiction else ts - | None , Some h1 -> subst_var ts h1 (None, Z.(b - b1)) - | Some j, None -> subst_var ts j (None, Z.(b1 - b)) - | Some j, Some h1 -> + (match var, (get_rhs ts i) with + (*| new conj , old conj *) + | None , (None , o1, divi1) -> if not @@ (Z.equal offs o1 && Z.equal divi divi1) then raise Contradiction else ts + (* o/d = x_i = (c1*x_h1+o1)/d1 *) + (* ======> x_h1 = (o*d1-o1*d)/(d*c1) /\ x_i = o/d *) + | None , (Some (coeff1,h1), o1, divi1) -> subst_var ts h1 (None, Z.(offs*divi1 - o1*divi),Z.(divi*coeff1)) + (* (c*x_j+o)/d = x_i = o1/d1 *) + (* ======> x_j = (o1*d-o*d1)/(d1*c) /\ x_i = o1/d1 *) + | Some (coeff,j), (None , o1, divi1) -> subst_var ts j (None, Z.(o1*divi - offs*divi1),Z.(divi1*coeff)) + (* (c*x_j+o)/d = x_i = (c1*x_h1+o1)/d1 *) + (* ======> x_j needs normalization wrt. ts *) + | Some (coeff,j), ((Some (coeff1,h1), o1, divi1) as oldi)-> (match get_rhs ts j with - | (None, b2) -> subst_var ts i (None, Z.(b2 + b)) - | (Some h2, b2) -> - if h1 = h2 then - (if not @@ Z.equal b1 Z.(b2 + b) then raise Contradiction else ts) - else if h1 < h2 then subst_var ts h2 (Some h1, Z.(b1 - (b + b2))) - else subst_var ts h1 (Some h2, Z.(b + (b2 - b1))))) in - if M.tracing then M.trace "meet" "meet_with_one_conj conj: { %s } eq: var_%d=%s -> { %s } " (show (snd ts)) i (Rhs.show (var,b)) (show (snd ts)) + (* ts[x_j]=o2/d2 ========> ... *) + | (None , o2, divi2) -> + let newxi = Rhs.subst (None,o2,divi2) j (Some (coeff,j),offs,divi) in + let newxh1 = snd @@ reverse i (coeff1,h1,o1,divi1) in + let newxh1 = Rhs.subst newxi i newxh1 in + subst_var ts h1 newxh1 + (* ts[x_j]=(c2*x_h2+o2)/d2 ========> ... *) + | (Some (coeff2,h2), o2, divi2) as normalizedj -> + if h1 = h2 then (* this is the case where x_i and x_j already where in the same equivalence class; let's see whether the new equality contradicts the old one *) + let normalizedi= Rhs.subst normalizedj j (Some(coeff,j),offs,divi) in + (if not @@ Rhs.equal normalizedi oldi then raise Contradiction else ts) + else if h1 < h2 (* good, we no unite the two equvalence classes; let's decide upon the representant *) + then (* express h2 in terms of h1: *) + let (_,newh2)= reverse j (coeff2,h2,o2,divi2) in + let newh2 = Rhs.subst oldi i (Rhs.subst (snd @@ reverse i (coeff,j,offs,divi)) j newh2) in + subst_var ts h2 newh2 + else (* express h1 in terms of h2: *) + let (_,newh1)= reverse i (coeff1,h1,o1,divi1) in + let newh1 = Rhs.subst normalizedj j (Rhs.subst (Some(coeff,j),offs,divi) i newh1) in + subst_var ts h1 newh1)) in + if M.tracing then M.trace "meet" "meet_with_one_conj conj: { %s } eq: var_%d=%s -> { %s } " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd ts)) ; res end From a9248db7e355c7dfa74182acaa8eeab55abfb866 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 17 May 2024 15:38:23 +0200 Subject: [PATCH 193/689] [skip ci] tiny migration steps, low hanging fruit --- .../apron/linearTwoVarEqualityDomain.apron.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 1793f38de8..6d6363329b 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -327,7 +327,7 @@ struct (* Copy because function is not "with" so should not mutate inputs *) let assign_const t var const = match t.d with | None -> t - | Some t_d -> {d = Some (EConj.set_rhs t_d var (None, const)); env = t.env} + | Some t_d -> {d = Some (EConj.set_rhs t_d var (None, const,Z.one)); env = t.env} let subtract_const_from_var t var const = match t.d with @@ -419,12 +419,12 @@ struct let printXml f x = BatPrintf.fprintf f "\n\n\nequalities\n\n\n%s\n\nenv\n\n\n%s\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) (XmlUtil.escape (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (x.env))) let eval_interval ask = Bounds.bound_texpr - let meet_with_one_conj t i (var, b) = + let meet_with_one_conj t i (var, o, divi) = match t.d with | None -> t | Some d -> try - { d = Some (EConj.meet_with_one_conj d i (var, b)); env = t.env} + { d = Some (EConj.meet_with_one_conj d i (var, o, divi)); env = t.env} with EConj.Contradiction -> if M.tracing then M.trace "meet" " -> Contradiction\n"; { d = None; env = t.env} @@ -585,7 +585,7 @@ struct subtract_const_from_var t var_i off | Some (Some exp_var, off) -> (* Statement "assigned_var = exp_var + off" (assigned_var is not the same as exp_var) *) - meet_with_one_conj (forget_var t var) var_i (Some exp_var, off) + meet_with_one_conj (forget_var t var) var_i (Some (Z.one,exp_var), off, Z.one) end | None -> bot_env @@ -702,13 +702,13 @@ struct end | [(varexpr, index)] -> (* guard has a single reference variable only *) if Tcons1.get_typ tcons = EQ && Z.divisible constant varexpr then - meet_with_one_conj t index (None, (Z.(-(constant) / varexpr))) + meet_with_one_conj t index (None, (Z.(-(constant) / varexpr)),Z.one) else t (* only EQ is supported in equality based domains *) | [(a1,var1); (a2,var2)] -> (* two variables in relation needs a little sorting out *) begin match Tcons1.get_typ tcons with | EQ when Z.(a1 * a2 = -one) -> (* var1-var1 or var2-var1 *) - meet_with_one_conj t var2 (Some var1, Z.mul a1 constant) + meet_with_one_conj t var2 (Some (Z.one,var1), Z.mul a1 constant,Z.one) | _-> t (* Not supported in equality based 2vars without coeffiients *) end | _ -> t (* For equalities of more then 2 vars we just return t *)) From 1257b680109575bf79157d33f503eb23c7413fb1 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Sun, 19 May 2024 23:23:50 +0200 Subject: [PATCH 194/689] [skip ci] dealt with simplifying linear expressions to lin2vars with coeffs --- .../apron/linearTwoVarEqualityDomain.apron.ml | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 6d6363329b..1e60f28e8f 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -260,14 +260,14 @@ struct let negate coeff_var_list = List.map (function | (Some(coeff,i),offs,divi) -> (Some(Z.neg coeff,i),Z.neg offs,divi) | (None ,offs,divi) -> (None ,Z.neg offs,divi)) coeff_var_list in - let multiply_with_Z number divisor coeff_var_list = List.map (function - | (Some (coeff, var),offs,divi) -> Rhs.canonicalize (Some(Z.mul number coeff,var),Z.(number * offs),Z.mul divi divisor) - | (None,offs,divi) -> Rhs.canonicalize (None,Z.mul number offs,Z.mul divi divisor)) coeff_var_list in + let multiply_with_Q dividend divisor coeff_var_list = List.map (function + | (Some (coeff, var),offs,divi) -> Rhs.canonicalize (Some(Z.mul dividend coeff,var),Z.(dividend * offs),Z.mul divi divisor) + | (None,offs,divi) -> Rhs.canonicalize (None,Z.mul dividend offs,Z.mul divi divisor)) coeff_var_list in let multiply a b = (* if one of them is a constant, then multiply. Otherwise, the expression is not linear *) match a, b with - | [(None,a_coeff, divi)], b -> multiply_with_Z a_coeff divi b - | a, [(None,b_coeff, divi)] -> multiply_with_Z b_coeff divi a + | [(None,coeff, divi)], c + | c, [(None,coeff, divi)] -> multiply_with_Q coeff divi c | _ -> raise NotLinearExpr in let rec convert_texpr texp = @@ -284,8 +284,8 @@ struct | None -> [(Some (Z.one,var_dim),Z.zero,Z.one)] | Some d -> (match (EConj.get_rhs d var_dim) with - | (Some (coeff,i), k,divi) -> [(Some (coeff,i),Z.zero,Z.one); (None,k,Z.one)] - | (None, k,divi) -> [ (None,k,Z.one)]) + | (Some (coeff,i), k,divi) -> [(Some (coeff,i),Z.zero,divi); (None,k,divi)] + | (None, k,divi) -> [ (None,k,divi)]) end | Unop (Neg, e, _, _) -> negate (convert_texpr e) | Unop (Cast, e, _, _) -> convert_texpr e (* Ignore since casts in apron are used for floating point nums and rounding in contrast to CIL casts *) @@ -299,27 +299,27 @@ struct | exception ScalarIsInfinity -> None | x -> Some(x) - (** convert and simplify (wrt. reference variables) a texpr into a tuple of a list of monomials and a constant *) + (** convert and simplify (wrt. reference variables) a texpr into a tuple of a list of monomials (coeff,varidx,divi) and a (constant/divi) *) let simplified_monomials_from_texp (t: t) texp = BatOption.bind (monomials_from_texp t texp) (fun monomiallist -> let d = Option.get t.d in - let expr = Array.make (Environment.size t.env) Z.zero in - let accumulate_constants a (c, v) = match v with - | None -> Z.(a + c) - | Some idx -> let (term,con) = (EConj.get_rhs d idx) in - (Option.may (fun ter -> expr.(ter) <- Z.(expr.(ter) + c)) term; - Z.(a + c * con)) + let expr = Array.make (Environment.size t.env) (Q.zero) in (*TODO*: migrate to map; array of coeff/divisor per var idx*) + let accumulate_constants (aconst,adiv) (v,offs,divi) = match v with + | None -> let gcdee = Z.gcd adiv divi in (Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi) + | Some (coeff,idx) -> let (somevar,someoffs,somedivi)=Rhs.subst (EConj.get_rhs d idx) idx (v,offs,divi) in (* normalize! *) + (Option.may (fun (coef,ter) -> expr.(ter) <- Q.(expr.(ter) + Q.make coef somedivi)) somevar; + let gcdee = Z.gcd adiv divi in (Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi)) in - let constant = List.fold_left accumulate_constants Z.zero monomiallist in (* abstract simplification of the guard wrt. reference variables *) - Some (Array.fold_lefti (fun list v (c) -> if Z.equal c Z.zero then list else (c,v)::list) [] expr, constant) ) + let constant = List.fold_left accumulate_constants (Z.zero,Z.one) monomiallist in (* abstract simplification of the guard wrt. reference variables *) + Some (Array.fold_lefti (fun list v (c) -> if Q.equal c Q.zero then list else (c.num,v,c.den)::list) [] expr, constant) ) let simplify_to_ref_and_offset (t: t) texp = BatOption.bind (simplified_monomials_from_texp t texp ) - (fun (sum_of_terms, constant) -> + (fun (sum_of_terms, (constant,divisor)) -> (match sum_of_terms with - | [] -> Some (None, constant) - | [(coeff,var)] when Z.equal coeff Z.one -> Some (Some var, constant) + | [] -> Some (None, constant,divisor) + | [(coeff,var,divi)] when Z.equal coeff Z.one -> Some (Rhs.canonicalize (Some (Z.mul divisor coeff,var), Z.mul constant divi,Z.mul divisor divi)) |_ -> None)) let simplify_to_ref_and_offset t texp = timing_wrap "coeff_vec" (simplify_to_ref_and_offset t) texp @@ -364,9 +364,12 @@ struct if t.d = None then None, None else match simplify_to_ref_and_offset t (Texpr1.to_expr texpr) with - | Some (None, offset) -> - (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string offset) (IntOps.BigIntOps.to_string offset); - Some offset, Some offset) + | Some (None, offset, divisor) when Z.equal (Z.rem offset divisor) Z.zero -> let res = Z.div offset divisor in + (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string res) (IntOps.BigIntOps.to_string res); + Some res, Some res) + | Some (None, offset, divisor) -> let res = Z.div offset divisor in + (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string res) (IntOps.BigIntOps.to_string (Z.add res Z.one)); + Some res, Some (Z.add res Z.one); failwith "ToDo: Rethink interval bounds (add or subtract depending on sign of res)") | _ -> None, None let bound_texpr d texpr1 = timing_wrap "bounds calculation" (bound_texpr d) texpr1 From cad5f6e6c3b047cc30061188b57889b87a8b767a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 20 May 2024 13:03:12 +0300 Subject: [PATCH 195/689] Add BasePriv invariant_global tracing --- src/analyses/basePriv.ml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index af88cfb742..cbc11070d3 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -1917,6 +1917,17 @@ struct if M.tracing then M.traceu "priv" "-> %a" BaseComponents.pretty r; r + let invariant_global ask getg g = + if M.tracing then M.traceli "priv" "invariant_global %a" V.pretty g; + let getg x = + let r = getg x in + if M.tracing then M.trace "priv" "getg %a -> %a" V.pretty x G.pretty r; + r + in + let r = invariant_global ask getg g in + if M.tracing then M.traceu "priv" "-> %a" Invariant.pretty r; + r + end let priv_module: (module S) Lazy.t = From 9084ba46074703425f41e5e37b4344ddf5d604d7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 20 May 2024 12:55:52 +0200 Subject: [PATCH 196/689] Rm spurious comments Co-authored-by: Simmo Saan --- src/analyses/tutorials/taint.ml | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/analyses/tutorials/taint.ml b/src/analyses/tutorials/taint.ml index 13ce92c62c..f62a5a4722 100644 --- a/src/analyses/tutorials/taint.ml +++ b/src/analyses/tutorials/taint.ml @@ -31,9 +31,6 @@ struct let context ctx _ _ = () let startcontext () = () - (* Queries *) - - (** Determines whether a variable [v] is tainted, given a [state]. *) (** Determines whether an expression [e] is tainted, given a [state]. *) let rec is_exp_tainted (state:D.t) (e:Cil.exp) = match e with From 9bb067fb0ef2c8dde5140e54655ea229bb112ad7 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 20 May 2024 14:00:32 +0300 Subject: [PATCH 197/689] Move activating longjmp analyses from autotune to soundness config --- src/autoTune.ml | 14 -------------- src/goblint.ml | 4 ++-- src/svcompSpecConfig.ml | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 1cbdb4ae1e..1a6dd908d0 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -198,20 +198,6 @@ let reduceThreadAnalyses () = disableAnalyses notNeccessaryThreadAnalyses; ) -(* This is run independent of the autotuner being enabled or not to be sound in the presence of setjmp/longjmp *) -(* It is done this way around to allow enabling some of these analyses also for programs without longjmp *) -let longjmpAnalyses = ["activeLongjmp"; "activeSetjmp"; "taintPartialContexts"; "modifiedSinceSetjmp"; "poisonVariables"; "expsplit"; "vla"] - -let activateLongjmpAnalysesWhenRequired () = - let isLongjmp = function - | LibraryDesc.Longjmp _ -> true - | _ -> false - in - if hasFunction isLongjmp then ( - Logs.info "longjmp -> enabling longjmp analyses \"%s\"" (String.concat ", " longjmpAnalyses); - enableAnalyses longjmpAnalyses; - ) - let focusOnMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidMemtrack diff --git a/src/goblint.ml b/src/goblint.ml index 56a7cf3d47..3e28c4ab68 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -56,8 +56,8 @@ let main () = else None in - (* This is run independant of the autotuner being enabled or not be sound for programs with longjmp *) - AutoTune.activateLongjmpAnalysesWhenRequired (); + (* This is run independant of the autotuner being enabled or not to be sound for programs with longjmp *) + SvcompSpecConfig.activateLongjmpAnalysesWhenRequired (); if get_string "ana.specification" <> "" then SvcompSpecConfig.enableAnalysesForSpecification (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; file |> do_analyze changeInfo; diff --git a/src/svcompSpecConfig.ml b/src/svcompSpecConfig.ml index 41628f2b4d..107aff7b1c 100644 --- a/src/svcompSpecConfig.ml +++ b/src/svcompSpecConfig.ml @@ -63,3 +63,17 @@ let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = let enableAnalysesForSpecification () = List.iter enableAnalysesForSpecification (Svcomp.Specification.of_option ()) + +(* This is run independent of the autotuner being enabled or not to be sound in the presence of setjmp/longjmp *) +(* It is done this way around to allow enabling some of these analyses also for programs without longjmp *) +let longjmpAnalyses = ["activeLongjmp"; "activeSetjmp"; "taintPartialContexts"; "modifiedSinceSetjmp"; "poisonVariables"; "expsplit"; "vla"] + +let activateLongjmpAnalysesWhenRequired () = + let isLongjmp = function + | LibraryDesc.Longjmp _ -> true + | _ -> false + in + if hasFunction isLongjmp then ( + Logs.info "longjmp -> enabling longjmp analyses \"%s\"" (String.concat ", " longjmpAnalyses); + enableAnalyses longjmpAnalyses; + ) From 747c4162a549a451359ac521b0ddffdd500ecdd7 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 20 May 2024 14:20:37 +0300 Subject: [PATCH 198/689] Rename SvcompSpecConfig -> AutoSoundConfig and better document the mechanism --- src/{svcompSpecConfig.ml => autoSoundConfig.ml} | 17 ++++++++++++----- src/goblint.ml | 6 +++--- src/goblint_lib.ml | 2 +- src/maingoblint.ml | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) rename src/{svcompSpecConfig.ml => autoSoundConfig.ml} (87%) diff --git a/src/svcompSpecConfig.ml b/src/autoSoundConfig.ml similarity index 87% rename from src/svcompSpecConfig.ml rename to src/autoSoundConfig.ml index 107aff7b1c..c0338c7847 100644 --- a/src/svcompSpecConfig.ml +++ b/src/autoSoundConfig.ml @@ -1,7 +1,10 @@ -(** Selecting sound configurations based on SV-COMP specification. - Activating the analyses and enabling options that are - required for analyzing the property defined in the specification. - **) + +(** Automatically turning on analyses required to ensure soundness + based on a given specification (e.g., SV-COMP specification) + or programming idioms (e.g., longjump) in the analyzed code, + but only when it is possible to do so automatically. + This does not fully exempt from the need for manual configuration. +*) open GobConfig open AutoTune @@ -15,7 +18,11 @@ let enableOptions options = in List.iter enableOpt options -(* TODO: have only one function for matching all specifications and find a place where it can be called. *) +(** Selecting sound configurations based on SV-COMP specification. + Activating the analyses and enabling options that are + required for analyzing the property defined in the specification. + TODO: have only one function for matching all specifications and find a place where it can be called. +*) let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) diff --git a/src/goblint.ml b/src/goblint.ml index 3e28c4ab68..a687badb8e 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -36,7 +36,7 @@ let main () = Logs.debug "%s" (GobUnix.localtime ()); Logs.debug "%s" GobSys.command_line; (* When analyzing a termination specification, activate the termination analysis before pre-processing. *) - if get_string "ana.specification" <> "" then SvcompSpecConfig.enableAnalysesForTerminationSpecification (); + if get_string "ana.specification" <> "" then AutoSoundConfig.enableAnalysesForTerminationSpecification (); if AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( @@ -57,8 +57,8 @@ let main () = None in (* This is run independant of the autotuner being enabled or not to be sound for programs with longjmp *) - SvcompSpecConfig.activateLongjmpAnalysesWhenRequired (); - if get_string "ana.specification" <> "" then SvcompSpecConfig.enableAnalysesForSpecification (); + AutoSoundConfig.activateLongjmpAnalysesWhenRequired (); + if get_string "ana.specification" <> "" then AutoSoundConfig.enableAnalysesForSpecification (); if get_bool "ana.autotune.enabled" then AutoTune.chooseConfig file; file |> do_analyze changeInfo; do_html_output (); diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index b998ccdd47..8013d9b2fe 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -59,7 +59,7 @@ module GobConfig = GobConfig module AfterConfig = AfterConfig module AutoTune = AutoTune -module SvcompSpecConfig = SvcompSpecConfig +module AutoSoundConfig = AutoSoundConfig module JsonSchema = JsonSchema module Options = Options diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 8aa2f81890..95849bce36 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -202,7 +202,7 @@ let handle_options () = check_arguments (); 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 get_string "ana.specification" <> "" then - SvcompSpecConfig.enableAnalysesForMemSafetySpecification (); + AutoSoundConfig.enableAnalysesForMemSafetySpecification (); if AutoTune.specificationMemSafetyIsActivated () then AutoTune.focusOnMemSafetySpecification (); AfterConfig.run (); From 2f29e90e7fcd5b032cdc6e6f4c2721f244e2a17c Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 20 May 2024 15:03:33 +0200 Subject: [PATCH 199/689] Union Domain: Cleanup meet Co-authored-by: Simmo Saan --- src/cdomain/value/cdomains/unionDomain.ml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/cdomain/value/cdomains/unionDomain.ml b/src/cdomain/value/cdomains/unionDomain.ml index b5e1b3bae0..302875ea2e 100644 --- a/src/cdomain/value/cdomains/unionDomain.ml +++ b/src/cdomain/value/cdomains/unionDomain.ml @@ -23,13 +23,9 @@ module Field = struct end) (CilType.Fieldinfo) let meet f g = - if equal f g then - f - else - match f, g with - | `Top, f - | f, `Top -> f - | _ -> raise Lattice.Uncomparable + match meet f g with + | `Bot -> raise Lattice.Uncomparable + | m -> m end module Simple (Values: Arg) = From 034492e12c4772f0d06af8f8de305b66703a0839 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Mon, 20 May 2024 23:32:21 +0200 Subject: [PATCH 200/689] [skip ci] replaced overspecialized subtract_with_constant by affine_transform --- .../apron/linearTwoVarEqualityDomain.apron.ml | 70 ++++++++----------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 1e60f28e8f..b296a3420d 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -76,7 +76,7 @@ module EqualitiesConjunction = struct let nontrivial (_,econmap) lhs = IntMap.mem lhs econmap (** turn x = (cy+o)/d into y = (dx-o)/c*) - let reverse x (c,y,o,d) = (y,(Some (d,x),Z.neg o,c)) + let inverse x (c,y,o,d) = (y,(Some (d,x),Z.neg o,c)) (** sparse implementation of get rhs for lhs, but will default to no mapping for sparse entries *) let get_rhs (_,econmap) lhs = IntMap.find_default (Rhs.var_zero lhs) lhs econmap @@ -220,7 +220,7 @@ module EqualitiesConjunction = struct (* ts[x_j]=o2/d2 ========> ... *) | (None , o2, divi2) -> let newxi = Rhs.subst (None,o2,divi2) j (Some (coeff,j),offs,divi) in - let newxh1 = snd @@ reverse i (coeff1,h1,o1,divi1) in + let newxh1 = snd @@ inverse i (coeff1,h1,o1,divi1) in let newxh1 = Rhs.subst newxi i newxh1 in subst_var ts h1 newxh1 (* ts[x_j]=(c2*x_h2+o2)/d2 ========> ... *) @@ -230,16 +230,32 @@ module EqualitiesConjunction = struct (if not @@ Rhs.equal normalizedi oldi then raise Contradiction else ts) else if h1 < h2 (* good, we no unite the two equvalence classes; let's decide upon the representant *) then (* express h2 in terms of h1: *) - let (_,newh2)= reverse j (coeff2,h2,o2,divi2) in - let newh2 = Rhs.subst oldi i (Rhs.subst (snd @@ reverse i (coeff,j,offs,divi)) j newh2) in + let (_,newh2)= inverse j (coeff2,h2,o2,divi2) in + let newh2 = Rhs.subst oldi i (Rhs.subst (snd @@ inverse i (coeff,j,offs,divi)) j newh2) in subst_var ts h2 newh2 else (* express h1 in terms of h2: *) - let (_,newh1)= reverse i (coeff1,h1,o1,divi1) in + let (_,newh1)= inverse i (coeff1,h1,o1,divi1) in let newh1 = Rhs.subst normalizedj j (Rhs.subst (Some(coeff,j),offs,divi) i newh1) in subst_var ts h1 newh1)) in if M.tracing then M.trace "meet" "meet_with_one_conj conj: { %s } eq: var_%d=%s -> { %s } " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd ts)) ; res + (** affine transform variable i allover conj with transformer (Some (coeff,i)+offs)/divi *) + let affine_transform econ i (var,offs,divi) = + if nontrivial econ i then (** i cannot occur on any other rhs apart from itself *) + set_rhs econ i (Rhs.subst (get_rhs econ i) i (var,offs,divi)) + else (* var_i = var_i, i.e. it may occur on the rhs of other equalities *) + match var with + | None -> failwith "this is not a valid affine transformation" + | Some (coeff,j) -> + (* so now, we transform with the inverse of the transformer: *) + let inv = snd (inverse i (coeff,j,offs,divi)) in + IntMap.fold (fun k v acc -> + match v with + | (Some (c,x),o,d) when x=i-> set_rhs acc k (Rhs.subst inv i v) + | _ -> acc + ) (snd econ) econ + end (** [VarManagement] defines the type t of the affine equality domain (a record that contains an optional matrix and an apron environment) and provides the functions needed for handling variables (which are defined by [RelationDomain.D2]) such as [add_vars], [remove_vars]. @@ -325,33 +341,9 @@ struct let simplify_to_ref_and_offset t texp = timing_wrap "coeff_vec" (simplify_to_ref_and_offset t) texp (* Copy because function is not "with" so should not mutate inputs *) - let assign_const t var const = match t.d with - | None -> t - | Some t_d -> {d = Some (EConj.set_rhs t_d var (None, const,Z.one)); env = t.env} - - let subtract_const_from_var t var const = - match t.d with + let assign_const t var const divi = match t.d with | None -> t - | Some t_d -> - let subtract_const_from_var_for_single_equality index (eq_var_opt, off2) econ = - if index <> var then - begin match eq_var_opt with - | Some eq_var when eq_var = var -> - EConj.set_rhs econ index (eq_var_opt, Z.(off2 - const)) - | _ -> econ - end - else econ - in - let d = - if not @@ EConj.nontrivial t_d var - (* var is a reference variable -> it can appear on the right-hand side of an equality *) - then - (EConj.IntMap.fold (subtract_const_from_var_for_single_equality) (snd t_d) t_d) - else - (* var never appears on the right hand side-> we only need to modify the array entry at index var *) - EConj.set_rhs t_d var (Tuple2.map2 (Z.add const) (EConj.get_rhs t_d var)) - in - {d = Some d; env = t.env} + | Some t_d -> {d = Some (EConj.set_rhs t_d var (None, const, divi)); env = t.env} end @@ -580,15 +572,15 @@ struct | None -> (* Statement "assigned_var = ?" (non-linear assignment) *) forget_var t var - | Some (None, off) -> + | Some (None, off, divi) -> (* Statement "assigned_var = off" (constant assignment) *) - assign_const (forget_var t var) var_i off - | Some (Some exp_var, off) when var_i = exp_var -> - (* Statement "assigned_var = assigned_var + off" *) - subtract_const_from_var t var_i off - | Some (Some exp_var, off) -> - (* Statement "assigned_var = exp_var + off" (assigned_var is not the same as exp_var) *) - meet_with_one_conj (forget_var t var) var_i (Some (Z.one,exp_var), off, Z.one) + assign_const (forget_var t var) var_i off divi + | Some (Some (coeff_var,exp_var), off, divi) when var_i = exp_var -> + (* Statement "assigned_var = (coeff_var*assigned_var + off) / divi" *) + {d=Some (EConj.affine_transform d var_i (Some (coeff_var, var_i), off, divi)); env=t.env } + | Some (Some monomial, off, divi) -> + (* Statement "assigned_var = (monomial) + off / divi" (assigned_var is not the same as exp_var) *) + meet_with_one_conj (forget_var t var) var_i (Some (monomial), off, divi) end | None -> bot_env From 4d2668177c4bde52a89897253c2327806954b22c Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 21 May 2024 08:52:54 +0200 Subject: [PATCH 201/689] [skip ci] bounds --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index b296a3420d..a0bbcbce39 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -360,8 +360,12 @@ struct (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string res) (IntOps.BigIntOps.to_string res); Some res, Some res) | Some (None, offset, divisor) -> let res = Z.div offset divisor in - (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string res) (IntOps.BigIntOps.to_string (Z.add res Z.one)); - Some res, Some (Z.add res Z.one); failwith "ToDo: Rethink interval bounds (add or subtract depending on sign of res)") + let (lower,upper) = if Z.lt res Z.zero then + (Z.sub res Z.one,res) + else + (res,Z.add res Z.one) in + (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string lower) (IntOps.BigIntOps.to_string upper); + Some lower, Some upper) | _ -> None, None let bound_texpr d texpr1 = timing_wrap "bounds calculation" (bound_texpr d) texpr1 From fa58e2e301432c85c89b596d1c87b0923816c833 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 21 May 2024 09:24:25 +0200 Subject: [PATCH 202/689] [skip ci] leq/implies now also for coefficients --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index a0bbcbce39..5234f8d2fa 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -451,11 +451,13 @@ struct let leq t1 t2 = let env_comp = Environment.compare t1.env t2.env in (* Apron's Environment.compare has defined return values. *) - let implies ts i (var, b) = - let tuple_cmp = Tuple2.eq (Option.eq ~eq:Int.equal) (Z.equal) in + let implies ts i (var, offs, divi) = + let tuple_cmp = Tuple3.eq (Option.eq ~eq:(Tuple2.eq (Z.equal) (Int.equal))) (Z.equal) (Z.equal) in match var with - | None -> tuple_cmp (var, b) (EConj.get_rhs ts i) - | Some j -> tuple_cmp (EConj.get_rhs ts i) @@ Tuple2.map2 (Z.add b) (EConj.get_rhs ts j) + (* directly compare in case of constant value *) + | None -> tuple_cmp (var, offs, divi) (EConj.get_rhs ts i) + (* normalize in case of a full blown equality *) + | Some (coeffj,j) -> tuple_cmp (EConj.get_rhs ts i) @@ Rhs.subst (EConj.get_rhs ts j) j (var, offs, divi) in if env_comp = -2 || env_comp > 0 then false else if is_bot_env t1 || is_top t2 then true else From 1a976270e859211226506fb296f2debe9a364de2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 20 May 2024 17:43:20 +0300 Subject: [PATCH 203/689] Add Apron mutex-meet abortUnless non-termination test case (PR #1464) --- .../05-apron-mutex-meet-abortUnless.c | 39 +++++++++++++++++++ tests/regression/62-abortUnless/dune | 14 +++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/regression/62-abortUnless/05-apron-mutex-meet-abortUnless.c create mode 100644 tests/regression/62-abortUnless/dune diff --git a/tests/regression/62-abortUnless/05-apron-mutex-meet-abortUnless.c b/tests/regression/62-abortUnless/05-apron-mutex-meet-abortUnless.c new file mode 100644 index 0000000000..e00c665056 --- /dev/null +++ b/tests/regression/62-abortUnless/05-apron-mutex-meet-abortUnless.c @@ -0,0 +1,39 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.activated[+] abortUnless --set ana.path_sens[+] threadflag +// Minimized SV-COMP version of our regression test +// NOTIMEOUT +#include +#include + +void reach_error() { + assert(0); // NOWARN +} +void __VERIFIER_assert(int cond) { // NOWARN + if(!(cond)) { ERROR: {reach_error();abort();} } +} + +int glob1 = 5; +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; +void *t_fun(void *arg) { + int t; + pthread_mutex_lock(&mutex1); + t = glob1; + __VERIFIER_assert(t == 5); // NOWARN + glob1 = -10; + __VERIFIER_assert(glob1 == -10); // NOWARN + glob1 = t; + pthread_mutex_unlock(&mutex1); + return ((void *)0); +} +int main(void) { + pthread_t id; + __VERIFIER_assert(glob1 == 5); // NOWARN + pthread_create(&id, ((void *)0), t_fun, ((void *)0)); + pthread_mutex_lock(&mutex1); + glob1++; + __VERIFIER_assert(glob1 == 6); // NOWARN + glob1--; + pthread_mutex_unlock(&mutex1); + pthread_join (id, ((void *)0)); + return 0; +} diff --git a/tests/regression/62-abortUnless/dune b/tests/regression/62-abortUnless/dune new file mode 100644 index 0000000000..d0f8f1af41 --- /dev/null +++ b/tests/regression/62-abortUnless/dune @@ -0,0 +1,14 @@ +(rule + (aliases runtest runaprontest) + (enabled_if %{lib-available:apron}) + (deps + (package goblint) + ../../../goblint ; update_suite calls local goblint + (:update_suite ../../../scripts/update_suite.rb) + (glob_files ??-*.c)) + (locks /update_suite) + (action + (chdir ../../.. + (progn + (run %{update_suite} apron-mutex-meet-abortUnless -q))))) + From d008a2c50f6da39416488099069c1b1cac3ff894 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 20 May 2024 17:56:08 +0300 Subject: [PATCH 204/689] Make relational mutex-meet join sync more precise when threadflag is path-sensitive (PR #1464) --- src/analyses/apron/relationPriv.apron.ml | 2 +- src/analyses/commonPriv.ml | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 1a91b4d39a..69f96065ec 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -635,7 +635,7 @@ struct st end | `Join -> - if (ask.f (Q.MustBeSingleThreaded {since_start = true})) then + if ConfCheck.no_branched_thread_creation () || (ask.f (Q.MustBeSingleThreaded {since_start = true})) then st else let rel = st.rel in diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 6376a6ca11..a8de785aab 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -50,6 +50,19 @@ struct if not threadflag_path_sens then failwith "The activated privatization requires the 'threadflag' analysis to be path sensitive if it is enabled (it is currently enabled, but not path sensitive)"; () end + + let branched_thread_creation () = + let threadflag_active = List.mem "threadflag" (GobConfig.get_string_list "ana.activated") in + if threadflag_active then + let threadflag_path_sens = List.mem "threadflag" (GobConfig.get_string_list "ana.path_sens") in + if not threadflag_path_sens then + true + else + false + else + true + + let no_branched_thread_creation () = not (branched_thread_creation ()) end module Protection = From 5581d31433ccfcc0281bb1a8d8f276bc39e60796 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 20 May 2024 18:01:53 +0300 Subject: [PATCH 205/689] Use branched thread creation check for other privatizations --- src/analyses/apron/relationPriv.apron.ml | 6 +++--- src/analyses/basePriv.ml | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 69f96065ec..7a59c778ee 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -98,7 +98,7 @@ struct let sync (ask: Q.ask) getg sideg (st: relation_components_t) reason = match reason with | `Join -> - if ask.f (Q.MustBeSingleThreaded {since_start = true}) then + if ConfCheck.no_branched_thread_creation () || ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else (* must be like enter_multithreaded *) @@ -347,7 +347,7 @@ struct st end | `Join -> - if (ask.f (Q.MustBeSingleThreaded { since_start= true })) then + if ConfCheck.no_branched_thread_creation () || (ask.f (Q.MustBeSingleThreaded { since_start= true })) then st else (* must be like enter_multithreaded *) @@ -1190,7 +1190,7 @@ struct match reason with | `Return -> st (* TODO: implement? *) | `Join -> - if (ask.f (Q.MustBeSingleThreaded {since_start = true})) then + if ConfCheck.no_branched_thread_creation () || (ask.f (Q.MustBeSingleThreaded {since_start = true})) then st else let rel = st.rel in diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 527d11b1de..cecc838b9e 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -307,7 +307,7 @@ struct let sync ask getg sideg (st: BaseComponents (D).t) reason = match reason with - | `Join -> (* required for branched thread creation *) + | `Join when ConfCheck.branched_thread_creation () -> (* required for branched thread creation *) let global_cpa = CPA.filter (fun x _ -> is_global ask x && is_unprotected ask x) st.cpa in sideg V.mutex_inits global_cpa; (* must be like enter_multithreaded *) (* TODO: this makes mutex-oplus less precise in 28-race_reach/10-ptrmunge_racefree and 28-race_reach/trylock2_racefree, why? *) @@ -318,6 +318,7 @@ struct sideg (V.global x) (CPA.singleton x v) ) st.cpa; st + | `Join | `Return | `Normal | `Init @@ -404,7 +405,7 @@ struct let sync ask getg sideg (st: BaseComponents (D).t) reason = match reason with - | `Join -> (* required for branched thread creation *) + | `Join when ConfCheck.branched_thread_creation () -> (* required for branched thread creation *) let global_cpa = CPA.filter (fun x _ -> is_global ask x && is_unprotected ask x) st.cpa in sideg V.mutex_inits global_cpa; (* must be like enter_multithreaded *) @@ -421,6 +422,7 @@ struct ) st.cpa st.cpa in {st with cpa = cpa'} + | `Join | `Return | `Normal | `Init @@ -772,7 +774,7 @@ struct let sync ask getg sideg (st: BaseComponents (D).t) reason = let sideg = Wrapper.sideg ask sideg in match reason with - | `Join -> (* required for branched thread creation *) + | `Join when ConfCheck.branched_thread_creation () -> (* required for branched thread creation *) CPA.fold (fun x v (st: BaseComponents (D).t) -> if is_global ask x && is_unprotected ask x then ( sideg (V.unprotected x) v; @@ -782,6 +784,7 @@ struct else st ) st.cpa st + | `Join | `Return | `Normal | `Init From 556bf8cc217ddff95bba70685af416077c05968a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 21 May 2024 11:09:19 +0300 Subject: [PATCH 206/689] Remove ConfCheck.no_branched_thread_creation --- src/analyses/apron/relationPriv.apron.ml | 20 ++++++++++++-------- src/analyses/commonPriv.ml | 2 -- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 7a59c778ee..dd4b65bab8 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -97,8 +97,8 @@ struct let sync (ask: Q.ask) getg sideg (st: relation_components_t) reason = match reason with - | `Join -> - if ConfCheck.no_branched_thread_creation () || ask.f (Q.MustBeSingleThreaded {since_start = true}) then + | `Join when ConfCheck.branched_thread_creation () -> + if ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else (* must be like enter_multithreaded *) @@ -110,6 +110,7 @@ struct ) in {st with rel = rel_local} + | `Join | `Normal | `Init | `Thread @@ -346,8 +347,8 @@ struct | _ -> st end - | `Join -> - if ConfCheck.no_branched_thread_creation () || (ask.f (Q.MustBeSingleThreaded { since_start= true })) then + | `Join when ConfCheck.branched_thread_creation () -> + if ask.f (Q.MustBeSingleThreaded { since_start= true }) then st else (* must be like enter_multithreaded *) @@ -375,6 +376,7 @@ struct let rel_local' = RD.meet rel_local (getg ()) in {st with rel = rel_local'} *) st + | `Join | `Normal | `Init | `Thread -> @@ -634,8 +636,8 @@ struct | _ -> st end - | `Join -> - if ConfCheck.no_branched_thread_creation () || (ask.f (Q.MustBeSingleThreaded {since_start = true})) then + | `Join when ConfCheck.branched_thread_creation () -> + if ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else let rel = st.rel in @@ -657,6 +659,7 @@ struct ) in {st with rel = rel_local} + | `Join | `Normal | `Init | `Thread -> @@ -1189,8 +1192,8 @@ struct let sync (ask:Q.ask) getg sideg (st: relation_components_t) reason = match reason with | `Return -> st (* TODO: implement? *) - | `Join -> - if ConfCheck.no_branched_thread_creation () || (ask.f (Q.MustBeSingleThreaded {since_start = true})) then + | `Join when ConfCheck.branched_thread_creation () -> + if ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else let rel = st.rel in @@ -1204,6 +1207,7 @@ struct ) in {st with rel = rel_local} + | `Join | `Normal | `Init | `Thread -> diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index a8de785aab..cb2e13f910 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -61,8 +61,6 @@ struct false else true - - let no_branched_thread_creation () = not (branched_thread_creation ()) end module Protection = From 93aae836e216d8d1c13e8af1383dadd766d11d25 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 21 May 2024 11:11:57 +0300 Subject: [PATCH 207/689] Simplify and document ConfCheck.branched_thread_creation --- src/analyses/commonPriv.ml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index cb2e13f910..6b95de63e9 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -51,14 +51,12 @@ struct () end + (** Whether branched thread creation needs to be handled by [sync `Join] of privatization. *) let branched_thread_creation () = let threadflag_active = List.mem "threadflag" (GobConfig.get_string_list "ana.activated") in if threadflag_active then let threadflag_path_sens = List.mem "threadflag" (GobConfig.get_string_list "ana.path_sens") in - if not threadflag_path_sens then - true - else - false + not threadflag_path_sens else true end From ba485801970de0bf25618b8516b8ef4a89549523 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 21 May 2024 10:42:15 +0200 Subject: [PATCH 208/689] [skip ci] migrated meet_tcons --- .../apron/linearTwoVarEqualityDomain.apron.ml | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 5234f8d2fa..51c6d702ef 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -690,9 +690,9 @@ struct | Some d -> match simplified_monomials_from_texp t (Texpr1.to_expr @@ Tcons1.get_texpr1 tcons) with | None -> t - | Some (sum_of_terms, constant) ->( + | Some (sum_of_terms, (constant,divisor)) ->( match sum_of_terms with - | [] -> (* no reference variables in the guard *) + | [] -> (* no reference variables in the guard, so check constant for zero *) begin match Tcons1.get_typ tcons with | EQ when Z.equal constant Z.zero -> t | SUPEQ when Z.geq constant Z.zero -> t @@ -701,15 +701,20 @@ struct | EQMOD _ -> t | _ -> bot_env (* all other results are violating the guard *) end - | [(varexpr, index)] -> (* guard has a single reference variable only *) - if Tcons1.get_typ tcons = EQ && Z.divisible constant varexpr then - meet_with_one_conj t index (None, (Z.(-(constant) / varexpr)),Z.one) + | [(coeff, index, divi)] -> (* guard has a single reference variable only *) + if Tcons1.get_typ tcons = EQ then + meet_with_one_conj t index (Rhs.canonicalize (None, Z.(divi*constant),Z.(coeff*divisor))) else t (* only EQ is supported in equality based domains *) - | [(a1,var1); (a2,var2)] -> (* two variables in relation needs a little sorting out *) + | [(c1,var1,d1); (c2,var2,d2)] -> (* two variables in relation needs a little sorting out *) begin match Tcons1.get_typ tcons with - | EQ when Z.(a1 * a2 = -one) -> (* var1-var1 or var2-var1 *) - meet_with_one_conj t var2 (Some (Z.one,var1), Z.mul a1 constant,Z.one) + | EQ -> (* c1*var1/d1 + c2*var2/d2 +constant/divisor = 0*) + (* ======> c1*divisor*d2 * var1 = -c2*divisor*d1 * var2 +constant*-d1*d2*) + (* \/ c2*divisor*d1 * var2 = -c1*divisor*d2 * var1 +constant*-d1*d2*) + if var1 < var2 then + meet_with_one_conj t var2 (Rhs.canonicalize (Some (Z.neg @@ Z.(c1*divisor),var1),Z.neg @@ Z.(constant*d2*d1),Z.(c2*divisor*d1))) + else + meet_with_one_conj t var1 (Rhs.canonicalize (Some (Z.neg @@ Z.(c2*divisor),var2),Z.neg @@ Z.(constant*d2*d1),Z.(c1*divisor*d2))) | _-> t (* Not supported in equality based 2vars without coeffiients *) end | _ -> t (* For equalities of more then 2 vars we just return t *)) From bd329e16f72f296bdf88f46d31fcfc4477db3ffc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 21 May 2024 11:53:44 +0300 Subject: [PATCH 209/689] Fix mutex-meet invariant_global not including MUTEX_INITS --- src/analyses/apron/relationPriv.apron.ml | 4 ++-- src/analyses/basePriv.ml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index cb71884c8c..5ffb96650c 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -694,14 +694,14 @@ struct let finalize () = () let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function - | `Left m' as m -> (* mutex *) + | `Left m' -> (* mutex *) let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in if atomic || ask.f (GhostVarAvailable (Locked m')) then ( (* filters like query_invariant *) let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in let exact = GobConfig.get_bool "witness.invariant.exact" in - let rel = keep_only_protected_globals ask m' (getg m) in + let rel = keep_only_protected_globals ask m' (get_m_with_mutex_inits ask getg m') in (* TODO: disjunct with mutex_inits instead of join? *) let inv = RD.invariant rel |> List.enum diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index cbc11070d3..c244e7f3bf 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -250,7 +250,7 @@ struct let invariant_global ask getg = function | `Right g' -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g' + ValueDomain.invariant_global (read_unprotected_global getg) g' (* TODO: disjunct with mutex_inits instead of join? *) | _ -> (* mutex *) Invariant.none @@ -332,10 +332,10 @@ struct include PerMutexPrivBase let invariant_global (ask: Q.ask) getg = function - | `Left m' as m -> (* mutex *) + | `Left m' -> (* mutex *) let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in if atomic || ask.f (GhostVarAvailable (Locked m')) then ( - let cpa = getg m in + let cpa = get_m_with_mutex_inits ask getg m' in (* TODO: disjunct with mutex_inits instead of join? *) let inv = CPA.fold (fun v _ acc -> if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in @@ -688,7 +688,7 @@ struct let invariant_global ask getg = function | `Middle g -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g + ValueDomain.invariant_global (read_unprotected_global getg) g (* TODO: disjunct with mutex_inits instead of join? *) | `Left _ | `Right _ -> (* mutex or thread *) Invariant.none From 716bec950de4ee932aeac715b49637b48a3b59e5 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 12:16:51 +0300 Subject: [PATCH 210/689] Check that next thresholds in widening are smaller than max_ik or greater than min_ik --- src/cdomain/value/cdomains/intDomain.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index d8fe147d67..3c6ee1bb53 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -671,13 +671,13 @@ struct let upper_threshold u = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x <= 0) ts in + let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in BatOption.map_default Ints_t.of_bigint max_ik t in let lower_threshold l = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x >= 0) ts in + let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in BatOption.map_default Ints_t.of_bigint min_ik t in let lt = if threshold then lower_threshold l1 else min_ik in @@ -1397,13 +1397,13 @@ struct let upper_threshold (_,u) = let ts = if GobConfig.get_string "ana.int.interval_threshold_widening_constants" = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x <= 0) ts in + let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in BatOption.map_default Ints_t.of_bigint max_ik t in let lower_threshold (l,_) = let ts = if GobConfig.get_string "ana.int.interval_threshold_widening_constants" = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x >= 0) ts in + let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in BatOption.map_default Ints_t.of_bigint min_ik t in (*obtain partitioning of xs intervals according to the ys interval that includes them*) From 6e2a565461b92c1981ecd88bec3e3fa1bf426ba6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 12:21:57 +0300 Subject: [PATCH 211/689] Move upper_threshold and lower_threshold functions out of widen --- src/cdomain/value/cdomains/intDomain.ml | 27 ++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 3c6ee1bb53..c3c2ac462e 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -662,27 +662,26 @@ struct let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) + let upper_threshold u max_ik = + let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in + let u = Ints_t.to_bigint u in + let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in + BatOption.map_default Ints_t.of_bigint max_ik t + let lower_threshold l min_ik = + let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in + let l = Ints_t.to_bigint l in + let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in + BatOption.map_default Ints_t.of_bigint min_ik t + let widen ik x y = match x, y with | None, z | z, None -> z | Some (l0,u0), Some (l1,u1) -> let (min_ik, max_ik) = range ik in let threshold = get_interval_threshold_widening () in - let upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - in - let lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - in - let lt = if threshold then lower_threshold l1 else min_ik in + let lt = if threshold then lower_threshold l1 min_ik else min_ik in let l2 = if Ints_t.compare l0 l1 = 0 then l0 else Ints_t.min l1 (Ints_t.max lt min_ik) in - let ut = if threshold then upper_threshold u1 else max_ik in + let ut = if threshold then upper_threshold u1 max_ik else max_ik in let u2 = if Ints_t.compare u0 u1 = 0 then u0 else Ints_t.max u1 (Ints_t.min ut max_ik) in norm ik @@ Some (l2,u2) |> fst let widen ik x y = From b551cd5c8b521405ed033d9e78cf30b80995dca8 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 12:27:01 +0300 Subject: [PATCH 212/689] Move upper_threshold and lower_threshold functions to IntervalArith --- src/cdomain/value/cdomains/intDomain.ml | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index c3c2ac462e..c8dd2c3ef5 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -559,6 +559,17 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct let to_int (x1, x2) = if Ints_t.equal x1 x2 then Some x1 else None + + let upper_threshold u max_ik = + let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in + let u = Ints_t.to_bigint u in + let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in + BatOption.map_default Ints_t.of_bigint max_ik t + let lower_threshold l min_ik = + let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in + let l = Ints_t.to_bigint l in + let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in + BatOption.map_default Ints_t.of_bigint min_ik t end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = @@ -662,26 +673,15 @@ struct let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let widen ik x y = match x, y with | None, z | z, None -> z | Some (l0,u0), Some (l1,u1) -> let (min_ik, max_ik) = range ik in let threshold = get_interval_threshold_widening () in - let lt = if threshold then lower_threshold l1 min_ik else min_ik in + let lt = if threshold then IArith.lower_threshold l1 min_ik else min_ik in let l2 = if Ints_t.compare l0 l1 = 0 then l0 else Ints_t.min l1 (Ints_t.max lt min_ik) in - let ut = if threshold then upper_threshold u1 max_ik else max_ik in + let ut = if threshold then IArith.upper_threshold u1 max_ik else max_ik in let u2 = if Ints_t.compare u0 u1 = 0 then u0 else Ints_t.max u1 (Ints_t.min ut max_ik) in norm ik @@ Some (l2,u2) |> fst let widen ik x y = From beb1200cb5bad790ec30be8233cc11d31ec7a433 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 12:28:22 +0300 Subject: [PATCH 213/689] Use upper_threshold and lower_threshold functions from IntervalArith in IntervalSetFunctior, instead definining its own --- src/cdomain/value/cdomains/intDomain.ml | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index c8dd2c3ef5..c76eb2ef50 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -1393,18 +1393,8 @@ struct let widen ik xs ys = let (min_ik,max_ik) = range ik in let threshold = get_bool "ana.int.interval_threshold_widening" in - let upper_threshold (_,u) = - let ts = if GobConfig.get_string "ana.int.interval_threshold_widening_constants" = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - in - let lower_threshold (l,_) = - let ts = if GobConfig.get_string "ana.int.interval_threshold_widening_constants" = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - in + let upper_threshold (_,u) = IArith.upper_threshold u max_ik in + let lower_threshold (l,_) = IArith.lower_threshold l min_ik in (*obtain partitioning of xs intervals according to the ys interval that includes them*) let rec interval_sets_to_partitions (ik: ikind) (acc : (int_t * int_t) option) (xs: t) (ys: t)= match xs,ys with From 91216653bf5661c73d8b1a3e409c659391ad3ea4 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 12:49:52 +0300 Subject: [PATCH 214/689] Convert svc_run back to unknown and add comment --- src/util/library/libraryFunctions.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 0e67dc4c09..caf1dad784 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -694,7 +694,7 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("pmap_unset", unknown [drop "prognum" []; drop "versnum" []]); ("svcudp_create", unknown [drop "sock" []]); ("svc_register", unknown [drop "xprt" [r_deep; w_deep]; drop "prognum" []; drop "versnum" []; drop "dispatch" [r; w; c]; drop "protocol" []]); - ("svc_run", special [] Abort); + ("svc_run", unknown []); (* TODO: make new special kind "NoReturn" for this: the following node will be dead (like Abort), but the program doesn't exit (so it shouldn't be Abort) *) (* RPC library end *) ] [@@coverage off] From 91eca5a639c3bd2654f882a596699e1f1a628dfe Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 12:50:36 +0300 Subject: [PATCH 215/689] Apply suggested changes --- src/util/library/libraryFunctions.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index caf1dad784..d0ed2fd820 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -651,7 +651,7 @@ let glibc_desc_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__readlink_alias", unknown [drop "path" [r]; drop "buf" [w]; drop "len" []]); ("__overflow", unknown [drop "f" [r]; drop "ch" []]); ("__ctype_get_mb_cur_max", unknown []); - ("__maskrune", unknown [drop "c" [w]; drop "f" []]); + ("__maskrune", unknown [drop "c" []; drop "f" []]); ("__xmknod", unknown [drop "ver" []; drop "path" [r]; drop "mode" []; drop "dev" [r; w]]); ("yp_get_default_domain", unknown [drop "outdomain" [w]]); ("__nss_configure_lookup", unknown [drop "db" [r]; drop "service_line" [r]]); From f3a0ab62affa513ddac95dbed32b30cbf03a89ea Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Tue, 21 May 2024 13:08:08 +0300 Subject: [PATCH 216/689] Apply suggestions from code review Co-authored-by: Simmo Saan --- src/cdomain/value/cdomains/intDomain.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index c76eb2ef50..7d51293d3e 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -563,12 +563,14 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct let upper_threshold u max_ik = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x (Ints_t.to_bigint max_ik) <= 0) ts in + let max_ik' = Ints_t.to_bigint max_ik in + let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in BatOption.map_default Ints_t.of_bigint max_ik t let lower_threshold l min_ik = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x (Ints_t.to_bigint min_ik) >= 0) ts in + let min_ik' = Ints_t.to_bigint min_ik in + let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in BatOption.map_default Ints_t.of_bigint min_ik t end From c9d7cf71ae9c11b8abd0f0c000d1bb4106cd5cf5 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 13:42:16 +0300 Subject: [PATCH 217/689] Calculate lt and ut only when needed --- src/cdomain/value/cdomains/intDomain.ml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 7d51293d3e..54ea2f0cd1 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -681,10 +681,20 @@ struct | Some (l0,u0), Some (l1,u1) -> let (min_ik, max_ik) = range ik in let threshold = get_interval_threshold_widening () in - let lt = if threshold then IArith.lower_threshold l1 min_ik else min_ik in - let l2 = if Ints_t.compare l0 l1 = 0 then l0 else Ints_t.min l1 (Ints_t.max lt min_ik) in - let ut = if threshold then IArith.upper_threshold u1 max_ik else max_ik in - let u2 = if Ints_t.compare u0 u1 = 0 then u0 else Ints_t.max u1 (Ints_t.min ut max_ik) in + let l2 = + if Ints_t.compare l0 l1 = 0 then + l0 + else + let lt = if threshold then IArith.lower_threshold l1 min_ik else min_ik in + Ints_t.min l1 (Ints_t.max lt min_ik) + in + let u2 = + if Ints_t.compare u0 u1 = 0 then + u0 + else + let ut = if threshold then IArith.upper_threshold u1 max_ik else max_ik in + Ints_t.max u1 (Ints_t.min ut max_ik) + in norm ik @@ Some (l2,u2) |> fst let widen ik x y = let r = widen ik x y in From f3d932da1a3471d49ea3a97859308d871f4f5f6e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 13:44:24 +0300 Subject: [PATCH 218/689] Remove duplicated check of selecting min (or max) of max_ik (or min_ik) and threshold --- src/cdomain/value/cdomains/intDomain.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 54ea2f0cd1..d8f5451927 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -686,14 +686,14 @@ struct l0 else let lt = if threshold then IArith.lower_threshold l1 min_ik else min_ik in - Ints_t.min l1 (Ints_t.max lt min_ik) + Ints_t.min l1 lt in let u2 = if Ints_t.compare u0 u1 = 0 then u0 else let ut = if threshold then IArith.upper_threshold u1 max_ik else max_ik in - Ints_t.max u1 (Ints_t.min ut max_ik) + Ints_t.max u1 ut in norm ik @@ Some (l2,u2) |> fst let widen ik x y = From 4c21a79d9c66179e5b2540460fbe4d747c581074 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 13:57:59 +0300 Subject: [PATCH 219/689] Remove unnecessary max of u1 or threshold (and min of l1 or threshold) --- src/cdomain/value/cdomains/intDomain.ml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index d8f5451927..3bf81b1ba1 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -682,18 +682,14 @@ struct let (min_ik, max_ik) = range ik in let threshold = get_interval_threshold_widening () in let l2 = - if Ints_t.compare l0 l1 = 0 then - l0 - else - let lt = if threshold then IArith.lower_threshold l1 min_ik else min_ik in - Ints_t.min l1 lt + if Ints_t.compare l0 l1 = 0 then l0 + else if threshold then IArith.lower_threshold l1 min_ik + else min_ik in let u2 = - if Ints_t.compare u0 u1 = 0 then - u0 - else - let ut = if threshold then IArith.upper_threshold u1 max_ik else max_ik in - Ints_t.max u1 ut + if Ints_t.compare u0 u1 = 0 then u0 + else if threshold then IArith.upper_threshold u1 max_ik + else max_ik in norm ik @@ Some (l2,u2) |> fst let widen ik x y = From a86fb6f95fb3c6bffbc210300d65f2b084b77b54 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 21 May 2024 16:49:52 +0300 Subject: [PATCH 220/689] Add unit tests for interval widen --- tests/unit/cdomains/intDomainTest.ml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/unit/cdomains/intDomainTest.ml b/tests/unit/cdomains/intDomainTest.ml index 288d8f9337..e697b022eb 100644 --- a/tests/unit/cdomains/intDomainTest.ml +++ b/tests/unit/cdomains/intDomainTest.ml @@ -198,22 +198,35 @@ let test_ex_set _ = assert_equal (Some true) (T.to_bool tex10); assert_equal None (T.to_bool tex1) -module Interval = +module IntervalTest (I : IntDomain.SOverflow with type int_t = Z.t) = struct - module I = IntDomain.SOverflowUnlifter(IntDomain.Interval) + module I = IntDomain.SOverflowUnlifter (I) + let ik = Cil.IInt + let i65536 = I.of_interval ik (Z.zero, of_int 65536) + let i65537 = I.of_interval ik (Z.zero, of_int 65537) + let imax = I.of_interval ik (Z.zero, of_int 2147483647) let assert_equal x y = assert_equal ~cmp:I.equal ~printer:I.show x y let test_interval_rem _ = - let ik = Cil.IInt in assert_equal (I.of_int ik Z.zero) (I.rem ik (I.of_int ik Z.minus_one) (I.of_int ik Z.one)) + let test_interval_widen _ = + GobConfig.set_bool "ana.int.interval_threshold_widening" true; + GobConfig.set_string "ana.int.interval_threshold_widening_constants" "comparisons"; + assert_equal imax (I.widen ik i65536 i65537); + assert_equal imax (I.widen ik i65536 imax) + let test () = [ "test_interval_rem" >:: test_interval_rem; + "test_interval_widen" >:: test_interval_widen; ] end +module Interval = IntervalTest (IntDomain.Interval) +module IntervalSet = IntervalTest (IntDomain.IntervalSet) + module Congruence = struct module C = IntDomain.Congruence @@ -291,6 +304,7 @@ let test () = "test_meet" >:: test_meet; "test_excl_list">:: test_ex_set; "interval" >::: Interval.test (); + "intervalSet" >::: IntervalSet.test (); "congruence" >::: Congruence.test (); "intDomTuple" >::: IntDomTuple.test (); ] From 80ef4bd311de6fb433683c042de56706e8cc7db8 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 21 May 2024 17:51:05 +0200 Subject: [PATCH 221/689] [skip ci] formulated new join sorting criterium --- .../apron/linearTwoVarEqualityDomain.apron.ml | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 51c6d702ef..8e6a97d18c 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -478,32 +478,36 @@ struct (* joinfunction handles the dirty details of performing an "inner join" on the lhs of both bindings; in the resulting binding, the lhs is then mapped to values that are later relevant for sorting/grouping, i.e. - lhs itself - - the difference of both offsets + - the affine transformation from refvar1 to refvar2, i.E. the parameters A and B of the general affine transformer Ax+B - rhs1 - rhs2 however, we have to account for the sparseity of EConj maps by manually patching holes with default values *) - let joinfunction lhs rhs1 rhs2 = match rhs1, rhs2 with - | Some (ai,aj),Some (bi,bj) -> Some (lhs,Z.(aj - bj),(ai,aj),(bi,bj)) (* this is explicitely what we want *) - | None, Some (bi,bj) -> Some (lhs,Z.neg bj ,Rhs.var_zero lhs,(bi,bj)) (* account for the sparseity of binding 1 *) - | Some (ai,aj), None -> Some (lhs,aj ,(ai,aj),Rhs.var_zero lhs) (* account for the sparseity of binding 2 *) - | _,_ -> None (* no binding for lhs in both maps is replicated implicitely in a sparse result map *) + let joinfunction lhs rhs1 rhs2 = let coeff = Option.map_default fst Z.one in match rhs1, rhs2 with + (* Compute Ax+B such that (coeff1*(Ax+B)+off1)/d1 = (coeff2*x+off2)/d2 *) + (* ====> A = (coeff2*d1)/(coeff1*d2) /\ B = (off2*d1-off1*d2)/(c1*c2) *) + (* lhs A B rhs1 rhs2 *) + (*TODO*: if this works, make it more concise *) + | Some (ai,aj,ak), Some (bi,bj,bk) -> Some (lhs,Q.make Z.(ak*coeff bi) Z.(bk* coeff ai),Q.make Z.(bj*ak-aj*bk) Z.(bk*coeff ai), (ai,aj,ak) , (bi,bj,bk)) (* this is explicitely what we want *) + | None , Some (bi,bj,bk) -> Some (lhs,Q.make Z.( coeff bi) Z.(bk ),Q.make Z.(bj ) Z.(bk ), Rhs.var_zero lhs, (bi,bj,bk)) (* account for the sparseity of binding 1 *) + | Some (ai,aj,ak), None -> Some (lhs,Q.make Z.(ak ) Z.( coeff ai),Q.make Z.( neg aj) Z.( coeff ai), (ai,aj,ak), Rhs.var_zero lhs) (* account for the sparseity of binding 2 *) + | _,_ -> None (* no binding for lhs in both maps is replicated implicitely in a sparse result map *) in let table = List.of_enum @@ EConj.IntMap.values @@ EConj.IntMap.merge joinfunction (snd ad) (snd bd) in - (*compare two variables for grouping depending on delta function and reference index*) - let cmp_z (_, t0i, t1i, t2i) (_, t0j, t1j, t2j) = - let cmp_ref = Option.compare ~cmp:Int.compare in - Tuple3.compare ~cmp1:cmp_ref ~cmp2:cmp_ref ~cmp3:Z.compare (fst t1i, fst t2i, t0i) (fst t1j, fst t2j, t0j) + (* compare two variables for grouping depending on affine function parameters a, b and reference variable indices *) + let cmp_z (_, ai, bi, t1i, t2i) (_, aj, bj, t1j, t2j) = + let cmp_ref = Option.compare ~cmp:(fun x y -> Int.compare (snd x) (snd y)) in + Tuple4.compare ~cmp1:cmp_ref ~cmp2:cmp_ref ~cmp3:Q.compare ~cmp4:Q.compare (Tuple3.first t1i, Tuple3.first t2i, ai, bi) (Tuple3.first t1j, Tuple3.first t2j, aj, bj) in - (*Calculate new components as groups*) + (* Calculate new components as groups *) let new_components = BatList.group cmp_z table in - (*Adjust the domain array to represent the new components*) - let modify map idx_h b_h (idx, _, (opt1, z1), (opt2, z2)) = EConj.set_rhs map (idx) - (if opt1 = opt2 && Z.equal z1 z2 then (opt1, z1) - else (Some idx_h, Z.(z1 - b_h))) + (* Adjust the domain map to represent the new components *) + let modify map idx_h offs_h (idx, _, _, (opt1, z1, d1), (opt2, z2, d2)) = EConj.set_rhs map (idx) + (if opt1 = opt2 && Z.equal z1 z2 && Z.equal d1 d2 then (opt1, z1, d1) + else (Some idx_h, Z.(z1 - offs_h))) in let iterate map l = match l with - | (idx_h, _, (_, b_h), _) :: t -> List.fold (fun map' e -> modify map' idx_h b_h e) map l + | (idx_h, _, _, (_, offs_h, divi_h), _) :: t -> List.fold (fun map' e -> modify map' idx_h offs_h e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From 7e5b727373e27d3cd0565ccb9f44fc9936934197 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 21 May 2024 18:03:23 +0200 Subject: [PATCH 222/689] [skip ci] satisfy semgrep --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 8e6a97d18c..6c12744228 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -361,9 +361,9 @@ struct Some res, Some res) | Some (None, offset, divisor) -> let res = Z.div offset divisor in let (lower,upper) = if Z.lt res Z.zero then - (Z.sub res Z.one,res) + (Z.pred res,res) else - (res,Z.add res Z.one) in + (res,Z.succ res) in (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string lower) (IntOps.BigIntOps.to_string upper); Some lower, Some upper) | _ -> None, None From ad01be4ebe8012ee02bd1537386dbf00bd3cad1c Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 22 May 2024 10:27:40 +0200 Subject: [PATCH 223/689] [skip ci] finally affine transform the reference variables in join --- .../apron/linearTwoVarEqualityDomain.apron.ml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 6c12744228..cff8cab293 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -501,13 +501,16 @@ struct (* Calculate new components as groups *) let new_components = BatList.group cmp_z table in (* Adjust the domain map to represent the new components *) - let modify map idx_h offs_h (idx, _, _, (opt1, z1, d1), (opt2, z2, d2)) = EConj.set_rhs map (idx) - (if opt1 = opt2 && Z.equal z1 z2 && Z.equal d1 d2 then (opt1, z1, d1) - else (Some idx_h, Z.(z1 - offs_h))) + let modify map x (refmonom, offs, divi) (idx, _, _, (monom1, z1, d1), (monom2, z2, d2)) = EConj.set_rhs map (idx) + (if monom1 = monom2 && Z.equal z1 z2 && Z.equal d1 d2 then (monom1, z1, d1) + else + let refcoeff = Option.map_default fst Z.one refmonom in + let coeff1 = Option.map_default fst Z.one monom1 in + (Some (Z.(coeff1*divi),x), Z.((z1*refcoeff)-(offs*coeff1)), Z.(refcoeff*d1)) ) in let iterate map l = match l with - | (idx_h, _, _, (_, offs_h, divi_h), _) :: t -> List.fold (fun map' e -> modify map' idx_h offs_h e) map l + | (idx_h, _, _, rhs_h, _) :: t -> List.fold (fun acc e -> modify acc idx_h rhs_h e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From 9923eafdc167b0453cfad0cff3d4fffdc5617c0c Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 22 May 2024 11:28:29 +0200 Subject: [PATCH 224/689] cosmetics --- .../apron/linearTwoVarEqualityDomain.apron.ml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index cff8cab293..6346dc0975 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -25,7 +25,8 @@ module Rhs = struct let var_zero i = (Some (Z.one,i), Z.zero, Z.one) let show_coeff c = if Z.equal c Z.one then "" - else (Z.to_string c) ^"*" + else if Z.equal c Z.minus_one then "-" + else (Z.to_string c) ^"·" let show_rhs_formatted formatter = function | (Some (coeff,v), o,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s%+Ld" (show_coeff coeff) (formatter v) (Z.to_int64 o) @@ -404,7 +405,13 @@ struct (** prints the current variable equalities with resolved variable names *) let show varM = - let lookup i = Var.to_string (Environment.var_of_dim varM.env i) in + let lookup i = + let transl = [|"₀";"₁";"₂";"₃";"₄";"₅";"₆";"₇";"₈";"₉"|] in + let res = Var.to_string (Environment.var_of_dim varM.env i) in + match String.split_on_char '#' res with + | varname::rest::[] -> varname ^ (try String.fold_left (fun acc c -> acc ^ transl.(Char.code c - Char.code '0')) "" rest with _ -> "#"^rest) + | _ -> failwith "Variable name not found" + in match varM.d with | None -> "⊥\n" | Some arr when EConj.is_top_con arr -> "⊤\n" From 53d62d411b99a8e9d732bc00a08bc7051186cc0b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 13:41:21 +0300 Subject: [PATCH 225/689] Make pattern match with one expression being a constant symmetric --- src/autoTune.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index b5def761b5..5ecb743423 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -345,8 +345,8 @@ let extractOctagonVars = function | BinOp (MinusA, e1,e2, (TInt _)) -> ( match extractVar e1, extractVar e2 with | Some a, Some b -> Some (`Left (a,b)) - | Some a, None - | None, Some a -> if isConstant e1 then Some (`Right a) else None + | Some a, None when isConstant e2 -> Some (`Right a) + | None, Some a when isConstant e1 -> Some (`Right a) | _,_ -> None ) | _ -> None From 4ff244f350d7b9c76e867b764e54e1eb848515fb Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 13:47:52 +0300 Subject: [PATCH 226/689] Extract duplicated code into a new function --- src/autoTune.ml | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 5ecb743423..2729daf014 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -340,15 +340,16 @@ let rec extractVar = function | CastE (_, e) -> extractVar e | _ -> None +let extractBinOpVars e1 e2 = + match extractVar e1, extractVar e2 with + | Some a, Some b -> Some (`Left (a,b)) + | Some a, None when isConstant e2 -> Some (`Right a) + | None, Some a when isConstant e1 -> Some (`Right a) + | _,_ -> None + let extractOctagonVars = function | BinOp (PlusA, e1,e2, (TInt _)) - | BinOp (MinusA, e1,e2, (TInt _)) -> ( - match extractVar e1, extractVar e2 with - | Some a, Some b -> Some (`Left (a,b)) - | Some a, None when isConstant e2 -> Some (`Right a) - | None, Some a when isConstant e1 -> Some (`Right a) - | _,_ -> None - ) + | BinOp (MinusA, e1,e2, (TInt _)) -> extractBinOpVars e1 e2 | _ -> None let addOrCreateVarMapping varMap key v globals = if key.vglob = globals then varMap := @@ -377,13 +378,7 @@ class octagonVariableVisitor(varMap, globals) = object ) | Lval ((Var info),_) when not (isGoblintStub info) -> handle varMap 1 globals (Some (`Right info)) ; SkipChildren | UnOp (LNot, BinOp (op, e1,e2, (TInt _)),_) when isComparison op -> (* TODO: Should be generalized *) - handle varMap 5 globals ( - match extractVar e1, extractVar e2 with - | Some a, Some b -> Some (`Left (a,b)) - | Some a, None - | None, Some a -> if isConstant e1 then Some (`Right a) else None - | _,_ -> None - ); + handle varMap 5 globals (extractBinOpVars e1 e2); DoChildren (*Traverse down only operations fitting for linear equations*) | UnOp (Neg, _,_) From de75a0666b0cd0f9b357353b8bd679504ef2869c Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 14:47:18 +0300 Subject: [PATCH 227/689] Handle variables in addition to plus and minus in extractOctagonVars --- src/autoTune.ml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 2729daf014..91ba88f0c5 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -350,7 +350,11 @@ let extractBinOpVars e1 e2 = let extractOctagonVars = function | BinOp (PlusA, e1,e2, (TInt _)) | BinOp (MinusA, e1,e2, (TInt _)) -> extractBinOpVars e1 e2 - | _ -> None + | e -> ( + match extractVar e with + | Some a -> Some (`Right a) + | _ -> None + ) let addOrCreateVarMapping varMap key v globals = if key.vglob = globals then varMap := if VariableMap.mem key !varMap then @@ -372,15 +376,14 @@ class octagonVariableVisitor(varMap, globals) = object method! vexpr = function (*an expression of type +/- a +/- b where a,b are either variables or constants*) | BinOp (op, e1,e2, (TInt _)) when isComparison op -> ( + Logs.info "exp1 %a exp2 %a" GoblintCil.d_plainexp e1 GoblintCil.d_plainexp e2; handle varMap 5 globals (extractOctagonVars e1) ; handle varMap 5 globals (extractOctagonVars e2) ; DoChildren ) | Lval ((Var info),_) when not (isGoblintStub info) -> handle varMap 1 globals (Some (`Right info)) ; SkipChildren - | UnOp (LNot, BinOp (op, e1,e2, (TInt _)),_) when isComparison op -> (* TODO: Should be generalized *) - handle varMap 5 globals (extractBinOpVars e1 e2); - DoChildren (*Traverse down only operations fitting for linear equations*) + | UnOp (LNot, _,_) | UnOp (Neg, _,_) | BinOp (PlusA,_,_,_) | BinOp (MinusA,_,_,_) From 8f62145575a2d1b79fef6bf51c896b54958000d0 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 22 May 2024 13:56:41 +0200 Subject: [PATCH 228/689] Add test for #1478 --- tests/regression/46-apron2/85-fix.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/regression/46-apron2/85-fix.c diff --git a/tests/regression/46-apron2/85-fix.c b/tests/regression/46-apron2/85-fix.c new file mode 100644 index 0000000000..e0d7e8964b --- /dev/null +++ b/tests/regression/46-apron2/85-fix.c @@ -0,0 +1,13 @@ +// SKIP PARAM: --set ana.activated[+] apron --set sem.int.signed_overflow assume_none +#include + +int main() { + int d = 1; + while (d < 6) { + if (0) + return 0; //FIXPOINT: Earlier this fixpoint was not reached here + d++; + } + + return 0; +} From f54687f251a93af6e1e1b78207b321409847d863 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:00:04 +0300 Subject: [PATCH 229/689] Use lists instead either option --- src/autoTune.ml | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 91ba88f0c5..9fbba045cf 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -336,25 +336,21 @@ let isGoblintStub v = List.exists (fun (Attr(s,_)) -> s = "goblint_stub") v.vatt let rec extractVar = function | UnOp (Neg, e, _) -> extractVar e - | Lval ((Var info),_) when not (isGoblintStub info) -> Some info + | Lval ((Var info),_) when not (isGoblintStub info) -> [info] | CastE (_, e) -> extractVar e - | _ -> None + | _ -> [] let extractBinOpVars e1 e2 = match extractVar e1, extractVar e2 with - | Some a, Some b -> Some (`Left (a,b)) - | Some a, None when isConstant e2 -> Some (`Right a) - | None, Some a when isConstant e1 -> Some (`Right a) - | _,_ -> None + | [], [] -> [] + | a, [] when isConstant e2 -> a + | [], b when isConstant e1 -> b + | a, b -> List.append a b let extractOctagonVars = function | BinOp (PlusA, e1,e2, (TInt _)) | BinOp (MinusA, e1,e2, (TInt _)) -> extractBinOpVars e1 e2 - | e -> ( - match extractVar e with - | Some a -> Some (`Right a) - | _ -> None - ) + | e -> extractVar e let addOrCreateVarMapping varMap key v globals = if key.vglob = globals then varMap := if VariableMap.mem key !varMap then @@ -363,12 +359,7 @@ let addOrCreateVarMapping varMap key v globals = if key.vglob = globals then var else VariableMap.add key v !varMap -let handle varMap v globals = function - | Some (`Left (a,b)) -> - addOrCreateVarMapping varMap a v globals; - addOrCreateVarMapping varMap b v globals; - | Some (`Right a) -> addOrCreateVarMapping varMap a v globals; - | None -> () +let handle varMap v globals vars = List.iter (fun var -> addOrCreateVarMapping varMap var v globals) vars class octagonVariableVisitor(varMap, globals) = object inherit nopCilVisitor @@ -381,7 +372,7 @@ class octagonVariableVisitor(varMap, globals) = object handle varMap 5 globals (extractOctagonVars e2) ; DoChildren ) - | Lval ((Var info),_) when not (isGoblintStub info) -> handle varMap 1 globals (Some (`Right info)) ; SkipChildren + | Lval ((Var info),_) when not (isGoblintStub info) -> handle varMap 1 globals [info]; SkipChildren (*Traverse down only operations fitting for linear equations*) | UnOp (LNot, _,_) | UnOp (Neg, _,_) From 70b2313099322c8480dac43ca76e982af147f31e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:04:01 +0300 Subject: [PATCH 230/689] Inline handle function and remove a logging added by accident --- src/autoTune.ml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 9fbba045cf..db3c275d56 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -359,20 +359,17 @@ let addOrCreateVarMapping varMap key v globals = if key.vglob = globals then var else VariableMap.add key v !varMap -let handle varMap v globals vars = List.iter (fun var -> addOrCreateVarMapping varMap var v globals) vars - class octagonVariableVisitor(varMap, globals) = object inherit nopCilVisitor method! vexpr = function (*an expression of type +/- a +/- b where a,b are either variables or constants*) | BinOp (op, e1,e2, (TInt _)) when isComparison op -> ( - Logs.info "exp1 %a exp2 %a" GoblintCil.d_plainexp e1 GoblintCil.d_plainexp e2; - handle varMap 5 globals (extractOctagonVars e1) ; - handle varMap 5 globals (extractOctagonVars e2) ; + let extractedVars = List.append (extractOctagonVars e1) (extractOctagonVars e2) in + List.iter (fun var -> addOrCreateVarMapping varMap var 5 globals) extractedVars; DoChildren ) - | Lval ((Var info),_) when not (isGoblintStub info) -> handle varMap 1 globals [info]; SkipChildren + | Lval ((Var info),_) when not (isGoblintStub info) -> addOrCreateVarMapping varMap info 1 globals; SkipChildren (*Traverse down only operations fitting for linear equations*) | UnOp (LNot, _,_) | UnOp (Neg, _,_) From a4f419bd4d41610473fcdc31c6937b7734f79974 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:12:00 +0300 Subject: [PATCH 231/689] Make extractVar still return an option --- src/autoTune.ml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index db3c275d56..28d828a9f9 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -335,22 +335,22 @@ let isComparison = function let isGoblintStub v = List.exists (fun (Attr(s,_)) -> s = "goblint_stub") v.vattr let rec extractVar = function - | UnOp (Neg, e, _) -> extractVar e - | Lval ((Var info),_) when not (isGoblintStub info) -> [info] + | UnOp (Neg, e, _) | CastE (_, e) -> extractVar e - | _ -> [] + | Lval ((Var info),_) when not (isGoblintStub info) -> Some info + | _ -> None let extractBinOpVars e1 e2 = match extractVar e1, extractVar e2 with - | [], [] -> [] - | a, [] when isConstant e2 -> a - | [], b when isConstant e1 -> b - | a, b -> List.append a b + | Some a, Some b -> [a; b] + | Some a, None when isConstant e2 -> [a] + | None, Some b when isConstant e1 -> [b] + | _, _ -> [] let extractOctagonVars = function | BinOp (PlusA, e1,e2, (TInt _)) | BinOp (MinusA, e1,e2, (TInt _)) -> extractBinOpVars e1 e2 - | e -> extractVar e + | e -> Option.to_list (extractVar e) let addOrCreateVarMapping varMap key v globals = if key.vglob = globals then varMap := if VariableMap.mem key !varMap then From 8bbd7b60c5473d2872fd8c736f79d0e4c8e1bc5e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:13:31 +0300 Subject: [PATCH 232/689] Iter twice instead of append --- src/autoTune.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 28d828a9f9..b1c834cd5a 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -365,8 +365,8 @@ class octagonVariableVisitor(varMap, globals) = object method! vexpr = function (*an expression of type +/- a +/- b where a,b are either variables or constants*) | BinOp (op, e1,e2, (TInt _)) when isComparison op -> ( - let extractedVars = List.append (extractOctagonVars e1) (extractOctagonVars e2) in - List.iter (fun var -> addOrCreateVarMapping varMap var 5 globals) extractedVars; + List.iter (fun var -> addOrCreateVarMapping varMap var 5 globals) (extractOctagonVars e1); + List.iter (fun var -> addOrCreateVarMapping varMap var 5 globals) (extractOctagonVars e2); DoChildren ) | Lval ((Var info),_) when not (isGoblintStub info) -> addOrCreateVarMapping varMap info 1 globals; SkipChildren From a0309d10f311222c6f3757127dfe1c0bfd52e551 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 22 May 2024 14:16:32 +0200 Subject: [PATCH 233/689] Use `D.bot ()`for `startcontext`. Closes #1474 --- src/framework/analyses.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 930793b60f..4ef98358f4 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -427,7 +427,7 @@ end module ValueContexts (D:Lattice.S) = struct module C = D - let startcontext () = D.top () + let startcontext () = D.bot () end module type SpecSys = From 22ebaae71b1368f0add49211371a1c80d86b9318 Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Wed, 22 May 2024 15:20:35 +0300 Subject: [PATCH 234/689] Apply suggestions from code review Co-authored-by: Simmo Saan --- src/autoSoundConfig.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/autoSoundConfig.ml b/src/autoSoundConfig.ml index c0338c7847..332de65302 100644 --- a/src/autoSoundConfig.ml +++ b/src/autoSoundConfig.ml @@ -1,7 +1,6 @@ - (** Automatically turning on analyses required to ensure soundness based on a given specification (e.g., SV-COMP specification) - or programming idioms (e.g., longjump) in the analyzed code, + or programming idioms (e.g., longjmp) in the analyzed code, but only when it is possible to do so automatically. This does not fully exempt from the need for manual configuration. *) From b3a3c9d9dd09b36f23176c4076a083289e5b5a4c Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:26:20 +0300 Subject: [PATCH 235/689] Refactor logging and enabling analyses into one function --- src/autoSoundConfig.ml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/autoSoundConfig.ml b/src/autoSoundConfig.ml index c0338c7847..12674bec41 100644 --- a/src/autoSoundConfig.ml +++ b/src/autoSoundConfig.ml @@ -9,7 +9,9 @@ open GobConfig open AutoTune -let logEnablingAnalyses spec ana = Logs.info "Specification: %s -> enabling soundness analyses \"%s\"" (Svcomp.Specification.to_string [spec]) (String.concat ", " ana) +let enableSpecAnalyses spec analyses = + Logs.info "Specification: %s -> enabling soundness analyses \"%s\"" (Svcomp.Specification.to_string [spec]) (String.concat ", " analyses); + enableAnalyses analyses let enableOptions options = let enableOpt option = @@ -27,19 +29,16 @@ let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) let analyses = ["base"; "useAfterFree"] in - logEnablingAnalyses spec analyses; - enableAnalyses analyses + enableSpecAnalyses spec analyses; | ValidDeref -> (* Enable the soundness analyses for ValidDeref spec *) let analyses = ["base"; "memOutOfBounds"] in - logEnablingAnalyses spec analyses; - enableAnalyses analyses; + enableSpecAnalyses spec analyses; let options = ["ana.arrayoob"; "cil.addNestedScopeAttr"] in enableOptions options | ValidMemtrack | ValidMemcleanup -> (* Enable the soundness analyses for ValidMemtrack and ValidMemcleanup specs *) let analyses = ["memLeak"] in - logEnablingAnalyses spec analyses; - enableAnalyses analyses + enableSpecAnalyses spec analyses; | _ -> () let enableAnalysesForMemSafetySpecification () = @@ -49,8 +48,7 @@ let enableAnalysesForTerminationSpecification (spec: Svcomp.Specification.t) = match spec with | Termination -> (* Enable the soundness analyses for Termination spec *) let analyses = ["termination"] in - logEnablingAnalyses spec analyses; - enableAnalyses analyses + enableSpecAnalyses spec analyses; | _ -> () let enableAnalysesForTerminationSpecification () = @@ -61,8 +59,7 @@ let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = | UnreachCall s -> () | NoDataRace -> (* Enable the soundness analyses for NoDataRace spec *) let analyses = ["access"; "race"] in - logEnablingAnalyses spec analyses; - enableAnalyses analyses + enableSpecAnalyses spec analyses; | NoOverflow -> (* Enable the soundness analyses for NoOverflow spec *) let options = ["ana.int.interval"] in enableOptions options From 34fcbc8409ac199cd1658e6d553452b49b70234f Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:29:47 +0300 Subject: [PATCH 236/689] Inline variables that are used once and remove excessive comments --- src/autoSoundConfig.ml | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/autoSoundConfig.ml b/src/autoSoundConfig.ml index 12674bec41..50c8884b48 100644 --- a/src/autoSoundConfig.ml +++ b/src/autoSoundConfig.ml @@ -27,18 +27,12 @@ let enableOptions options = *) let enableAnalysesForMemSafetySpecification (spec: Svcomp.Specification.t) = match spec with - | ValidFree -> (* Enable the soundness analyses for ValidFree spec *) - let analyses = ["base"; "useAfterFree"] in - enableSpecAnalyses spec analyses; - | ValidDeref -> (* Enable the soundness analyses for ValidDeref spec *) - let analyses = ["base"; "memOutOfBounds"] in - enableSpecAnalyses spec analyses; - let options = ["ana.arrayoob"; "cil.addNestedScopeAttr"] in - enableOptions options + | ValidFree -> enableSpecAnalyses spec ["base"; "useAfterFree"]; + | ValidDeref -> + enableSpecAnalyses spec ["base"; "memOutOfBounds"]; + enableOptions ["ana.arrayoob"; "cil.addNestedScopeAttr"] | ValidMemtrack - | ValidMemcleanup -> (* Enable the soundness analyses for ValidMemtrack and ValidMemcleanup specs *) - let analyses = ["memLeak"] in - enableSpecAnalyses spec analyses; + | ValidMemcleanup -> enableSpecAnalyses spec ["memLeak"]; | _ -> () let enableAnalysesForMemSafetySpecification () = @@ -46,9 +40,7 @@ let enableAnalysesForMemSafetySpecification () = let enableAnalysesForTerminationSpecification (spec: Svcomp.Specification.t) = match spec with - | Termination -> (* Enable the soundness analyses for Termination spec *) - let analyses = ["termination"] in - enableSpecAnalyses spec analyses; + | Termination -> enableSpecAnalyses spec ["termination"]; | _ -> () let enableAnalysesForTerminationSpecification () = @@ -57,12 +49,8 @@ let enableAnalysesForTerminationSpecification () = let enableAnalysesForSpecification (spec: Svcomp.Specification.t) = match spec with | UnreachCall s -> () - | NoDataRace -> (* Enable the soundness analyses for NoDataRace spec *) - let analyses = ["access"; "race"] in - enableSpecAnalyses spec analyses; - | NoOverflow -> (* Enable the soundness analyses for NoOverflow spec *) - let options = ["ana.int.interval"] in - enableOptions options + | NoDataRace -> enableSpecAnalyses spec ["access"; "race"]; + | NoOverflow -> enableOptions ["ana.int.interval"] | _ -> () let enableAnalysesForSpecification () = From 18c1fe039b198039277dfb606eeecd1c4ffc0958 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 22 May 2024 15:32:29 +0300 Subject: [PATCH 237/689] Move autoSoundConfig from `src` to `src/util` --- src/{ => util}/autoSoundConfig.ml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => util}/autoSoundConfig.ml (100%) diff --git a/src/autoSoundConfig.ml b/src/util/autoSoundConfig.ml similarity index 100% rename from src/autoSoundConfig.ml rename to src/util/autoSoundConfig.ml From dfeb71537c731b2c839afe04df1379f799f74fb5 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 22 May 2024 14:59:16 +0200 Subject: [PATCH 238/689] sign errors corrected --- .../apron/linearTwoVarEqualityDomain.apron.ml | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 6346dc0975..d51bebb332 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -41,7 +41,8 @@ module Rhs = struct let gcd = match v with | Some (c,_) -> Z.gcd c gcd | None -> gcd - in (BatOption.map (fun (coeff,i) -> (Z.div coeff gcd,i)) v,Z.div o gcd, Z.div d gcd) + in let gcd = if (Z.(lt d Z.zero)) then Z.neg gcd else gcd in + (BatOption.map (fun (coeff,i) -> (Z.div coeff gcd,i)) v,Z.div o gcd, Z.div d gcd) (** Substitute rhs for varx in rhs' *) let subst rhs varx rhs' = @@ -238,7 +239,7 @@ module EqualitiesConjunction = struct let (_,newh1)= inverse i (coeff1,h1,o1,divi1) in let newh1 = Rhs.subst normalizedj j (Rhs.subst (Some(coeff,j),offs,divi) i newh1) in subst_var ts h1 newh1)) in - if M.tracing then M.trace "meet" "meet_with_one_conj conj: { %s } eq: var_%d=%s -> { %s } " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd ts)) + if M.tracing then M.trace "meet_with_one_conj" "meet_with_one_conj conj: %s eq: var_%d=%s -> %s " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd ts)) ; res (** affine transform variable i allover conj with transformer (Some (coeff,i)+offs)/divi *) @@ -331,6 +332,12 @@ struct let constant = List.fold_left accumulate_constants (Z.zero,Z.one) monomiallist in (* abstract simplification of the guard wrt. reference variables *) Some (Array.fold_lefti (fun list v (c) -> if Q.equal c Q.zero then list else (c.num,v,c.den)::list) [] expr, constant) ) + let simplified_monomials_from_texp (t: t) texp = + let res = simplified_monomials_from_texp t texp in + if M.tracing then M.tracel "from_texp" "%s %s -> %s" (EConj.show @@ snd @@ BatOption.get t.d) (Format.asprintf "%a" Texpr1.print_expr texp) + (BatOption.map_default (fun (l,(o,d)) -> List.fold_right (fun (a,x,b) acc -> Printf.sprintf "%s*var_%d/%s + %s" (Z.to_string a) x (Z.to_string b) acc) l ((Z.to_string o)^"/"^(Z.to_string d))) "" res); + res + let simplify_to_ref_and_offset (t: t) texp = BatOption.bind (simplified_monomials_from_texp t texp ) (fun (sum_of_terms, (constant,divisor)) -> @@ -403,15 +410,22 @@ struct (** is_top returns true for top_of array and empty array; precondition: t.env and t.d are of same size *) let is_top t = Environment.equal empty_env t.env && GobOption.exists EConj.is_top_con t.d + let to_subscript i = + let transl = [|"₀";"₁";"₂";"₃";"₄";"₅";"₆";"₇";"₈";"₉"|] in + let rec subscr i = + if i = 0 then "" + else (subscr (i/10)) ^ transl.(i mod 10) in + subscr i + + let show_var env i = + let transl = [|"₀";"₁";"₂";"₃";"₄";"₅";"₆";"₇";"₈";"₉"|] in + let res = Var.to_string (Environment.var_of_dim env i) in + match String.split_on_char '#' res with + | varname::rest::[] -> varname ^ (try String.fold_left (fun acc c -> acc ^ transl.(Char.code c - Char.code '0')) "" rest with _ -> "#"^rest) + | _ -> failwith "Variable name not found" + (** prints the current variable equalities with resolved variable names *) let show varM = - let lookup i = - let transl = [|"₀";"₁";"₂";"₃";"₄";"₅";"₆";"₇";"₈";"₉"|] in - let res = Var.to_string (Environment.var_of_dim varM.env i) in - match String.split_on_char '#' res with - | varname::rest::[] -> varname ^ (try String.fold_left (fun acc c -> acc ^ transl.(Char.code c - Char.code '0')) "" rest with _ -> "#"^rest) - | _ -> failwith "Variable name not found" - in match varM.d with | None -> "⊥\n" | Some arr when EConj.is_top_con arr -> "⊤\n" @@ -419,7 +433,7 @@ struct if is_bot varM then "Bot \n" else - EConj.show_formatted lookup (snd arr) ^ (" with dimension " ^ (string_of_int @@ fst arr)) + EConj.show_formatted (show_var varM.env) (snd arr) ^ (to_subscript @@ fst arr) let pretty () (x:t) = text (show x) let printXml f x = BatPrintf.fprintf f "\n\n\nequalities\n\n\n%s\n\nenv\n\n\n%s\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) (XmlUtil.escape (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (x.env))) @@ -437,7 +451,7 @@ struct let meet_with_one_conj t i e = let res = meet_with_one_conj t i e in - if M.tracing then M.trace "meet" "meet_with_one_conj %s with var_%d=%s -> %s" (show t) i (Rhs.show e) (show res); + if M.tracing then M.trace "meet" "%s with single eq %s=%s -> %s" (show t) (show_var t.env i) (Rhs.show_rhs_formatted (show_var t.env) e) (show res); res let meet t1 t2 = @@ -517,7 +531,7 @@ struct in let iterate map l = match l with - | (idx_h, _, _, rhs_h, _) :: t -> List.fold (fun acc e -> modify acc idx_h rhs_h e) map l + | (idx_h, _, _, rhs_h, _) :: t -> List.fold (fun acc e -> modify acc idx_h rhs_h e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) @@ -717,7 +731,7 @@ struct end | [(coeff, index, divi)] -> (* guard has a single reference variable only *) if Tcons1.get_typ tcons = EQ then - meet_with_one_conj t index (Rhs.canonicalize (None, Z.(divi*constant),Z.(coeff*divisor))) + meet_with_one_conj t index (Rhs.canonicalize (None, Z.neg @@ Z.(divi*constant),Z.(coeff*divisor))) else t (* only EQ is supported in equality based domains *) | [(c1,var1,d1); (c2,var2,d2)] -> (* two variables in relation needs a little sorting out *) From c6928c58a426674077bd38a5a02149edefc89745 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 22 May 2024 15:10:02 +0200 Subject: [PATCH 239/689] do not enforce pattern on variable names --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index d51bebb332..60e8f50d9d 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -422,7 +422,7 @@ struct let res = Var.to_string (Environment.var_of_dim env i) in match String.split_on_char '#' res with | varname::rest::[] -> varname ^ (try String.fold_left (fun acc c -> acc ^ transl.(Char.code c - Char.code '0')) "" rest with _ -> "#"^rest) - | _ -> failwith "Variable name not found" + | _ -> res (** prints the current variable equalities with resolved variable names *) let show varM = From ada7065af6bd9c276a0de59e96822bdf0ff4e504 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Wed, 22 May 2024 22:44:09 +0200 Subject: [PATCH 240/689] migration to appendix A - join (part 1) --- .../apron/linearTwoVarEqualityDomain.apron.ml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 60e8f50d9d..8f9694de2c 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -503,7 +503,21 @@ struct - rhs1 - rhs2 however, we have to account for the sparseity of EConj maps by manually patching holes with default values *) - let joinfunction lhs rhs1 rhs2 = let coeff = Option.map_default fst Z.one in match rhs1, rhs2 with + let joinfunction lhs rhs1 rhs2 = + let pairing = match rhs1,rhs2 with (* first of all re-instantiate implicit sparse elements *) + | Some a, Some b -> Some (a,b) + | None, Some b -> Some (Rhs.var_zero lhs,b) + | Some a, None -> Some (a,Rhs.var_zero lhs) + | _ -> None + in let _= BatOption.map (function + | (Some (c1,var1),o1,d1) as r1 ,(Some (c2,var2),o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 + | (None, o1,d1) as r1, (Some (c2,var2),o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 + | (Some (c1,var1),o1,d1) as r1, (None ,o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 + | (None, o1,d1) as r1, (None ,o2,d2) as r2 -> + let magicnumber=Z.((o1/d1)-(o2/d2)) in + lhs, Q.make Z.(o1/magicnumber) Z.one,Q.make Z.(o1 mod magicnumber) Z.one,r1, r2 + ) pairing in () ; + let coeff = Option.map_default fst Z.one in match rhs1, rhs2 with (* Compute Ax+B such that (coeff1*(Ax+B)+off1)/d1 = (coeff2*x+off2)/d2 *) (* ====> A = (coeff2*d1)/(coeff1*d2) /\ B = (off2*d1-off1*d2)/(c1*c2) *) (* lhs A B rhs1 rhs2 *) From 366b04c2e2244276fde4963089da372c26439451 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 22 May 2024 15:39:15 +0200 Subject: [PATCH 241/689] error in tracing --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 8f9694de2c..e953a420a4 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -239,7 +239,7 @@ module EqualitiesConjunction = struct let (_,newh1)= inverse i (coeff1,h1,o1,divi1) in let newh1 = Rhs.subst normalizedj j (Rhs.subst (Some(coeff,j),offs,divi) i newh1) in subst_var ts h1 newh1)) in - if M.tracing then M.trace "meet_with_one_conj" "meet_with_one_conj conj: %s eq: var_%d=%s -> %s " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd ts)) + if M.tracing then M.trace "meet_with_one_conj" "meet_with_one_conj conj: %s eq: var_%d=%s -> %s " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd res)) ; res (** affine transform variable i allover conj with transformer (Some (coeff,i)+offs)/divi *) @@ -451,7 +451,7 @@ struct let meet_with_one_conj t i e = let res = meet_with_one_conj t i e in - if M.tracing then M.trace "meet" "%s with single eq %s=%s -> %s" (show t) (show_var t.env i) (Rhs.show_rhs_formatted (show_var t.env) e) (show res); + if M.tracing then M.tracel "meet" "%s with single eq %s=%s -> %s" (show t) (Z.(to_string @@ Tuple3.third e)^ show_var t.env i) (Rhs.show_rhs_formatted (show_var t.env) e) (show res); res let meet t1 t2 = From cb3b486b680ceff271afc0afda68a9b639bfb01d Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Thu, 23 May 2024 09:19:21 +0200 Subject: [PATCH 242/689] join of two different constants still remains in one equivalence class --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index e953a420a4..a5d27fec39 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -343,7 +343,7 @@ struct (fun (sum_of_terms, (constant,divisor)) -> (match sum_of_terms with | [] -> Some (None, constant,divisor) - | [(coeff,var,divi)] when Z.equal coeff Z.one -> Some (Rhs.canonicalize (Some (Z.mul divisor coeff,var), Z.mul constant divi,Z.mul divisor divi)) + | [(coeff,var,divi)] -> Some (Rhs.canonicalize (Some (Z.mul divisor coeff,var), Z.mul constant divi,Z.mul divisor divi)) |_ -> None)) let simplify_to_ref_and_offset t texp = timing_wrap "coeff_vec" (simplify_to_ref_and_offset t) texp @@ -514,8 +514,7 @@ struct | (None, o1,d1) as r1, (Some (c2,var2),o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 | (Some (c1,var1),o1,d1) as r1, (None ,o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 | (None, o1,d1) as r1, (None ,o2,d2) as r2 -> - let magicnumber=Z.((o1/d1)-(o2/d2)) in - lhs, Q.make Z.(o1/magicnumber) Z.one,Q.make Z.(o1 mod magicnumber) Z.one,r1, r2 + lhs, Q.make Z.((o1*d2)-(o2*d1)) Z.(d1*d2), Q.zero, r1, r2 ) pairing in () ; let coeff = Option.map_default fst Z.one in match rhs1, rhs2 with (* Compute Ax+B such that (coeff1*(Ax+B)+off1)/d1 = (coeff2*x+off2)/d2 *) @@ -543,9 +542,9 @@ struct let coeff1 = Option.map_default fst Z.one monom1 in (Some (Z.(coeff1*divi),x), Z.((z1*refcoeff)-(offs*coeff1)), Z.(refcoeff*d1)) ) in - let iterate map l = + let iterate map l = match l with - | (idx_h, _, _, rhs_h, _) :: t -> List.fold (fun acc e -> modify acc idx_h rhs_h e) map l + | (idx_h, a, b, rhs_h, _) :: t -> M.trace "join" " join me in dept %s %s" (Q.to_string a) (Q.to_string b); List.fold (fun acc e -> modify acc idx_h rhs_h e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From 58c4e7dc08079b10fbe553b69e359485dfc4f930 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Thu, 23 May 2024 10:33:52 +0200 Subject: [PATCH 243/689] made join criteria much more legible --- .../apron/linearTwoVarEqualityDomain.apron.ml | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index a5d27fec39..ff4d19414f 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -499,32 +499,23 @@ struct (* joinfunction handles the dirty details of performing an "inner join" on the lhs of both bindings; in the resulting binding, the lhs is then mapped to values that are later relevant for sorting/grouping, i.e. - lhs itself - - the affine transformation from refvar1 to refvar2, i.E. the parameters A and B of the general affine transformer Ax+B + - criteria A and B that characterize equivalence class, depending on the reference variable and the affine expression parameters wrt. each EConj - rhs1 - rhs2 however, we have to account for the sparseity of EConj maps by manually patching holes with default values *) let joinfunction lhs rhs1 rhs2 = - let pairing = match rhs1,rhs2 with (* first of all re-instantiate implicit sparse elements *) - | Some a, Some b -> Some (a,b) - | None, Some b -> Some (Rhs.var_zero lhs,b) - | Some a, None -> Some (a,Rhs.var_zero lhs) - | _ -> None - in let _= BatOption.map (function - | (Some (c1,var1),o1,d1) as r1 ,(Some (c2,var2),o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 - | (None, o1,d1) as r1, (Some (c2,var2),o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 - | (Some (c1,var1),o1,d1) as r1, (None ,o2,d2) as r2 -> lhs, Q.one, Q.one, r1, r2 - | (None, o1,d1) as r1, (None ,o2,d2) as r2 -> - lhs, Q.make Z.((o1*d2)-(o2*d1)) Z.(d1*d2), Q.zero, r1, r2 - ) pairing in () ; - let coeff = Option.map_default fst Z.one in match rhs1, rhs2 with - (* Compute Ax+B such that (coeff1*(Ax+B)+off1)/d1 = (coeff2*x+off2)/d2 *) - (* ====> A = (coeff2*d1)/(coeff1*d2) /\ B = (off2*d1-off1*d2)/(c1*c2) *) - (* lhs A B rhs1 rhs2 *) - (*TODO*: if this works, make it more concise *) - | Some (ai,aj,ak), Some (bi,bj,bk) -> Some (lhs,Q.make Z.(ak*coeff bi) Z.(bk* coeff ai),Q.make Z.(bj*ak-aj*bk) Z.(bk*coeff ai), (ai,aj,ak) , (bi,bj,bk)) (* this is explicitely what we want *) - | None , Some (bi,bj,bk) -> Some (lhs,Q.make Z.( coeff bi) Z.(bk ),Q.make Z.(bj ) Z.(bk ), Rhs.var_zero lhs, (bi,bj,bk)) (* account for the sparseity of binding 1 *) - | Some (ai,aj,ak), None -> Some (lhs,Q.make Z.(ak ) Z.( coeff ai),Q.make Z.( neg aj) Z.( coeff ai), (ai,aj,ak), Rhs.var_zero lhs) (* account for the sparseity of binding 2 *) - | _,_ -> None (* no binding for lhs in both maps is replicated implicitely in a sparse result map *) + (match rhs1,rhs2 with (* first of all re-instantiate implicit sparse elements *) + | Some a, Some b -> Some (a,b) + | None, Some b -> Some (Rhs.var_zero lhs,b) + | Some a, None -> Some (a,Rhs.var_zero lhs) + | _ -> None) + |> + BatOption.map (fun (r1,r2) -> match (r1,r2) with (* criterion A , criterion B *) + | (Some (c1,_),o1,d1), (Some (c2,_),o2,d2)-> lhs, Q.make Z.((o1*d2)-(o2*d1)) Z.(c1*d2), Q.make Z.(c2*d2) Z.(c1*d1), r1, r2 + | (None, oc,dc), (Some (cv,_),ov,dv) + | (Some (cv,_),ov,dv), (None ,oc,dc)-> lhs, Q.make Z.((oc*dv)-(ov*dc)) Z.(dc*cv), Q.one , r1, r2 (* equivalence class defined by (oc/dc-ov/dv)/(cv/dv) *) + | (None, o1,d1), (None ,o2,d2)-> lhs, (if Z.(zero = ((o1*d2)-(o2*d1))) then Q.one else Q.zero), Q.zero, r1, r2 (* only two equivalence classes: constants with matching values or constants with different values *) + ) in let table = List.of_enum @@ EConj.IntMap.values @@ EConj.IntMap.merge joinfunction (snd ad) (snd bd) in (* compare two variables for grouping depending on affine function parameters a, b and reference variable indices *) @@ -544,7 +535,7 @@ struct in let iterate map l = match l with - | (idx_h, a, b, rhs_h, _) :: t -> M.trace "join" " join me in dept %s %s" (Q.to_string a) (Q.to_string b); List.fold (fun acc e -> modify acc idx_h rhs_h e) map l + | (idx_h, a, b, rhs_h, _) :: t -> M.trace "join" " iterate through equivalence group with a=%s and b=%s" (Q.to_string a) (Q.to_string b); List.fold (fun acc e -> modify acc idx_h rhs_h e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From 57a074190a470ff3f2c85e1f1669555c4a58a3f6 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 23 May 2024 11:22:52 +0200 Subject: [PATCH 244/689] Add example for unsoundness due to escape --- .../46-apron2/86-escape-cluster12.c | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/regression/46-apron2/86-escape-cluster12.c diff --git a/tests/regression/46-apron2/86-escape-cluster12.c b/tests/regression/46-apron2/86-escape-cluster12.c new file mode 100644 index 0000000000..283e45b728 --- /dev/null +++ b/tests/regression/46-apron2/86-escape-cluster12.c @@ -0,0 +1,21 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.relation.privatization mutex-meet-tid-cluster12 +#include +#include +void *a; + +void* nothing(void* arg) { + // Go multithreaded! +} + +void main() { + pthread_t t; + pthread_create(&t, 0, nothing, 0); + + int d = 5; + a = &d; + + if (0) + ; + + __goblint_check(1); // Should be reachable! +} From b5fed0874204e5f12e90eceaa23601653c35dae8 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Thu, 23 May 2024 16:32:21 +0200 Subject: [PATCH 245/689] added case distinction for equivalence classes --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index ff4d19414f..e49b3a0f93 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -535,7 +535,11 @@ struct in let iterate map l = match l with - | (idx_h, a, b, rhs_h, _) :: t -> M.trace "join" " iterate through equivalence group with a=%s and b=%s" (Q.to_string a) (Q.to_string b); List.fold (fun acc e -> modify acc idx_h rhs_h e) map l + | (x, a, b, ((Some _,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> M.trace "join" "handle var-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((Some _,_,_) as rhs), ((None,_,_) as rhs')) :: t -> M.trace "join" "handle var-const equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((None,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> M.trace "join" "handle const-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((None,o1,d1) as rhs), ((None,o2,d2) )) :: t when (o1,d1)=(o2,d2) -> M.trace "join" "handle const-const equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((None,_,_) as rhs), ((None,_,_) as rhs')) :: t -> M.trace "join" "handle const1-const2 equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From 7c6a86eae97ac4f376bf32053538f4b565c1ef2e Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 23 May 2024 17:40:38 +0200 Subject: [PATCH 246/689] Fix gloabl_init for escaped globals in cluster configuration --- src/analyses/apron/relationPriv.apron.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index dd4b65bab8..61da6ddc42 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -813,7 +813,9 @@ struct let g_var = V.global g in (* normal (strong) mapping: contains only still fully protected *) let g' = VS.singleton g in - let oct = LRD.find g' octs in + (* If there is no map entry yet which contains the global, default to top rather than bot *) + (* Happens e.g. in 46/86 because of escape *) + let oct = Option.default (RD.top ()) (LRD.find_opt g' octs) in LRD.singleton g' (RD.keep_vars oct [g_var]) let lock_get_m oct local_m get_m = From 083d1ea88a95cf0277ae8cbfeff07c658ff4b83c Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Thu, 23 May 2024 20:13:37 +0200 Subject: [PATCH 247/689] satisfy semgrep --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index e49b3a0f93..89cead570b 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -535,11 +535,11 @@ struct in let iterate map l = match l with - | (x, a, b, ((Some _,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> M.trace "join" "handle var-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((Some _,_,_) as rhs), ((None,_,_) as rhs')) :: t -> M.trace "join" "handle var-const equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((None,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> M.trace "join" "handle const-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((None,o1,d1) as rhs), ((None,o2,d2) )) :: t when (o1,d1)=(o2,d2) -> M.trace "join" "handle const-const equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((None,_,_) as rhs), ((None,_,_) as rhs')) :: t -> M.trace "join" "handle const1-const2 equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((Some _,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle var-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((Some _,_,_) as rhs), ((None,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle var-const equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((None,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle const-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((None,o1,d1) as rhs), ((None,o2,d2) )) :: t when (o1,d1)=(o2,d2) -> if M.tracing then M.trace "join" "handle const-const equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l + | (x, a, b, ((None,_,_) as rhs), ((None,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle const1-const2 equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From c6336515f17183f95e9dfc8a20e225067f94cc06 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Thu, 23 May 2024 22:13:41 +0200 Subject: [PATCH 248/689] join carried out for const cases --- .../apron/linearTwoVarEqualityDomain.apron.ml | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 89cead570b..6967d0371d 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -525,21 +525,21 @@ struct in (* Calculate new components as groups *) let new_components = BatList.group cmp_z table in - (* Adjust the domain map to represent the new components *) - let modify map x (refmonom, offs, divi) (idx, _, _, (monom1, z1, d1), (monom2, z2, d2)) = EConj.set_rhs map (idx) - (if monom1 = monom2 && Z.equal z1 z2 && Z.equal d1 d2 then (monom1, z1, d1) - else - let refcoeff = Option.map_default fst Z.one refmonom in - let coeff1 = Option.map_default fst Z.one monom1 in - (Some (Z.(coeff1*divi),x), Z.((z1*refcoeff)-(offs*coeff1)), Z.(refcoeff*d1)) ) - in + + (* ci1 = a*ch1+b /\ ci2 = a*ch2+b *) + (* ===> a = (ci1-ci2)/(ch1-ch2) b = ci2-a*ch2 *) + let constentry ci1 ci2 ch1 ch2 xh = + let a = Q.((ci1-ci2) / (ch1-ch2)) in + let b= Q.(ci2 - a*ch2) in + let anum=a.num and aden=a.den and bnum=b.num and bden=b.den in + Rhs.canonicalize (Some (Z.(anum*bden),xh),Z.(bnum*aden) ,Z.(aden*bden) ) in let iterate map l = match l with - | (x, a, b, ((Some _,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle var-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((Some _,_,_) as rhs), ((None,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle var-const equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((None,_,_) as rhs), ((Some _,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle const-var equivalence group"; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((None,o1,d1) as rhs), ((None,o2,d2) )) :: t when (o1,d1)=(o2,d2) -> if M.tracing then M.trace "join" "handle const-const equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l - | (x, a, b, ((None,_,_) as rhs), ((None,_,_) as rhs')) :: t -> if M.tracing then M.trace "join" "handle const1-const2 equivalence group" ; List.fold (fun acc e -> modify acc x rhs e) map l + | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> if M.tracing then M.trace "join" "handle var-var class"; List.fold (fun acc e -> acc) map t + | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> if M.tracing then M.trace "join" "handle var-const class"; List.fold (fun acc e -> acc) map t + | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> if M.tracing then M.trace "join" "handle const-var class"; List.fold (fun acc e -> acc) map t + | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> if M.tracing then M.trace "join" "handle const-const class" ; List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l + | (h, _, _, ((None,oh1,dh1) ), ((None),oh2,dh2) ) :: t -> if M.tracing then M.trace "join" "handle const1-const2 class" ; List.fold (fun acc (i,_,_,(_,oi1,di1),(_,oi2,di2)) -> EConj.set_rhs acc i (constentry Q.(make oi1 di1) Q.(make oi2 di2) (Q.make oh1 dh1) (Q.make oh2 dh2) h)) map t | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From 9e4cd5892b9ba8f9ed1d0c97e4d16586b7bdfcc8 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 09:53:34 +0200 Subject: [PATCH 249/689] migration to appendix A - join (part 2) --- .../apron/linearTwoVarEqualityDomain.apron.ml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 6967d0371d..2e3b473fcc 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -525,21 +525,25 @@ struct in (* Calculate new components as groups *) let new_components = BatList.group cmp_z table in - + let varentry ci offi ch offh xh = + let (coeff,off,d) = Q.(ci,(offi*ch)-(ci*offh),ch) in (* compute new rhs in Q *) + let (coeff,off,d) = Z.(coeff.num*d.den*off.den,off.num*d.den*coeff.den,d. num*coeff.den*off.den) in (* convert that back into Z *) + Rhs.canonicalize (Some(coeff,xh),off,d) + in (* ci1 = a*ch1+b /\ ci2 = a*ch2+b *) (* ===> a = (ci1-ci2)/(ch1-ch2) b = ci2-a*ch2 *) let constentry ci1 ci2 ch1 ch2 xh = let a = Q.((ci1-ci2) / (ch1-ch2)) in - let b= Q.(ci2 - a*ch2) in + let b = Q.(ci2 - a*ch2) in let anum=a.num and aden=a.den and bnum=b.num and bden=b.den in Rhs.canonicalize (Some (Z.(anum*bden),xh),Z.(bnum*aden) ,Z.(aden*bden) ) in let iterate map l = match l with - | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> if M.tracing then M.trace "join" "handle var-var class"; List.fold (fun acc e -> acc) map t - | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> if M.tracing then M.trace "join" "handle var-const class"; List.fold (fun acc e -> acc) map t - | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> if M.tracing then M.trace "join" "handle const-var class"; List.fold (fun acc e -> acc) map t - | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> if M.tracing then M.trace "join" "handle const-const class" ; List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l - | (h, _, _, ((None,oh1,dh1) ), ((None),oh2,dh2) ) :: t -> if M.tracing then M.trace "join" "handle const1-const2 class" ; List.fold (fun acc (i,_,_,(_,oi1,di1),(_,oi2,di2)) -> EConj.set_rhs acc i (constentry Q.(make oi1 di1) Q.(make oi2 di2) (Q.make oh1 dh1) (Q.make oh2 dh2) h)) map t + | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(Some (ci,_),oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t + | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> List.fold (fun acc (i,_,_,(Some (ci,_),oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t + | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> List.fold (fun acc (i,_,_,_,(Some (ci,_),oi,di)) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t + | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l + | (h, _, _, ((None,oh1,dh1) ), ((None),oh2,dh2) ) :: t -> List.fold (fun acc (i,_,_,(_,oi1,di1),(_,oi2,di2)) -> EConj.set_rhs acc i (constentry Q.(make oi1 di1) Q.(make oi2 di2) Q.(make oh1 dh1) Q.(make oh2 dh2) h)) map t | [] -> let exception EmptyComponent in raise EmptyComponent in Some (List.fold iterate (EConj.make_empty_conj @@ fst ad) new_components) From e290d3c2556fc91ec4a5f3371c65f8e2d23b5036 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 10:07:28 +0200 Subject: [PATCH 250/689] added regression test for coefficient-heavy transactions --- .../77-lin2vareq/34-coefficient-features.c | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/regression/77-lin2vareq/34-coefficient-features.c diff --git a/tests/regression/77-lin2vareq/34-coefficient-features.c b/tests/regression/77-lin2vareq/34-coefficient-features.c new file mode 100644 index 0000000000..4a0469a40d --- /dev/null +++ b/tests/regression/77-lin2vareq/34-coefficient-features.c @@ -0,0 +1,69 @@ +//SKIP PARAM: --set ana.activated[+] lin2vareq --set sem.int.signed_overflow assume_none +// this test checks basic coefficient handing in main and join capabilities in loop + +#include + +void loop() { + int random; + int i = 0; + int x = 0; + int y = 0; + + x=x+4; + y=y+8; + i=i+1; + + if (random) { + x=x+4; + y=y+8; + i=i+1; + } + + __goblint_check(x == 4*i); //SUCCESS + + for(i = 1; i < 100; i++) { + x=x+4; + y=y+8; + + __goblint_check(y == 2*x); //SUCCESS + } + + x=0; + y=0; + + for(i = 1; i < 100; i++) { + x=x+4; + y=y+8; + + __goblint_check(y == 2*x); //SUCCESS + __goblint_check(x == 4*i); //SUCCESS + } +} + +void main() { + int a; + int b; + int c; + int unknown; + a = 4; + + b = 4*c; + + __goblint_check(b == 4*c); //SUCCESS + + b = a*c; + + __goblint_check(b == 4*c); //SUCCESS + + if (5*b == 20*unknown + a){ + + __goblint_check(5*b == 20*unknown + a); //SUCCESS + } + + b = unknown ? a*c : 4*c; + + __goblint_check(b == 4*c); //SUCCESS + + loop(); + +} \ No newline at end of file From 9de6f858fcdf8526208e5041aba22036517365ee Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 10:59:26 +0200 Subject: [PATCH 251/689] make coefficents in regression coprime, and flex with propagation of 2var relations --- tests/regression/77-lin2vareq/34-coefficient-features.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/regression/77-lin2vareq/34-coefficient-features.c b/tests/regression/77-lin2vareq/34-coefficient-features.c index 4a0469a40d..b415f4398a 100644 --- a/tests/regression/77-lin2vareq/34-coefficient-features.c +++ b/tests/regression/77-lin2vareq/34-coefficient-features.c @@ -26,6 +26,10 @@ void loop() { y=y+8; __goblint_check(y == 2*x); //SUCCESS + + int res = (y==2*x )+ 1; + + __goblint_check(res); //SUCCESS } x=0; @@ -55,9 +59,9 @@ void main() { __goblint_check(b == 4*c); //SUCCESS - if (5*b == 20*unknown + a){ + if (7*b == 20*unknown + a){ - __goblint_check(5*b == 20*unknown + a); //SUCCESS + __goblint_check(7*b == 20*unknown + a); //SUCCESS } b = unknown ? a*c : 4*c; From 3291633f1a1dde4fff71751ac567f5986b05d0e1 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 11:00:06 +0200 Subject: [PATCH 252/689] wave through var-var equivalences if var1=var2 --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 2e3b473fcc..8dc4a71e90 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -539,10 +539,10 @@ struct Rhs.canonicalize (Some (Z.(anum*bden),xh),Z.(bnum*aden) ,Z.(aden*bden) ) in let iterate map l = match l with + | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(Some (ci,_),oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> List.fold (fun acc (i,_,_,(Some (ci,_),oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> List.fold (fun acc (i,_,_,_,(Some (ci,_),oi,di)) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t - | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l | (h, _, _, ((None,oh1,dh1) ), ((None),oh2,dh2) ) :: t -> List.fold (fun acc (i,_,_,(_,oi1,di1),(_,oi2,di2)) -> EConj.set_rhs acc i (constentry Q.(make oi1 di1) Q.(make oi2 di2) Q.(make oh1 dh1) Q.(make oh2 dh2) h)) map t | [] -> let exception EmptyComponent in raise EmptyComponent in From 83d7fb8f263a64b71e10872ae5691d56e08ee327 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 11:05:21 +0200 Subject: [PATCH 253/689] removed warning 8 --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 8dc4a71e90..9d744ad926 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -540,9 +540,9 @@ struct let iterate map l = match l with | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l - | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(Some (ci,_),oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t - | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> List.fold (fun acc (i,_,_,(Some (ci,_),oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t - | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> List.fold (fun acc (i,_,_,_,(Some (ci,_),oi,di)) -> EConj.set_rhs acc i (varentry Q.(make ci di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t + | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(monom,oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t + | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> List.fold (fun acc (i,_,_,(monom,oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t + | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> List.fold (fun acc (i,_,_,_,(monom,oi,di)) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t | (h, _, _, ((None,oh1,dh1) ), ((None),oh2,dh2) ) :: t -> List.fold (fun acc (i,_,_,(_,oi1,di1),(_,oi2,di2)) -> EConj.set_rhs acc i (constentry Q.(make oi1 di1) Q.(make oi2 di2) Q.(make oh1 dh1) Q.(make oh2 dh2) h)) map t | [] -> let exception EmptyComponent in raise EmptyComponent in From 16c8e6567a09836a684e56c0a3fcd8a5a55a0933 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 13:25:47 +0200 Subject: [PATCH 254/689] got rid of unnecessarily largearray --- .../apron/linearTwoVarEqualityDomain.apron.ml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 9d744ad926..d3beadbb9f 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -290,7 +290,6 @@ struct in let rec convert_texpr texp = begin match texp with - (* If x is a constant, replace it with its const. val. immediately *) | Cst (Interval _) -> failwith "constant was an interval; this is not supported" | Cst (Scalar x) -> begin match SharedFunctions.int_of_scalar ?round:None x with @@ -322,15 +321,15 @@ struct BatOption.bind (monomials_from_texp t texp) (fun monomiallist -> let d = Option.get t.d in - let expr = Array.make (Environment.size t.env) (Q.zero) in (*TODO*: migrate to map; array of coeff/divisor per var idx*) - let accumulate_constants (aconst,adiv) (v,offs,divi) = match v with - | None -> let gcdee = Z.gcd adiv divi in (Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi) + let accumulate_constants (exprcache,(aconst,adiv)) (v,offs,divi) = match v with + | None -> let gcdee = Z.gcd adiv divi in exprcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi) | Some (coeff,idx) -> let (somevar,someoffs,somedivi)=Rhs.subst (EConj.get_rhs d idx) idx (v,offs,divi) in (* normalize! *) - (Option.may (fun (coef,ter) -> expr.(ter) <- Q.(expr.(ter) + Q.make coef somedivi)) somevar; - let gcdee = Z.gcd adiv divi in (Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi)) + let newcache = Option.map_default (fun (coef,ter) -> EConj.IntMap.add ter Q.((EConj.IntMap.find_default zero ter exprcache) + make coef somedivi) exprcache) exprcache somevar in + let gcdee = Z.gcd adiv divi in + (newcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi)) in - let constant = List.fold_left accumulate_constants (Z.zero,Z.one) monomiallist in (* abstract simplification of the guard wrt. reference variables *) - Some (Array.fold_lefti (fun list v (c) -> if Q.equal c Q.zero then list else (c.num,v,c.den)::list) [] expr, constant) ) + let (expr,constant) = List.fold_left accumulate_constants (EConj.IntMap.empty,(Z.zero,Z.one)) monomiallist in (* abstract simplification of the guard wrt. reference variables *) + Some (EConj.IntMap.fold (fun v c acc -> if Q.equal c Q.zero then acc else (Q.num c,v,Q.den c)::acc) expr [], constant) ) let simplified_monomials_from_texp (t: t) texp = let res = simplified_monomials_from_texp t texp in @@ -348,7 +347,6 @@ struct let simplify_to_ref_and_offset t texp = timing_wrap "coeff_vec" (simplify_to_ref_and_offset t) texp - (* Copy because function is not "with" so should not mutate inputs *) let assign_const t var const divi = match t.d with | None -> t | Some t_d -> {d = Some (EConj.set_rhs t_d var (None, const, divi)); env = t.env} From aded7d59eaa7153134b6f71ed89aae85e9eea893 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 14:03:46 +0200 Subject: [PATCH 255/689] rm redundancies --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index d3beadbb9f..5bd68cc858 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -416,10 +416,9 @@ struct subscr i let show_var env i = - let transl = [|"₀";"₁";"₂";"₃";"₄";"₅";"₆";"₇";"₈";"₉"|] in let res = Var.to_string (Environment.var_of_dim env i) in match String.split_on_char '#' res with - | varname::rest::[] -> varname ^ (try String.fold_left (fun acc c -> acc ^ transl.(Char.code c - Char.code '0')) "" rest with _ -> "#"^rest) + | varname::rest::[] -> varname ^ (try to_subscript @@ int_of_string rest with _ -> "#" ^ rest) | _ -> res (** prints the current variable equalities with resolved variable names *) From 26419aa1bd1645cbb766be67464f60b7c2e73610 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Fri, 24 May 2024 15:30:28 +0200 Subject: [PATCH 256/689] Update src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml make repopulation of the sparse conjunction more concise Co-authored-by: Michael Schwarz --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 5bd68cc858..d73d9cf783 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -501,11 +501,11 @@ struct - rhs2 however, we have to account for the sparseity of EConj maps by manually patching holes with default values *) let joinfunction lhs rhs1 rhs2 = - (match rhs1,rhs2 with (* first of all re-instantiate implicit sparse elements *) - | Some a, Some b -> Some (a,b) - | None, Some b -> Some (Rhs.var_zero lhs,b) - | Some a, None -> Some (a,Rhs.var_zero lhs) - | _ -> None) + ( + let e = Option.default (Rhs.var_zero lhs) in + match rhs1,rhs2 with (* first of all re-instantiate implicit sparse elements *) + | None, None -> None + | a, b -> Some (e a, e b)) |> BatOption.map (fun (r1,r2) -> match (r1,r2) with (* criterion A , criterion B *) | (Some (c1,_),o1,d1), (Some (c2,_),o2,d2)-> lhs, Q.make Z.((o1*d2)-(o2*d1)) Z.(c1*d2), Q.make Z.(c2*d2) Z.(c1*d1), r1, r2 From 49895fe04666fdfa4a82d3a7323c7692931ccbfd Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 15:25:25 +0200 Subject: [PATCH 257/689] replace = with more specialized Rhs.equal --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index d73d9cf783..b2beb9fab9 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -536,7 +536,7 @@ struct Rhs.canonicalize (Some (Z.(anum*bden),xh),Z.(bnum*aden) ,Z.(aden*bden) ) in let iterate map l = match l with - | (_, _, _, rhs , rhs' ) :: t when rhs=rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l + | (_, _, _, rhs , rhs' ) :: t when Rhs.equal rhs rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(monom,oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t | (h, _, _, ((Some (ch,_),oh,dh)), ((None,_,_) )) :: t -> List.fold (fun acc (i,_,_,(monom,oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t | (h, _, _, ((None,_,_) ), ((Some (ch,_),oh,dh))) :: t -> List.fold (fun acc (i,_,_,_,(monom,oi,di)) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t From 7e2a741eedcb942c16720181ebd37f7d1a849cf3 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 15:27:52 +0200 Subject: [PATCH 258/689] gotten rid of silly record deconstruction --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index b2beb9fab9..090f31718e 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -532,8 +532,7 @@ struct let constentry ci1 ci2 ch1 ch2 xh = let a = Q.((ci1-ci2) / (ch1-ch2)) in let b = Q.(ci2 - a*ch2) in - let anum=a.num and aden=a.den and bnum=b.num and bden=b.den in - Rhs.canonicalize (Some (Z.(anum*bden),xh),Z.(bnum*aden) ,Z.(aden*bden) ) in + Rhs.canonicalize (Some (Z.(a.num*b.den),xh),Z.(b.num*a.den) ,Z.(a.den*b.den) ) in let iterate map l = match l with | (_, _, _, rhs , rhs' ) :: t when Rhs.equal rhs rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l From 62e569b0767332a8321d735f91b213977629171d Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 15:34:53 +0200 Subject: [PATCH 259/689] make indentation happy again --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 090f31718e..23ee5056be 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -504,8 +504,8 @@ struct ( let e = Option.default (Rhs.var_zero lhs) in match rhs1,rhs2 with (* first of all re-instantiate implicit sparse elements *) - | None, None -> None - | a, b -> Some (e a, e b)) + | None, None -> None + | a, b -> Some (e a, e b)) |> BatOption.map (fun (r1,r2) -> match (r1,r2) with (* criterion A , criterion B *) | (Some (c1,_),o1,d1), (Some (c2,_),o2,d2)-> lhs, Q.make Z.((o1*d2)-(o2*d1)) Z.(c1*d2), Q.make Z.(c2*d2) Z.(c1*d1), r1, r2 From 4810b5da346eb66ae59d59063a6961710b0138b4 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 15:39:19 +0200 Subject: [PATCH 260/689] make gcd more compact --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 23ee5056be..266f8e0505 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -38,10 +38,8 @@ module Rhs = struct (** factor out gcd from all terms, i.e. ax=by+c is the canonical form for adx+bdy+cd *) let canonicalize (v,o,d) = let gcd = Z.gcd o d in - let gcd = match v with - | Some (c,_) -> Z.gcd c gcd - | None -> gcd - in let gcd = if (Z.(lt d Z.zero)) then Z.neg gcd else gcd in + let gcd = Option.map_default (fun (c,_) -> Z.gcd c gcd) gcd v in + let gcd = if (Z.(lt d Z.zero)) then Z.neg gcd else gcd in (BatOption.map (fun (coeff,i) -> (Z.div coeff gcd,i)) v,Z.div o gcd, Z.div d gcd) (** Substitute rhs for varx in rhs' *) From 98ae9a4bb46b0976e9491b91f3bb2d50b6c0319a Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 15:49:00 +0200 Subject: [PATCH 261/689] explain canonicalization --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 266f8e0505..5aef1b1371 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -37,10 +37,10 @@ module Rhs = struct (** factor out gcd from all terms, i.e. ax=by+c is the canonical form for adx+bdy+cd *) let canonicalize (v,o,d) = - let gcd = Z.gcd o d in - let gcd = Option.map_default (fun (c,_) -> Z.gcd c gcd) gcd v in - let gcd = if (Z.(lt d Z.zero)) then Z.neg gcd else gcd in - (BatOption.map (fun (coeff,i) -> (Z.div coeff gcd,i)) v,Z.div o gcd, Z.div d gcd) + let gcd = Z.gcd o d in (* gcd of coefficients *) + let gcd = Option.map_default (fun (c,_) -> Z.gcd c gcd) gcd v in (* include monomial in gcd computation *) + let commondivisor = if Z.(lt d zero) then Z.neg gcd else gcd in (* cannonical form dictates d being positive *) + (BatOption.map (fun (coeff,i) -> (Z.div coeff commondivisor,i)) v,Z.div o commondivisor, Z.div d commondivisor) (** Substitute rhs for varx in rhs' *) let subst rhs varx rhs' = From 55c15f74bcffa6adc5d8360b1a9d88be1f7b0a31 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 24 May 2024 16:21:23 +0200 Subject: [PATCH 262/689] printf tuning --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 5aef1b1371..50fdf54d99 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -29,7 +29,7 @@ module Rhs = struct else (Z.to_string c) ^"·" let show_rhs_formatted formatter = function | (Some (coeff,v), o,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) - | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s%+Ld" (show_coeff coeff) (formatter v) (Z.to_int64 o) + | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s%+Lu" (show_coeff coeff) (formatter v) (Z.to_int64_unsigned o) | (None, o,_) -> Printf.sprintf "%Ld" (Z.to_int64 o) let show (v,o,d) = let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,d) in From f551e3c6595aa68754dcf4bcc6c81236f0ec4594 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Sat, 25 May 2024 14:22:59 +0300 Subject: [PATCH 263/689] Remove old `Invalidate` module and now empty `invalidate_actions` list --- src/util/library/libraryFunctions.ml | 116 +-------------------------- 1 file changed, 1 insertion(+), 115 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index d0ed2fd820..5e913e9c52 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1276,115 +1276,6 @@ let activated_library_descs: (string, LibraryDesc.t) Hashtbl.t ResettableLazy.t let reset_lazy () = ResettableLazy.reset activated_library_descs -module Invalidate = -struct - [@@@warning "-unused-value-declaration"] (* some functions are not used below *) - open AccessKind - - let drop = List.drop - let keep ns = List.filteri (fun i _ -> List.mem i ns) - - let partition ns x = - let rec go n = - function - | [] -> ([],[]) - | y :: ys -> - let (i,o) = go (n + 1) ys in - if List.mem n ns - then (y::i, o) - else ( i,y::o) - in - go 1 x - - let writesAllButFirst n f a x = - match a with - | Write | Call | Spawn -> f a x @ drop n x - | Read -> f a x - | Free -> [] - - let readsAllButFirst n f a x = - match a with - | Write | Call | Spawn -> f a x - | Read -> f a x @ drop n x - | Free -> [] - - let reads ns a x = - let i, o = partition ns x in - match a with - | Write | Call | Spawn -> o - | Read -> i - | Free -> [] - - let writes ns a x = - let i, o = partition ns x in - match a with - | Write | Call | Spawn -> i - | Read -> o - | Free -> [] - - let frees ns a x = - let i, o = partition ns x in - match a with - | Write | Call | Spawn -> [] - | Read -> o - | Free -> i - - let readsFrees rs fs a x = - match a with - | Write | Call | Spawn -> [] - | Read -> keep rs x - | Free -> keep fs x - - let onlyReads ns a x = - match a with - | Write | Call | Spawn -> [] - | Read -> keep ns x - | Free -> [] - - let onlyWrites ns a x = - match a with - | Write | Call | Spawn -> keep ns x - | Read -> [] - | Free -> [] - - let readsWrites rs ws a x = - match a with - | Write | Call | Spawn -> keep ws x - | Read -> keep rs x - | Free -> [] - - let readsAll a x = - match a with - | Write | Call | Spawn -> [] - | Read -> x - | Free -> [] - - let writesAll a x = - match a with - | Write | Call | Spawn -> x - | Read -> [] - | Free -> [] -end - -open Invalidate - -(* Data races: which arguments are read/written? - * 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 = [] - -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"]) let add_lib_funs funs = lib_funs := List.fold_right Set.String.add funs !lib_funs let use_special fn_name = Set.String.mem fn_name !lib_funs @@ -1425,12 +1316,7 @@ let find f = let name = f.vname in match Hashtbl.find_option (ResettableLazy.force activated_library_descs) name with | Some desc -> desc - | None -> - match Hashtbl.find_option invalidate_actions name with - | Some old_accesses -> - LibraryDesc.of_old old_accesses - | None -> - unknown_desc f + | None -> unknown_desc f let is_special fv = From c88ff964882d4d7c34a5cbe499b8e9aac9501fe4 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Sat, 25 May 2024 14:37:56 +0300 Subject: [PATCH 264/689] Inline `LibraryDesc.of_old` --- src/util/library/libraryDesc.ml | 16 ---------------- src/util/library/libraryFunctions.ml | 12 +++++++++++- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/util/library/libraryDesc.ml b/src/util/library/libraryDesc.ml index ef22dc0df0..80cf86b1e2 100644 --- a/src/util/library/libraryDesc.ml +++ b/src/util/library/libraryDesc.ml @@ -91,16 +91,6 @@ module Accesses = struct type t = Cil.exp list -> (Access.t * Cil.exp list) list - (* TODO: remove after migration *) - type old = AccessKind.t -> Cil.exp list -> Cil.exp list - let of_old (f: old): t = fun args -> - [ - ({ kind = Read; deep = true; }, f Read args); - ({ kind = Write; deep = true; }, f Write args); - ({ kind = Free; deep = true; }, f Free args); - ({ kind = Spawn; deep = true; }, f Spawn args); - ] - (* TODO: remove/rename after migration? *) let find (accs: t): Access.t -> Cil.exp list -> Cil.exp list = fun acc args -> BatOption.(List.assoc_opt acc (accs args) |? []) @@ -136,12 +126,6 @@ type t = { attrs: attr list; (** Attributes of function. *) } -let of_old ?(attrs: attr list=[]) (old_accesses: Accesses.old): t = { - attrs; - accs = Accesses.of_old old_accesses; - special = fun _ -> Unknown; -} - module MathPrintable = struct include Printable.StdLeaf type t = math [@@deriving eq, ord, hash] diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 5e913e9c52..0ea3006f22 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1310,7 +1310,17 @@ let unknown_desc f = M.msg_final Error ~category:Imprecise ~tags:[Category Unsound] "Function definition missing"; M.error ~category:Imprecise ~tags:[Category Unsound] "Function definition missing for %s" f.vname ); - LibraryDesc.of_old ~attrs old_accesses + { + LibraryDesc.attrs; + accs = (fun args -> + [ + ({ kind = Read; deep = true; }, old_accesses Read args); + ({ kind = Write; deep = true; }, old_accesses Write args); + ({ kind = Free; deep = true; }, old_accesses Free args); + ({ kind = Spawn; deep = true; }, old_accesses Spawn args); + ]); + special = fun _ -> Unknown; + } let find f = let name = f.vname in From c730b95e9896907264b5bd21a433be38e5fb852b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Sat, 25 May 2024 14:59:28 +0300 Subject: [PATCH 265/689] Simplify and rename `old_accesses` to `accs` --- src/util/library/libraryFunctions.ml | 29 ++++++++++------------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 0ea3006f22..4e678c926e 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1287,17 +1287,14 @@ let is_safe_uncalled fn_name = List.exists (fun r -> Str.string_match r fn_name 0) kernel_safe_uncalled_regex -let unknown_desc f = - let old_accesses (kind: AccessKind.t) args = match kind with - | Write when GobConfig.get_bool "sem.unknown_function.invalidate.args" -> args - | Write -> [] - | Read when GobConfig.get_bool "sem.unknown_function.read.args" -> args - | Read -> [] - | Free -> [] - | Call when get_bool "sem.unknown_function.call.args" -> args - | Call -> [] - | Spawn when get_bool "sem.unknown_function.spawn" -> args - | Spawn -> [] +let unknown_desc f : LibraryDesc.t = + let accs args : (LibraryDesc.Access.t * 'a list) list = [ + ({ kind = Read; deep = true; }, if GobConfig.get_bool "sem.unknown_function.read.args" then args else []); + ({ kind = Write; deep = true; }, if GobConfig.get_bool "sem.unknown_function.invalidate.args" then args else []); + ({ kind = Free; deep = true; }, []); (* TODO: why no option? *) + ({ kind = Call; deep = true; }, if get_bool "sem.unknown_function.call" then args else []); + ({ kind = Spawn; deep = true; }, if get_bool "sem.unknown_function.spawn" then args else []); + ] in let attrs: LibraryDesc.attr list = if GobConfig.get_bool "sem.unknown_function.invalidate.globals" then @@ -1311,14 +1308,8 @@ let unknown_desc f = M.error ~category:Imprecise ~tags:[Category Unsound] "Function definition missing for %s" f.vname ); { - LibraryDesc.attrs; - accs = (fun args -> - [ - ({ kind = Read; deep = true; }, old_accesses Read args); - ({ kind = Write; deep = true; }, old_accesses Write args); - ({ kind = Free; deep = true; }, old_accesses Free args); - ({ kind = Spawn; deep = true; }, old_accesses Spawn args); - ]); + attrs; + accs; special = fun _ -> Unknown; } From 9078c2a6e087e8ae7ef5bf30d2d01f6caee168da Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Sat, 25 May 2024 22:33:36 +0200 Subject: [PATCH 266/689] oversight of %+, so lets do it the affeq way --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 50fdf54d99..81ae290f66 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -27,9 +27,10 @@ module Rhs = struct if Z.equal c Z.one then "" else if Z.equal c Z.minus_one then "-" else (Z.to_string c) ^"·" - let show_rhs_formatted formatter = function + let show_rhs_formatted formatter = let ztostring n = if Z.(geq n zero) then "+" else "" ^ Z.to_string n in + function | (Some (coeff,v), o,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) - | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s%+Lu" (show_coeff coeff) (formatter v) (Z.to_int64_unsigned o) + | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s %s" (show_coeff coeff) (formatter v) (ztostring o) | (None, o,_) -> Printf.sprintf "%Ld" (Z.to_int64 o) let show (v,o,d) = let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,d) in From e0e9c3436e8652df23476e177b22e6e507e9ab7e Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Sat, 25 May 2024 23:02:13 +0200 Subject: [PATCH 267/689] point out IMap has nothing directly to do with EConj --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 81ae290f66..f89a8d39ba 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -316,19 +316,20 @@ struct | x -> Some(x) (** convert and simplify (wrt. reference variables) a texpr into a tuple of a list of monomials (coeff,varidx,divi) and a (constant/divi) *) - let simplified_monomials_from_texp (t: t) texp = + let simplified_monomials_from_texp (t: t) texp = BatOption.bind (monomials_from_texp t texp) (fun monomiallist -> let d = Option.get t.d in + let module IMap = EConj.IntMap in let accumulate_constants (exprcache,(aconst,adiv)) (v,offs,divi) = match v with | None -> let gcdee = Z.gcd adiv divi in exprcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi) | Some (coeff,idx) -> let (somevar,someoffs,somedivi)=Rhs.subst (EConj.get_rhs d idx) idx (v,offs,divi) in (* normalize! *) - let newcache = Option.map_default (fun (coef,ter) -> EConj.IntMap.add ter Q.((EConj.IntMap.find_default zero ter exprcache) + make coef somedivi) exprcache) exprcache somevar in + let newcache = Option.map_default (fun (coef,ter) -> IMap.add ter Q.((IMap.find_default zero ter exprcache) + make coef somedivi) exprcache) exprcache somevar in let gcdee = Z.gcd adiv divi in (newcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi)) in - let (expr,constant) = List.fold_left accumulate_constants (EConj.IntMap.empty,(Z.zero,Z.one)) monomiallist in (* abstract simplification of the guard wrt. reference variables *) - Some (EConj.IntMap.fold (fun v c acc -> if Q.equal c Q.zero then acc else (Q.num c,v,Q.den c)::acc) expr [], constant) ) + let (expr,constant) = List.fold_left accumulate_constants (IMap.empty,(Z.zero,Z.one)) monomiallist in (* abstract simplification of the guard wrt. reference variables *) + Some (IMap.fold (fun v c acc -> if Q.equal c Q.zero then acc else (Q.num c,v,Q.den c)::acc) expr [], constant) ) let simplified_monomials_from_texp (t: t) texp = let res = simplified_monomials_from_texp t texp in From c6ec44bb6686c0123cfd819892fa15607a024cb2 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Sat, 25 May 2024 23:13:37 +0200 Subject: [PATCH 268/689] more concise subst --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index f89a8d39ba..87446a7b6b 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -46,8 +46,7 @@ module Rhs = struct (** Substitute rhs for varx in rhs' *) let subst rhs varx rhs' = match rhs,rhs' with - | (Some (c,x),o,d),(Some (c',x'),o',d') when x'=varx -> canonicalize (Some (Z.mul c c',x),Z.((o*c')+(d*o')),Z.mul d d') - | (None ,o,d),(Some (c',x'),o',d') when x'=varx -> canonicalize (None ,Z.((o*c')+(d*o')),Z.mul d d') + | (monom,o,d),(Some (c',x'),o',d') when x'=varx -> canonicalize (Option.map (fun (c,x) -> (Z.mul c c',x)) monom,Z.((o*c')+(d*o')),Z.mul d d') | _ -> rhs' end From 6f02c2ab45d901bc78eedf35908b1bc9f7dd71ce Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Sat, 25 May 2024 23:24:20 +0200 Subject: [PATCH 269/689] rm faulty eval_int answer --- .../apron/linearTwoVarEqualityDomain.apron.ml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 87446a7b6b..99fc69a0a5 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -158,8 +158,8 @@ module EqualitiesConjunction = struct List.fold (fun map i -> let (oldref,c',a') = (get_rhs d i) in let (b',_) = BatOption.get oldref in - let newrhs = (Some (Z.(b'*a),head), Z.(c' - (b' * c)), Z.(a'*b)) in - canonicalize_and_set map i newrhs + (Some (Z.(b'*a),head), Z.(c' - (b' * c)), Z.(a'*b)) |> + canonicalize_and_set map i ) d cluster (* shift offset to match new reference variable *) | [] -> d) (* empty cluster means no work for us *) | _ -> d) (* variable is either a constant or expressed by another refvar *) in @@ -364,13 +364,6 @@ struct | Some (None, offset, divisor) when Z.equal (Z.rem offset divisor) Z.zero -> let res = Z.div offset divisor in (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string res) (IntOps.BigIntOps.to_string res); Some res, Some res) - | Some (None, offset, divisor) -> let res = Z.div offset divisor in - let (lower,upper) = if Z.lt res Z.zero then - (Z.pred res,res) - else - (res,Z.succ res) in - (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string lower) (IntOps.BigIntOps.to_string upper); - Some lower, Some upper) | _ -> None, None let bound_texpr d texpr1 = timing_wrap "bounds calculation" (bound_texpr d) texpr1 From 083e291185cf3cfa7e6eebc9b38fb9b941c01203 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 May 2024 10:20:05 +0300 Subject: [PATCH 270/689] Reorganize exp.arg options --- src/config/options.schema.json | 48 ++++++++---- src/framework/control.ml | 11 +-- tests/regression/56-witness/63-hh-ex3-term.c | 2 +- tests/sv-comp/dune.inc | 82 ++++++++++---------- tests/sv-comp/gen/gen.ml | 2 +- 5 files changed, 81 insertions(+), 64 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index be1ef3c63f..5eee4eb9cb 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1817,22 +1817,38 @@ }, "arg": { "title": "exp.arg", - "description": "Construct abstract reachability graph (ARG).", - "type": "boolean", - "default": false - }, - "argdot": { - "title": "exp.argdot", - "description": "Output ARG as dot file.", - "type": "boolean", - "default": false - }, - "argdotlabel": { - "title": "exp.argdotlabel", - "description": "Which ARG node labels to use? node/empty", - "type": "string", - "enum": ["node", "empty"], - "default": "node" + "description": "Abstract reachability graph (ARG) options", + "type": "object", + "properties": { + "enabled": { + "title": "exp.arg.enabled", + "description": "Construct ARG.", + "type": "boolean", + "default": false + }, + "dot": { + "title": "exp.arg.dot", + "description": "ARG output as .dot file", + "type": "object", + "properties": { + "path": { + "title": "exp.arg.dot.path", + "description": "ARG .dot file output path. Disabled if empty.", + "type": "string", + "default": "" + }, + "node-label": { + "title": "exp.arg.dot.node-label", + "description": "Which ARG node labels to use? node/empty", + "type": "string", + "enum": ["node", "empty"], + "default": "node" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/src/framework/control.ml b/src/framework/control.ml index 118942227b..5abe96a5a1 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -15,7 +15,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 "witness.graphml.enabled" || get_bool "exp.arg" in + let arg_enabled = get_bool "witness.graphml.enabled" || get_bool "exp.arg.enabled" in let termination_enabled = List.mem "termination" (get_string_list "ana.activated") in (* check if loop termination analysis is enabled*) let open Batteries in (* apply functor F on module X if opt is true *) @@ -745,22 +745,23 @@ struct in Timing.wrap "warn_global" (GHT.iter warn_global) gh; - if get_bool "exp.arg" then ( + if get_bool "exp.arg.enabled" then ( let module ArgTool = ArgTools.Make (R) in let module Arg = (val ArgTool.create entrystates) in - if get_bool "exp.argdot" then ( + let arg_dot_path = get_string "exp.arg.dot.path" in + if arg_dot_path <> "" then ( let module NoLabelNodeStyle = struct type node = Arg.Node.t let extra_node_styles node = - match GobConfig.get_string "exp.argdotlabel" with + match GobConfig.get_string "exp.arg.dot.node-label" with | "node" -> [] | "empty" -> ["label=\"_\""] (* can't have empty string because graph-easy will default to node ID then... *) | _ -> assert false end in let module ArgDot = ArgTools.Dot (Arg) (NoLabelNodeStyle) in - let oc = Batteries.open_out "arg.dot" in + let oc = Batteries.open_out arg_dot_path in Fun.protect (fun () -> let ppf = Format.formatter_of_out_channel oc in ArgDot.dot ppf; diff --git a/tests/regression/56-witness/63-hh-ex3-term.c b/tests/regression/56-witness/63-hh-ex3-term.c index 80913c3b9d..6f21652226 100644 --- a/tests/regression/56-witness/63-hh-ex3-term.c +++ b/tests/regression/56-witness/63-hh-ex3-term.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --enable ana.int.interval --set ana.activated[+] apron --set ana.apron.domain polyhedra --enable ana.apron.strengthening --set ana.activated[+] unassume --set witness.yaml.unassume 63-hh-ex3-term.yml --enable ana.widen.tokens --disable witness.invariant.other --enable exp.arg +// SKIP PARAM: --enable ana.int.interval --set ana.activated[+] apron --set ana.apron.domain polyhedra --enable ana.apron.strengthening --set ana.activated[+] unassume --set witness.yaml.unassume 63-hh-ex3-term.yml --enable ana.widen.tokens --disable witness.invariant.other --enable exp.arg.enabled extern void __assert_fail (const char *__assertion, const char *__file, unsigned int __line, const char *__function) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__noreturn__)); diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index 427033a3ff..879153afb7 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -11,7 +11,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -33,7 +33,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -55,7 +55,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -77,7 +77,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -99,7 +99,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -121,7 +121,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -143,7 +143,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -165,7 +165,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -187,7 +187,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -209,7 +209,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -231,7 +231,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -253,7 +253,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -275,7 +275,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -297,7 +297,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -319,7 +319,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -341,7 +341,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -363,7 +363,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -385,7 +385,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -407,7 +407,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -429,7 +429,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -451,7 +451,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -473,7 +473,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -495,7 +495,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -517,7 +517,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -539,7 +539,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -561,7 +561,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -583,7 +583,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -605,7 +605,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -627,7 +627,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -649,7 +649,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -671,7 +671,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -693,7 +693,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -715,7 +715,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -737,7 +737,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -759,7 +759,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -781,7 +781,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -803,7 +803,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -825,7 +825,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -847,7 +847,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -869,7 +869,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -891,7 +891,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index 2beeb07dfd..7c12da1cee 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -15,7 +15,7 @@ let generate_rule c_dir_file = (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable witness.graphml.uncil --enable exp.argdot --enable exp.arg --set exp.argdotlabel empty)) + (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %%{target} (run graph-easy --as=boxart arg.dot))))) From 6eafd2a3ab87fc6aeb152757d34e8ab8ba0e6228 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 May 2024 10:24:24 +0300 Subject: [PATCH 271/689] Add automatic generation warning to ARG tests --- tests/sv-comp/dune.inc | 1 + tests/sv-comp/gen/gen.ml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index 879153afb7..b01ed10053 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -1,3 +1,4 @@ +; Automatically generated, do not edit! (subdir basic (rule diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index 7c12da1cee..8523e0072b 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -1,3 +1,7 @@ +let generate_header () = + Printf.printf {|; Automatically generated, do not edit! +|} + let generate_rule c_dir_file = let dir = Filename.dirname c_dir_file in let c_file = Filename.basename c_dir_file in @@ -27,6 +31,7 @@ let generate_rule c_dir_file = |} dir c_file file file file let () = + generate_header (); Sys.argv |> Array.to_seq |> Seq.drop 1 From 9f0d3baacc04c2b540f8724746018b2785ee95d0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 May 2024 10:31:42 +0300 Subject: [PATCH 272/689] Switch ARG tests to up-to-date svcomp conf --- ...ocal_shadow_fun_true-unreach-call.expected | 251 +++++++++--------- tests/sv-comp/dune.inc | 82 +++--- tests/sv-comp/gen/gen.ml | 2 +- 3 files changed, 167 insertions(+), 168 deletions(-) diff --git a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected index 1d7efcacfe..bcdf9d176b 100644 --- a/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected +++ b/tests/sv-comp/cfg/local_shadow_fun_true-unreach-call.expected @@ -1,126 +1,125 @@ - - ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Entry main │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ·┐ │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineEntry '()' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Entry __VERIFIER_nondet_int : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Ret (Some val, __VERIFIER_nondet_int) : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineReturn 'tmp' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ Assign 'i = i + 1' - │ │ _ │ ◀┘ │ - │ └────────────────────────────────────────┘ │ - │ │ │ - │ │ Assign 'n = tmp' │ - │ ▼ │ - │ ┌────────────────────────────────────────┐ │ - │ │ _ │ ·┐ │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ InlineEntry '(n)' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Entry sum : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Assign 'sum___0 = 0' : │ - │ ▼ : │ - │ ┌────────────────────────────────────────┐ : │ - │ │ _ │ : │ - │ └────────────────────────────────────────┘ : │ - │ │ : │ - │ │ Assign 'i = 0' : │ - │ ▼ : │ - │ ┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ : │ - │ │ _ │ ◀──────────────────── │ _ │ ◀┼────────────────────────────────────────────────┘ - │ └─────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ │ : - │ │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) : - │ ▼ ▼ : - │ ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : - └─ │ _ │ │ _ │ : - └─────────────────────────────────┘ └────────────────────────────────────────┘ : - │ : - │ Ret (Some sum___0, sum) : Inlined Proc 'tmp___0 = sum(n)' - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ InlineReturn 'tmp___0' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Assign 's = tmp___0' - ▼ - ┌────────────────────────────────────────┐ - │ _ │ ·┐ - └────────────────────────────────────────┘ : - │ : - │ InlineEntry '(s >= 0)' : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ : - └────────────────────────────────────────┘ : - │ : - │ Entry __VERIFIER_assert : - ▼ : - ┌─────────────────────────────────┐ Test (! cond,true) ┌────────────────────────────────────────┐ : - │ _ │ ◀──────────────────── │ _ │ : - └─────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ InlineEntry '()' │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(s >= 0)' - ▼ ▼ : - ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : - │ _ │ │ _ │ : - └─────────────────────────────────┘ └────────────────────────────────────────┘ : - │ │ : - │ Entry __VERIFIER_error │ Ret (None, __VERIFIER_assert) : - ▼ ▼ : - ┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : - │ _ │ │ _ │ : - └─────────────────────────────────┘ └────────────────────────────────────────┘ : - │ : - │ InlineReturn : - ▼ : - ┌────────────────────────────────────────┐ : - │ _ │ ◀┘ - └────────────────────────────────────────┘ - │ - │ Ret (Some 0, main) - ▼ - ┌────────────────────────────────────────┐ - │ _ │ - └────────────────────────────────────────┘ + ┌────────────────────────────────────────┐ + │ _ │ + └────────────────────────────────────────┘ + │ + │ Entry main + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '()' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry __VERIFIER_nondet_int : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : Inlined Proc 'tmp = __VERIFIER_nondet_int()' + └────────────────────────────────────────┘ : + │ : + │ Ret (Some val, __VERIFIER_nondet_int) : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ InlineReturn 'tmp' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ ◀┘ + └────────────────────────────────────────┘ + │ + │ Assign 'n = tmp' + ▼ + ┌────────────────────────────────────────┐ + │ _ │ ·┐ + └────────────────────────────────────────┘ : + │ : + │ InlineEntry '(n)' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Entry sum : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Assign 'sum___0 = 0' : + ▼ : + ┌────────────────────────────────────────┐ : + │ _ │ : + └────────────────────────────────────────┘ : + │ : + │ Assign 'i = 0' : + ▼ : +┌─────────────────────────────────┐ Test (i < n,true) ┌────────────────────────────────────────┐ : +│ _ │ ◀─────────────────── │ _ │ ◀┼────────────────────────────────────────────────┐ +└─────────────────────────────────┘ └────────────────────────────────────────┘ : │ + │ │ : │ + │ Assign 'sum___0 = sum___0 + i' │ Test (i < n,false) : │ + ▼ ▼ : │ +┌─────────────────────────────────┐ ┌────────────────────────────────────────┐ : │ +│ _ │ ─┐ │ _ │ : │ +└─────────────────────────────────┘ │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (Some sum___0, sum) : Inlined Proc 'tmp___0 = sum(n)' │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn 'tmp___0' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Assign 's = tmp___0' │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ ·┐ │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineEntry '(s >= 0)' : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ Assign 'i = i + 1' + │ │ Entry __VERIFIER_assert : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Test (! cond,false) : Inlined Proc '__VERIFIER_assert(s >= 0)' │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ Ret (None, __VERIFIER_assert) : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ : │ + │ └────────────────────────────────────────┘ : │ + │ │ : │ + │ │ InlineReturn : │ + │ ▼ : │ + │ ┌────────────────────────────────────────┐ : │ + │ │ _ │ ◀┘ │ + │ └────────────────────────────────────────┘ │ + │ │ │ + │ │ Ret (Some 0, main) │ + │ ▼ │ + │ ┌────────────────────────────────────────┐ │ + │ │ _ │ │ + │ └────────────────────────────────────────┘ │ + │ │ + └────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/tests/sv-comp/dune.inc b/tests/sv-comp/dune.inc index b01ed10053..009a09dcd3 100644 --- a/tests/sv-comp/dune.inc +++ b/tests/sv-comp/dune.inc @@ -12,7 +12,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -34,7 +34,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -56,7 +56,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -78,7 +78,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -100,7 +100,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -122,7 +122,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -144,7 +144,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -166,7 +166,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -188,7 +188,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -210,7 +210,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -232,7 +232,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -254,7 +254,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -276,7 +276,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -298,7 +298,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -320,7 +320,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -342,7 +342,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -364,7 +364,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -386,7 +386,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -408,7 +408,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -430,7 +430,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -452,7 +452,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -474,7 +474,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -496,7 +496,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -518,7 +518,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -540,7 +540,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -562,7 +562,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -584,7 +584,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -606,7 +606,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -628,7 +628,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -650,7 +650,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -672,7 +672,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -694,7 +694,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -716,7 +716,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -738,7 +738,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -760,7 +760,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -782,7 +782,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -804,7 +804,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -826,7 +826,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -848,7 +848,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -870,7 +870,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) @@ -892,7 +892,7 @@ (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %{prop} %{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %{target} (run graph-easy --as=boxart arg.dot))))) diff --git a/tests/sv-comp/gen/gen.ml b/tests/sv-comp/gen/gen.ml index 8523e0072b..a694c581a0 100644 --- a/tests/sv-comp/gen/gen.ml +++ b/tests/sv-comp/gen/gen.ml @@ -19,7 +19,7 @@ let generate_rule c_dir_file = (action (progn (ignore-outputs - (run goblint --conf svcomp21.json --set ana.specification %%{prop} %%{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) + (run goblint --conf svcomp.json --disable ana.autotune.enabled --set ana.specification %%{prop} %%{c} --enable witness.graphml.uncil --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty)) (with-outputs-to %%{target} (run graph-easy --as=boxart arg.dot))))) From 746b556f4ae7edab08661e3d29286748c679e124 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 May 2024 10:51:29 +0300 Subject: [PATCH 273/689] Update mutex analysis may-be-recursive unlock TODO --- src/analyses/mutexAnalysis.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index bcf66b7973..b44795b6da 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -159,7 +159,7 @@ struct (s, m') ) else - (MustLocksetRW.remove_mval mv s, m) (* TODO: should decrement something if may be recursive? *) + (MustLocksetRW.remove_mval mv s, m) (* Should decrement something if may be recursive? No: https://github.com/goblint/analyzer/pull/1430#discussion_r1615266081. *) let remove = remove' ~warn:true From ec293bf5aa684a0de262c157a10552c8124709d0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 May 2024 15:18:44 +0300 Subject: [PATCH 274/689] Add ARG test for 56-wintess/54-witness-lifter-abortUnless --- .../54-witness-lifter-abortUnless.t | 70 +++++++++++++++++++ tests/regression/56-witness/dune | 4 ++ 2 files changed, 74 insertions(+) create mode 100644 tests/regression/56-witness/54-witness-lifter-abortUnless.t diff --git a/tests/regression/56-witness/54-witness-lifter-abortUnless.t b/tests/regression/56-witness/54-witness-lifter-abortUnless.t new file mode 100644 index 0000000000..7168a63afa --- /dev/null +++ b/tests/regression/56-witness/54-witness-lifter-abortUnless.t @@ -0,0 +1,70 @@ + $ goblint --set ana.activated[+] abortUnless --enable exp.arg.enabled --set exp.arg.dot.path arg.dot --set exp.arg.dot.node-label empty 54-witness-lifter-abortUnless.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 8 + dead: 0 + total lines: 8 + + $ graph-easy --as=boxart arg.dot + ┌───────────────────────────┐ + │ _ │ + └───────────────────────────┘ + │ + │ Entry main + ▼ + ┌───────────────────────────┐ + │ _ │ ·┐ + └───────────────────────────┘ : + │ : + │ InlineEntry '(0)' : + ▼ : + ┌───────────────────────────┐ : + │ _ │ : + └───────────────────────────┘ : + │ : + │ Entry goodB2G1Sink : + ▼ : + ┌───────────────────────────┐ : + ┌··························· │ _ │ : + : └───────────────────────────┘ : + : │ : + : │ InlineEntry '()' : + : ▼ : + : ┌───────────────────────────┐ : + : │ _ │ : + : └───────────────────────────┘ : + : │ : + : │ Entry printLine : + : ▼ : + : ┌───────────────────────────┐ : + : Inlined Proc 'printLine()' │ _ │ : Inlined Proc 'goodB2G1Sink(0)' + : └───────────────────────────┘ : + : │ : + : │ Ret (None, printLine) : + : ▼ : + : ┌───────────────────────────┐ : + : │ _ │ : + : └───────────────────────────┘ : + : │ : + : │ InlineReturn : + : ▼ : + : ┌───────────────────────────┐ : + └··························▶ │ _ │ : + └───────────────────────────┘ : + │ : + │ Ret (None, goodB2G1Sink) : + ▼ : + ┌───────────────────────────┐ : + │ _ │ : + └───────────────────────────┘ : + │ : + │ InlineReturn : + ▼ : + ┌───────────────────────────┐ : + │ _ │ ◀┘ + └───────────────────────────┘ + │ + │ Ret (Some 0, main) + ▼ + ┌───────────────────────────┐ + │ _ │ + └───────────────────────────┘ diff --git a/tests/regression/56-witness/dune b/tests/regression/56-witness/dune index 53882c885d..215e47deb2 100644 --- a/tests/regression/56-witness/dune +++ b/tests/regression/56-witness/dune @@ -25,3 +25,7 @@ (cram (deps (glob_files *.c) (glob_files ??-*.yml))) + +(cram + (applies_to 54-witness-lifter-abortUnless) + (enabled_if %{bin-available:graph-easy})) From c5a6d5beb73eeb8118081d5af105a7d9010a43a6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 27 May 2024 15:22:48 +0300 Subject: [PATCH 275/689] Remove trailing whitespace (PR #1430) --- src/cdomain/value/cdomains/mval.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/mval.ml b/src/cdomain/value/cdomains/mval.ml index b9831fa513..888ce22a86 100644 --- a/src/cdomain/value/cdomains/mval.ml +++ b/src/cdomain/value/cdomains/mval.ml @@ -41,7 +41,7 @@ end module MakeLattice (Offs: Offset.Lattice): Lattice with type idx = Offs.idx = struct include MakePrintable (Offs) - + let top_indices (x, o) = (x, Offs.top_indices o) let semantic_equal (x, xoffs) (y, yoffs) = From 31bb80289111c688bbfc04cbf27a9965d1c43ca8 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Mon, 27 May 2024 16:11:30 +0200 Subject: [PATCH 276/689] rm Z.t->int conv issues --- src/cdomains/apron/gobApron.apron.ml | 7 +++++++ src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index c39a3e42db..e202a88c60 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -1,6 +1,13 @@ open Batteries include Apron +module Coeff = +struct + include Coeff + + let s_of_z z = Coeff.s_of_mpqf (Mpqf.of_mpz (Z_mlgmpidl.mpz_of_z z)) +end + module Var = struct include Var diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 99fc69a0a5..08358005b4 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -31,7 +31,7 @@ module Rhs = struct function | (Some (coeff,v), o,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s %s" (show_coeff coeff) (formatter v) (ztostring o) - | (None, o,_) -> Printf.sprintf "%Ld" (Z.to_int64 o) + | (None, o,_) -> Printf.sprintf "%s" (Z.to_string o) let show (v,o,d) = let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,d) in if not (Z.equal d Z.one) then "(" ^ rhs ^ ")/" ^ (Z.to_string d) else rhs @@ -798,12 +798,12 @@ struct let get_const acc i = function | (None, o, d) -> let xi = Environment.var_of_dim t.env i in - of_coeff xi [(Coeff.s_of_int (- (Z.to_int d)), xi)] o :: acc + of_coeff xi [(GobApron.Coeff.s_of_z @@ Z.neg d, xi)] o :: acc | (Some (c,r), _,_) when r = i -> acc | (Some (c,r), o, d) -> let xi = Environment.var_of_dim t.env i in let ri = Environment.var_of_dim t.env r in - of_coeff xi [(Coeff.s_of_int (- (Z.to_int d)), xi); (Coeff.s_of_int @@ Z.to_int c, ri)] o :: acc + of_coeff xi [(GobApron.Coeff.s_of_z @@ Z.neg d, xi); (GobApron.Coeff.s_of_z c, ri)] o :: acc in BatOption.get t.d |> fun (_,map) -> EConj.IntMap.fold (fun lhs rhs list -> get_const list lhs rhs) map [] From 9b4b255f29f887b5cffb38280e7ebf86ed7cdd4c Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 27 May 2024 17:45:58 +0200 Subject: [PATCH 277/689] Fix `mutex-meet` for malloc after thread creation --- src/analyses/apron/relationPriv.apron.ml | 9 +++++++-- tests/regression/46-apron2/89-malloc.c | 21 +++++++++++++++++++++ tests/regression/46-apron2/90-malloc2.c | 21 +++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/regression/46-apron2/89-malloc.c create mode 100644 tests/regression/46-apron2/90-malloc2.c diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 61da6ddc42..046e1230d7 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -479,7 +479,7 @@ struct let get_mutex_inits' = keep_only_protected_globals ask m get_mutex_inits in RD.join get_m get_mutex_inits' - let get_mutex_global_g_with_mutex_inits ask getg g = + let get_mutex_global_g_with_mutex_inits (ask:Q.ask) getg g = let g_var = AV.global g in let get_mutex_global_g = if Param.handle_atomic then ( @@ -487,7 +487,12 @@ struct RD.keep_vars (getg (V.mutex atomic_mutex)) [g_var] ) else - getg (V.global g) + let r = getg (V.global g) in + if RD.is_bot r && (ask.f (Queries.IsAllocVar g)) then + (* malloc'ed blobs may not have a value here yet *) + RD.top () + else + r in let get_mutex_inits = getg V.mutex_inits in let get_mutex_inits' = RD.keep_vars get_mutex_inits [g_var] in diff --git a/tests/regression/46-apron2/89-malloc.c b/tests/regression/46-apron2/89-malloc.c new file mode 100644 index 0000000000..8780568748 --- /dev/null +++ b/tests/regression/46-apron2/89-malloc.c @@ -0,0 +1,21 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --set ana.apron.domain interval --set sem.int.signed_overflow assume_none +// Checks that assinging to malloc'ed memory does not cause both branches to be dead +#include +#include +void nop(void* arg) { +} + +void main() { + pthread_t thread; + pthread_create(&thread, 0, &nop, 0); + + long *k = malloc(sizeof(long)); + *k = 5; + if (1) + ; + + __goblint_check(*k >= 5); // Reachable and true + + *k = *k+1; + __goblint_check(*k >= 5); // Reachable and true +} diff --git a/tests/regression/46-apron2/90-malloc2.c b/tests/regression/46-apron2/90-malloc2.c new file mode 100644 index 0000000000..36696956e7 --- /dev/null +++ b/tests/regression/46-apron2/90-malloc2.c @@ -0,0 +1,21 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.relation.privatization mutex-meet-tid --set ana.apron.domain interval --set sem.int.signed_overflow assume_none +// Checks that assinging to malloc'ed memory does not cause both branches to be dead +#include +#include +void nop(void* arg) { +} + +void main() { + pthread_t thread; + pthread_create(&thread, 0, &nop, 0); + + long *k = malloc(sizeof(long)); + *k = 5; + if (1) + ; + + __goblint_check(*k >= 5); // Reachable and true + + *k = *k+1; + __goblint_check(*k >= 5); // Reachable and true +} From 896f236c98ba829aee25e5f02cb08d4bb2bba9b1 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 27 May 2024 17:55:00 +0200 Subject: [PATCH 278/689] Also fix atomic --- src/analyses/apron/relationPriv.apron.ml | 21 ++++++++++--------- tests/regression/46-apron2/91-malloc-atomic.c | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 tests/regression/46-apron2/91-malloc-atomic.c diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 046e1230d7..78a06dc227 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -482,17 +482,18 @@ struct let get_mutex_global_g_with_mutex_inits (ask:Q.ask) getg g = let g_var = AV.global g in let get_mutex_global_g = - if Param.handle_atomic then ( - (* Unprotected invariant is one big relation. *) - RD.keep_vars (getg (V.mutex atomic_mutex)) [g_var] - ) - else - let r = getg (V.global g) in - if RD.is_bot r && (ask.f (Queries.IsAllocVar g)) then - (* malloc'ed blobs may not have a value here yet *) - RD.top () + let r = + if Param.handle_atomic then + (* Unprotected invariant is one big relation. *) + RD.keep_vars (getg (V.mutex atomic_mutex)) [g_var] else - r + getg (V.global g) + in + if RD.is_bot r && (ask.f (Queries.IsAllocVar g)) then + (* malloc'ed blobs may not have a value here yet *) + RD.top () + else + r in let get_mutex_inits = getg V.mutex_inits in let get_mutex_inits' = RD.keep_vars get_mutex_inits [g_var] in diff --git a/tests/regression/46-apron2/91-malloc-atomic.c b/tests/regression/46-apron2/91-malloc-atomic.c new file mode 100644 index 0000000000..b2f057f6a4 --- /dev/null +++ b/tests/regression/46-apron2/91-malloc-atomic.c @@ -0,0 +1,21 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-atomic --set ana.apron.domain interval --set sem.int.signed_overflow assume_none +// Checks that assinging to malloc'ed memory does not cause both branches to be dead +#include +#include +void nop(void* arg) { +} + +void main() { + pthread_t thread; + pthread_create(&thread, 0, &nop, 0); + + long *k = malloc(sizeof(long)); + *k = 5; + if (1) + ; + + __goblint_check(*k >= 5); // Reachable and true + + *k = *k+1; + __goblint_check(*k >= 5); // Reachable and true +} From ab78123429e6805415a97a4ecd737008ff3a5411 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Tue, 28 May 2024 10:32:19 +0200 Subject: [PATCH 279/689] [skip ci] int_of_scalar now returning Q.t --- src/cdomains/apron/sharedFunctions.apron.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 827dc252fc..b287bb9bae 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -20,21 +20,21 @@ let int_of_scalar ?round (scalar: Scalar.t) = | None when Stdlib.Float.is_integer f -> Some f | None -> None in - Z.of_float f + Q.make (Z.of_float f) Z.one | Mpqf scalar -> (* octMPQ, boxMPQ, polkaMPQ *) let n = Mpqf.get_num scalar in let d = Mpqf.get_den scalar in - let+ z = + let+ (n,d) = if Mpzf.cmp_int d 1 = 0 then (* exact integer (denominator 1) *) - Some n + Some (n,Mpzf.of_int 1) else begin match round with - | Some `Floor -> Some (Mpzf.fdiv_q n d) (* floor division *) - | Some `Ceil -> Some (Mpzf.cdiv_q n d) (* ceiling division *) - | None -> None + | Some `Floor -> Some (Mpzf.fdiv_q n d, Mpzf.of_int 1) (* floor division *) + | Some `Ceil -> Some (Mpzf.cdiv_q n d, Mpzf.of_int 1) (* ceiling division *) + | None -> Some (n,d) end in - Z_mlgmpidl.z_of_mpzf z + Q.make (Z_mlgmpidl.z_of_mpzf n) (Z_mlgmpidl.z_of_mpzf d) | _ -> failwith ("int_of_scalar: unsupported: " ^ Scalar.to_string scalar) From ec3deedeef7eba8f2e6f8f8d03c71cb1e500910e Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Tue, 28 May 2024 14:59:19 +0200 Subject: [PATCH 280/689] wrong brackets --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 08358005b4..0a110a5999 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -27,7 +27,7 @@ module Rhs = struct if Z.equal c Z.one then "" else if Z.equal c Z.minus_one then "-" else (Z.to_string c) ^"·" - let show_rhs_formatted formatter = let ztostring n = if Z.(geq n zero) then "+" else "" ^ Z.to_string n in + let show_rhs_formatted formatter = let ztostring n = (if Z.(geq n zero) then "+" else "") ^ Z.to_string n in function | (Some (coeff,v), o,_) when Z.equal o Z.zero -> Printf.sprintf "%s%s" (show_coeff coeff) (formatter v) | (Some (coeff,v), o,_) -> Printf.sprintf "%s%s %s" (show_coeff coeff) (formatter v) (ztostring o) From 075f2e858293e899f6f27f066629d27a2f62b306 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Tue, 28 May 2024 15:57:04 +0200 Subject: [PATCH 281/689] fix unmatched monom in forget_variable --- .../apron/linearTwoVarEqualityDomain.apron.ml | 6 ++++-- .../regression/77-lin2vareq/34-coefficient-features.c | 11 ----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 0a110a5999..2da7deb5cc 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -104,7 +104,7 @@ module EqualitiesConjunction = struct let offsetlist = Array.to_list indexes in let rec bumpvar delta i = function (* bump the variable i by delta; find delta by counting indices in offsetlist until we reach a larger index then our current parameter *) | head::rest when i>=head -> bumpvar (delta+1) i rest (* rec call even when =, in order to correctly interpret double bumps *) - | _ (* i op i delta + | _ (* i let res = op i delta in res in let memobumpvar = (* Memoized version of bumpvar *) let module IntHash = struct type t = int [@@deriving eq,hash] end in @@ -145,9 +145,11 @@ module EqualitiesConjunction = struct (let ref_var_opt = Tuple3.first (get_rhs d var) in match ref_var_opt with | Some (_,ref_var) when ref_var = var -> + if M.tracing then M.trace "forget" "headvar var_%d" var; (* var is the reference variable of its connected component *) (let cluster = IntMap.fold - (fun i (ref,_,_) l -> if ref = ref_var_opt then i::l else l) (snd d) [] in + (fun i (ref,_,_) l -> BatOption.map_default (fun (coeff,ref) -> if (ref=ref_var) then i::l else l) l ref) (snd d) [] in + if M.tracing then M.trace "forget" "cluster varindices: [%s]" (String.concat ", " (List.map (string_of_int) cluster)); (* obtain cluster with common reference variable ref_var*) match cluster with (* new ref_var is taken from head of the cluster *) | head :: _ -> diff --git a/tests/regression/77-lin2vareq/34-coefficient-features.c b/tests/regression/77-lin2vareq/34-coefficient-features.c index b415f4398a..561eccf0af 100644 --- a/tests/regression/77-lin2vareq/34-coefficient-features.c +++ b/tests/regression/77-lin2vareq/34-coefficient-features.c @@ -21,17 +21,6 @@ void loop() { __goblint_check(x == 4*i); //SUCCESS - for(i = 1; i < 100; i++) { - x=x+4; - y=y+8; - - __goblint_check(y == 2*x); //SUCCESS - - int res = (y==2*x )+ 1; - - __goblint_check(res); //SUCCESS - } - x=0; y=0; From 94ebf865fc261825d3d137f4d8203a5da8be1ba3 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 29 May 2024 10:57:03 +0200 Subject: [PATCH 282/689] fixed broken is_top --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 2da7deb5cc..f6ae9b2c51 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -400,7 +400,7 @@ struct let top () = {d = Some (EConj.empty()); env = empty_env} (** is_top returns true for top_of array and empty array; precondition: t.env and t.d are of same size *) - let is_top t = Environment.equal empty_env t.env && GobOption.exists EConj.is_top_con t.d + let is_top t = GobOption.exists EConj.is_top_con t.d let to_subscript i = let transl = [|"₀";"₁";"₂";"₃";"₄";"₅";"₆";"₇";"₈";"₉"|] in @@ -472,8 +472,8 @@ struct | Some (coeffj,j) -> tuple_cmp (EConj.get_rhs ts i) @@ Rhs.subst (EConj.get_rhs ts j) j (var, offs, divi) in if env_comp = -2 || env_comp > 0 then false else - if is_bot_env t1 || is_top t2 then true else - if is_bot_env t2 || is_top t1 then false else + if is_bot_env t1 || is_top t2 then true + else if is_bot_env t2 || is_top t1 then false else let m1, m2 = Option.get t1.d, Option.get t2.d in let m1' = if env_comp = 0 then m1 else VarManagement.dim_add (Environment.dimchange t1.env t2.env) m1 in EConj.IntMap.for_all (implies m1') (snd m2) (* even on sparse m2, it suffices to check the non-trivial equalities, still present in sparse m2 *) From 9663b1c772277fc3eb80b1a0ce4e3b7fd19bf46d Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 29 May 2024 13:17:04 +0200 Subject: [PATCH 283/689] make combine tracing in relational analysis more specific --- src/analyses/apron/relationAnalysis.apron.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 6c118dac7a..97fd66d676 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -388,11 +388,11 @@ struct let st = ctx.local in let reachable_from_args = reachable_from_args ctx args in let fundec = Node.find_fundec ctx.node in - if M.tracing then M.tracel "combine" "relation f: %a" CilType.Varinfo.pretty f.svar; - if M.tracing then M.tracel "combine" "relation formals: %a" (d_list "," CilType.Varinfo.pretty) f.sformals; - if M.tracing then M.tracel "combine" "relation args: %a" (d_list "," d_exp) args; - if M.tracing then M.tracel "combine" "relation st: %a" D.pretty st; - if M.tracing then M.tracel "combine" "relation fun_st: %a" D.pretty fun_st; + if M.tracing then M.tracel "combine-rel" "relation f: %a" CilType.Varinfo.pretty f.svar; + if M.tracing then M.tracel "combine-rel" "relation formals: %a" (d_list "," CilType.Varinfo.pretty) f.sformals; + if M.tracing then M.tracel "combine-rel" "relation args: %a" (d_list "," d_exp) args; + if M.tracing then M.tracel "combine-rel" "relation st: %a" D.pretty st; + if M.tracing then M.tracel "combine-rel" "relation fun_st: %a" D.pretty fun_st; let new_fun_rel = RD.add_vars fun_st.rel (RD.vars st.rel) in let arg_substitutes = let filter_actuals (x,e) = @@ -418,7 +418,7 @@ struct in let any_local_reachable = any_local_reachable fundec reachable_from_args in let arg_vars = f.sformals |> List.filter (RD.Tracked.varinfo_tracked) |> List.map RV.arg in - if M.tracing then M.tracel "combine" "relation remove vars: %a" (docList (fun v -> Pretty.text (Apron.Var.to_string v))) arg_vars; + if M.tracing then M.tracel "combine-rel" "relation remove vars: %a" (docList (fun v -> Pretty.text (Apron.Var.to_string v))) arg_vars; RD.remove_vars_with new_fun_rel arg_vars; (* fine to remove arg vars that also exist in caller because unify from new_rel adds them back with proper constraints *) let tainted = f_ask.f Queries.MayBeTainted in let tainted_vars = TaintPartialContexts.conv_varset tainted in @@ -432,7 +432,7 @@ struct ) in let unify_rel = RD.unify new_rel new_fun_rel in (* TODO: unify_with *) - if M.tracing then M.tracel "combine" "relation unifying %a %a = %a" RD.pretty new_rel RD.pretty new_fun_rel RD.pretty unify_rel; + if M.tracing then M.tracel "combine-rel" "relation unifying %a %a = %a" RD.pretty new_rel RD.pretty new_fun_rel RD.pretty unify_rel; {fun_st with rel = unify_rel} let combine_assign ctx r fe f args fc fun_st (f_ask : Queries.ask) = From caa8437fcbdbd2182c2f8a6aa50ea33a72ad58cb Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 29 May 2024 13:18:04 +0200 Subject: [PATCH 284/689] forget did not forget about the actual head-variable of the new cluster --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index f6ae9b2c51..d2489689e1 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -152,17 +152,18 @@ module EqualitiesConjunction = struct if M.tracing then M.trace "forget" "cluster varindices: [%s]" (String.concat ", " (List.map (string_of_int) cluster)); (* obtain cluster with common reference variable ref_var*) match cluster with (* new ref_var is taken from head of the cluster *) - | head :: _ -> + | head :: clusterrest -> (* ax = by + c /\ a'z = b'y + c' *) (* ==[[ y:=? ]]==> (a'b)z = (b'a)x + c' -(b'c) *) let (newref,c,a) = (get_rhs d head) in (* take offset between old and new reference variable *) let (b,_) = BatOption.get newref in - List.fold (fun map i -> + let shifted_cluster = (List.fold (fun map i -> (* shift offset to match new reference variable *) let (oldref,c',a') = (get_rhs d i) in let (b',_) = BatOption.get oldref in (Some (Z.(b'*a),head), Z.(c' - (b' * c)), Z.(a'*b)) |> canonicalize_and_set map i - ) d cluster (* shift offset to match new reference variable *) + ) d clusterrest) in + set_rhs shifted_cluster head (Rhs.var_zero head) (* finally make sure that head is now trivial *) | [] -> d) (* empty cluster means no work for us *) | _ -> d) (* variable is either a constant or expressed by another refvar *) in let res = (fst res, IntMap.remove var (snd res)) in (* set d(var) to unknown, finally *) From e1462b308d7695b37ac9041b1a465c70bdc15657 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Wed, 29 May 2024 14:58:40 +0200 Subject: [PATCH 285/689] fixed forget_variable by a) sorting vars in cluster and b) rehauling cluster transformation with subst/inverse convenience functions --- .../apron/linearTwoVarEqualityDomain.apron.ml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index d2489689e1..923229ca96 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -147,21 +147,21 @@ module EqualitiesConjunction = struct | Some (_,ref_var) when ref_var = var -> if M.tracing then M.trace "forget" "headvar var_%d" var; (* var is the reference variable of its connected component *) - (let cluster = IntMap.fold + (let cluster = List.sort (Int.compare) @@ IntMap.fold (fun i (ref,_,_) l -> BatOption.map_default (fun (coeff,ref) -> if (ref=ref_var) then i::l else l) l ref) (snd d) [] in if M.tracing then M.trace "forget" "cluster varindices: [%s]" (String.concat ", " (List.map (string_of_int) cluster)); (* obtain cluster with common reference variable ref_var*) match cluster with (* new ref_var is taken from head of the cluster *) | head :: clusterrest -> - (* ax = by + c /\ a'z = b'y + c' *) - (* ==[[ y:=? ]]==> (a'b)z = (b'a)x + c' -(b'c) *) - let (newref,c,a) = (get_rhs d head) in (* take offset between old and new reference variable *) - let (b,_) = BatOption.get newref in - let shifted_cluster = (List.fold (fun map i -> (* shift offset to match new reference variable *) - let (oldref,c',a') = (get_rhs d i) in - let (b',_) = BatOption.get oldref in - (Some (Z.(b'*a),head), Z.(c' - (b' * c)), Z.(a'*b)) |> - canonicalize_and_set map i + (* head: divi*x = coeff*y + offs *) + (* divi*x = coeff*y + offs =inverse=> y =( divi*x - offs)/coeff *) + let (newref,offs,divi) = (get_rhs d head) in + let (coeff,y) = BatOption.get newref in + let (y,yrhs)= inverse head (coeff,y,offs,divi) in (* reassemble yrhs out of components *) + let shifted_cluster = (List.fold (fun map i -> + let irhs = (get_rhs d i) in (* old entry is i = irhs *) + Rhs.subst yrhs y irhs |> (* new entry for i is irhs [yrhs/y] *) + set_rhs map i ) d clusterrest) in set_rhs shifted_cluster head (Rhs.var_zero head) (* finally make sure that head is now trivial *) | [] -> d) (* empty cluster means no work for us *) @@ -240,7 +240,7 @@ module EqualitiesConjunction = struct let (_,newh1)= inverse i (coeff1,h1,o1,divi1) in let newh1 = Rhs.subst normalizedj j (Rhs.subst (Some(coeff,j),offs,divi) i newh1) in subst_var ts h1 newh1)) in - if M.tracing then M.trace "meet_with_one_conj" "meet_with_one_conj conj: %s eq: var_%d=%s -> %s " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd res)) + if M.tracing then M.tracel "meet_with_one_conj" "meet_with_one_conj conj: %s eq: var_%d=%s -> %s " (show (snd ts)) i (Rhs.show (var,offs,divi)) (show (snd res)) ; res (** affine transform variable i allover conj with transformer (Some (coeff,i)+offs)/divi *) From 35a4382efc2509e46a64edc7dc2effa8fc10060f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 31 May 2024 14:31:54 +0300 Subject: [PATCH 286/689] Simplify SetDomain.FiniteSet arguments --- src/domain/setDomain.ml | 12 ++++++------ tests/unit/maindomaintest.ml | 9 +++------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/domain/setDomain.ml b/src/domain/setDomain.ml index 1b5239de80..9b545a78ee 100644 --- a/src/domain/setDomain.ml +++ b/src/domain/setDomain.ml @@ -436,23 +436,23 @@ struct include Lattice.Reverse (Base) end -module type FiniteSetElems = +module type FiniteSetElem = sig - type t + include Printable.S val elems: t list + (** List of all possible elements. *) end -(* TODO: put elems into E *) -module FiniteSet (E:Printable.S) (Elems:FiniteSetElems with type t = E.t) = +module FiniteSet (E: FiniteSetElem) = struct module E = struct include E - let arbitrary () = QCheck.oneofl Elems.elems + let arbitrary () = QCheck.oneofl E.elems end include Make (E) - let top () = of_list Elems.elems + let top () = of_list E.elems let is_top x = equal x (top ()) end diff --git a/tests/unit/maindomaintest.ml b/tests/unit/maindomaintest.ml index 8e6a7f5a3a..8e1db76b83 100644 --- a/tests/unit/maindomaintest.ml +++ b/tests/unit/maindomaintest.ml @@ -15,14 +15,11 @@ struct let show = show end include Printable.SimpleShow (P) + + let elems = ['a'; 'b'; 'c'; 'd'] end -module ArbitraryLattice = SetDomain.FiniteSet (PrintableChar) ( - struct - type t = char - let elems = ['a'; 'b'; 'c'; 'd'] - end - ) +module ArbitraryLattice = SetDomain.FiniteSet (PrintableChar) module HoareArbitrary = HoareDomain.Set_LiftTop (ArbitraryLattice) (struct let topname = "Top" end) module HoareArbitrary_NoTop = HoareDomain.Set (ArbitraryLattice) From 07f539ffd4433913c087fb5d99f9bb5e5db3bc3f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 31 May 2024 14:33:39 +0300 Subject: [PATCH 287/689] Update first analysis tutorial regarding SetDomain.FiniteSet --- docs/developer-guide/firstanalysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-guide/firstanalysis.md b/docs/developer-guide/firstanalysis.md index 4eb35e7f5d..b32538134b 100644 --- a/docs/developer-guide/firstanalysis.md +++ b/docs/developer-guide/firstanalysis.md @@ -80,4 +80,4 @@ For example, have a look at the following program: `tests/regression/99-tutorial _Hint:_ The easiest way to do this is to use the powerset lattice of `{-, 0, +}`. For example, "non-negative" is represented by `{0, +}`, while negative is represented by `{-}`. -To do this, modify `SL` by using `SetDomain.FiniteSet` (takes a `struct` with a list of finite elements as second parameter) instead of `Lattice.Flat` and reimplementing the two functions using `singleton` and `for_all`. +To do this, modify `SL` by using `SetDomain.FiniteSet` (which needs a finite list of elements to be added to `Signs`) instead of `Lattice.Flat` and reimplementing the two functions using `singleton` and `for_all`. From 325dd23a98666c21bf619fe9b08ca1f610a8ded0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 31 May 2024 14:47:29 +0300 Subject: [PATCH 288/689] Fix typo in first analysis tutorial --- docs/developer-guide/firstanalysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-guide/firstanalysis.md b/docs/developer-guide/firstanalysis.md index b32538134b..c9e3c58720 100644 --- a/docs/developer-guide/firstanalysis.md +++ b/docs/developer-guide/firstanalysis.md @@ -74,7 +74,7 @@ For more information on the signature of the individual transfer functions, plea ## Extending the domain You could now enrich the lattice to also have a representation for non-negative (i.e., zero or positive) values. -Then the join of `Zero` and `Pos` would be "non-negative" instead of `Top`, allowing you to prove that such join is greated than `Neg`. +Then the join of `Zero` and `Pos` would be "non-negative" instead of `Top`, allowing you to prove that such join is greater than `Neg`. For example, have a look at the following program: `tests/regression/99-tutorials/02-first-extend.c`. _Hint:_ From 24d273bd0b44e98f523d6fea680ec5afb77768de Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 31 May 2024 14:47:53 +0300 Subject: [PATCH 289/689] Remove unnecessary warn.debug from first analysis tutorial --- docs/developer-guide/firstanalysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer-guide/firstanalysis.md b/docs/developer-guide/firstanalysis.md index c9e3c58720..bd4dfb3c11 100644 --- a/docs/developer-guide/firstanalysis.md +++ b/docs/developer-guide/firstanalysis.md @@ -35,7 +35,7 @@ This program is in the Goblint repository: `tests/regression/99-tutorials/01-fir But if you run Goblint out of the box on this example, it will not work: ```console -./goblint --enable warn.debug tests/regression/99-tutorials/01-first.c +./goblint tests/regression/99-tutorials/01-first.c ``` This will claim that the assertion in unknown. From 1082f1c2afeb10ab5f8ddd8fb77a63b3e64b4bc6 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Mon, 3 Jun 2024 08:48:25 +0200 Subject: [PATCH 290/689] add missing stable_remove hook to destabilize_vs --- src/solver/td3.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/solver/td3.ml b/src/solver/td3.ml index 7e2a18b042..c7bec621e3 100644 --- a/src/solver/td3.ml +++ b/src/solver/td3.ml @@ -284,7 +284,11 @@ module Base = let was_stable = HM.mem stable y in HM.remove stable y; HM.remove superstable y; - HM.mem called y || destabilize_vs y || b || was_stable && List.mem_cmp S.Var.compare y vs + Hooks.stable_remove y; + if not (HM.mem called y) then + destabilize_vs y || b || was_stable && List.mem_cmp S.Var.compare y vs + else + true ) w false and solve ?reuse_eq x phase = if tracing then trace "sol2" "solve %a, phase: %s, called: %b, stable: %b, wpoint: %b" S.Var.pretty_trace x (show_phase phase) (HM.mem called x) (HM.mem stable x) (HM.mem wpoint x); From a50dc813320c2714b6bb0414e62a9897cc140370 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 3 Jun 2024 11:38:52 +0300 Subject: [PATCH 291/689] Unpin ppx_deriving --- dune-project | 2 +- goblint.opam | 4 +--- goblint.opam.locked | 8 ++------ goblint.opam.template | 2 -- gobview | 2 +- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/dune-project b/dune-project index 878abd3b4f..c5adaddf81 100644 --- a/dune-project +++ b/dune-project @@ -29,7 +29,7 @@ (zarith (>= 1.10)) (yojson (>= 2.0.0)) (qcheck-core (>= 0.19)) - ppx_deriving + (ppx_deriving (>= 6.0.2)) (ppx_deriving_hash (>= 0.1.2)) (ppx_deriving_yojson (>= 3.7.0)) (ounit2 :with-test) diff --git a/goblint.opam b/goblint.opam index 692625c965..0d8a561fa0 100644 --- a/goblint.opam +++ b/goblint.opam @@ -27,7 +27,7 @@ depends: [ "zarith" {>= "1.10"} "yojson" {>= "2.0.0"} "qcheck-core" {>= "0.19"} - "ppx_deriving" + "ppx_deriving" {>= "6.0.2"} "ppx_deriving_hash" {>= "0.1.2"} "ppx_deriving_yojson" {>= "3.7.0"} "ounit2" {with-test} @@ -79,8 +79,6 @@ available: os-distribution != "alpine" & arch != "arm64" pin-depends: [ # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] - # 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" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index f8de683948..d532457ced 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -81,10 +81,10 @@ depends: [ "ounit2" {= "2.2.6" & with-test} "pp" {= "1.1.2"} "ppx_derivers" {= "1.2.1"} - "ppx_deriving" {= "5.2.1"} + "ppx_deriving" {= "6.0.2"} "ppx_deriving_hash" {= "0.1.2"} "ppx_deriving_yojson" {= "3.7.0"} - "ppxlib" {= "0.28.0"} + "ppxlib" {= "0.32.1"} "qcheck-core" {= "0.20"} "qcheck-ounit" {= "0.20" & with-test} "re" {= "1.10.4" & with-doc} @@ -136,9 +136,5 @@ pin-depends: [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] - [ - "ppx_deriving.5.2.1" - "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" - ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.template b/goblint.opam.template index 2d5ef10bc9..a730d5c064 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -4,8 +4,6 @@ available: os-distribution != "alpine" & arch != "arm64" pin-depends: [ # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] - # 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" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/gobview b/gobview index 72abbb576b..195c61cbae 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 72abbb576b8ffc8759dcfa31501738f6b561b05a +Subproject commit 195c61cbae86b8ffb8af4a21f2acd689665c1c0e From 83d771b63a6c38edc5e344b078f59d989c81786f Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 3 Jun 2024 14:52:57 +0300 Subject: [PATCH 292/689] Improve zeroinit output by removing negation --- src/analyses/base.ml | 11 ++++++----- src/cdomain/value/cdomains/valueDomain.ml | 23 ++++++++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 67e6276239..c33aaa4abb 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -17,6 +17,7 @@ module IdxDom = ValueDomain.IndexDomain module AD = ValueDomain.AD module Addr = ValueDomain.Addr module Offs = ValueDomain.Offs +module ZeroInit = ValueDomain.ZeroInit module LF = LibraryFunctions module CArrays = ValueDomain.CArrays module PU = PrecisionUtil @@ -2652,7 +2653,7 @@ struct | Some lv -> let heap_var = AD.of_var (heap_var true ctx) in (* ignore @@ printf "alloca will allocate %a bytes\n" ID.pretty (eval_int ~ctx size); *) - set_many ~ctx st [(heap_var, TVoid [], Blob (VD.bot (), eval_int ~ctx st size, true)); + set_many ~ctx st [(heap_var, TVoid [], Blob (VD.bot (), eval_int ~ctx st size, ZeroInit.malloc)); (eval_lv ~ctx st lv, (Cilfacade.typeOfLval lv), Address heap_var)] | _ -> st end @@ -2665,7 +2666,7 @@ struct else AD.of_var (heap_var false ctx) in (* ignore @@ printf "malloc will allocate %a bytes\n" ID.pretty (eval_int ~ctx size); *) - set_many ~ctx st [(heap_var, TVoid [], Blob (VD.bot (), eval_int ~ctx st size, true)); + set_many ~ctx st [(heap_var, TVoid [], Blob (VD.bot (), eval_int ~ctx st size, ZeroInit.malloc)); (eval_lv ~ctx st lv, (Cilfacade.typeOfLval lv), Address heap_var)] | _ -> st end @@ -2682,7 +2683,7 @@ struct let countval = eval_int ~ctx st n in if ID.to_int countval = Some Z.one then ( set_many ~ctx st [ - (add_null (AD.of_var heap_var), TVoid [], Blob (VD.bot (), sizeval, false)); + (add_null (AD.of_var heap_var), TVoid [], Blob (VD.bot (), sizeval, ZeroInit.calloc)); (eval_lv ~ctx st lv, (Cilfacade.typeOfLval lv), Address (add_null (AD.of_var heap_var))) ] ) @@ -2690,7 +2691,7 @@ struct let blobsize = ID.mul (ID.cast_to ik @@ sizeval) (ID.cast_to ik @@ countval) in (* the memory that was allocated by calloc is set to bottom, but we keep track that it originated from calloc, so when bottom is read from memory allocated by calloc it is turned to zero *) set_many ~ctx st [ - (add_null (AD.of_var heap_var), TVoid [], Array (CArrays.make (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) Z.one) (Blob (VD.bot (), blobsize, false)))); + (add_null (AD.of_var heap_var), TVoid [], Array (CArrays.make (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) Z.one) (Blob (VD.bot (), blobsize, ZeroInit.calloc)))); (eval_lv ~ctx st lv, (Cilfacade.typeOfLval lv), Address (add_null (AD.of_mval (heap_var, `Index (IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) Z.zero, `NoOffset))))) ] ) @@ -2713,7 +2714,7 @@ struct let p_addr' = AD.remove NullPtr p_addr in (* realloc with NULL is same as malloc, remove to avoid unknown value from NullPtr access *) let p_addr_get = get ~ctx st p_addr' None in (* implicitly includes join of malloc value (VD.bot) *) let size_int = eval_int ~ctx st size in - let heap_val:value = Blob (p_addr_get, size_int, true) in (* copy old contents with new size *) + let heap_val:value = Blob (p_addr_get, size_int, ZeroInit.malloc) in (* copy old contents with new size *) let heap_addr = AD.of_var (heap_var false ctx) in let heap_addr' = if get_bool "sem.malloc.fail" then diff --git a/src/cdomain/value/cdomains/valueDomain.ml b/src/cdomain/value/cdomains/valueDomain.ml index de64fde807..12c86abf60 100644 --- a/src/cdomain/value/cdomains/valueDomain.ml +++ b/src/cdomain/value/cdomains/valueDomain.ml @@ -57,11 +57,24 @@ sig val invalidate_value: VDQ.t -> typ -> t -> t end -(* ZeroInit is true if malloc was used to allocate memory and it's false if calloc was used *) -module ZeroInit = +module type ZeroInit = +sig + include Lattice.S + + val is_malloc : t -> bool + val malloc : t + val calloc : t +end + +(* ZeroInit is false if malloc was used to allocate memory and true if calloc was used *) +module ZeroInit : ZeroInit = struct include Lattice.Fake(Basetype.RawBools) - let name () = "no zeroinit" + let name () = "zeroinit" + + let is_malloc x = not x + let malloc = false + let calloc = true end module Blob (Value: S) (Size: IntDomain.Z)= @@ -862,8 +875,8 @@ struct end | _, _ -> None - let zero_init_calloced_memory orig x t = - if orig then + let zero_init_calloced_memory zeroinit x t = + if ZeroInit.is_malloc zeroinit then (* This Blob came from malloc *) x else if x = Bot then From d19f9c9c8bab362a43a0b6cd1d819540d475bc07 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 3 Jun 2024 15:10:49 +0300 Subject: [PATCH 293/689] Rename origin -> zeroinit --- src/cdomain/value/cdomains/valueDomain.ml | 46 +++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/cdomain/value/cdomains/valueDomain.ml b/src/cdomain/value/cdomains/valueDomain.ml index 12c86abf60..dd8ac844e3 100644 --- a/src/cdomain/value/cdomains/valueDomain.ml +++ b/src/cdomain/value/cdomains/valueDomain.ml @@ -49,8 +49,8 @@ module type Blob = sig type value type size - type origin - include Lattice.S with type t = value * size * origin + type zeroinit + include Lattice.S with type t = value * size * zeroinit val map: (value -> value) -> t -> t val value: t -> value @@ -83,7 +83,7 @@ struct let name () = "blob" type value = Value.t type size = Size.t - type origin = ZeroInit.t + type zeroinit = ZeroInit.t let map f (v, s, o) = f v, s, o let value (a, b, c) = a @@ -891,23 +891,23 @@ struct if M.tracing then M.traceli "eval_offset" "do_eval_offset %a %a (%a)" pretty x Offs.pretty offs (Pretty.docOpt (CilType.Exp.pretty ())) exp; let r = match x, offs with - | Blob((va, _, orig) as c), `Index (_, ox) -> + | Blob((va, _, zeroinit) as c), `Index (_, ox) -> begin let l', o' = shift_one_over l o in let ev = do_eval_offset ask f (Blobs.value c) ox exp l' o' v t in - zero_init_calloced_memory orig ev t + zero_init_calloced_memory zeroinit ev t end - | Blob((va, _, orig) as c), `Field _ -> + | Blob((va, _, zeroinit) as c), `Field _ -> begin let l', o' = shift_one_over l o in let ev = do_eval_offset ask f (Blobs.value c) offs exp l' o' v t in - zero_init_calloced_memory orig ev t + zero_init_calloced_memory zeroinit ev t end - | Blob((va, _, orig) as c), `NoOffset -> + | Blob((va, _, zeroinit) as c), `NoOffset -> begin let l', o' = shift_one_over l o in let ev = do_eval_offset ask f (Blobs.value c) offs exp l' o' v t in - zero_init_calloced_memory orig ev t + zero_init_calloced_memory zeroinit ev t end | Bot, _ -> Bot | _ -> @@ -965,24 +965,24 @@ struct let update_offset ?(blob_destructive=false) (ask: VDQ.t) (x:t) (offs:offs) (value:t) (exp:exp option) (v:lval) (t:typ): t = let rec do_update_offset (ask:VDQ.t) (x:t) (offs:offs) (value:t) (exp:exp option) (l:lval option) (o:offset option) (v:lval) (t:typ):t = if M.tracing then M.traceli "update_offset" "do_update_offset %a %a (%a) %a" pretty x Offs.pretty offs (Pretty.docOpt (CilType.Exp.pretty ())) exp pretty value; - let mu = function Blob (Blob (y, s', orig), s, orig2) -> Blob (y, ID.join s s',orig) | x -> x in + let mu = function Blob (Blob (y, s', zeroinit), s, _) -> Blob (y, ID.join s s', zeroinit) | x -> x in let r = match x, offs with | Mutex, _ -> (* hide mutex structure contents, not updated anyway *) Mutex - | Blob (x,s,orig), `Index (_,ofs) -> + | Blob (x,s,zeroinit), `Index (_,ofs) -> begin let l', o' = shift_one_over l o in - let x = zero_init_calloced_memory orig x t in - mu (Blob (join x (do_update_offset ask x ofs value exp l' o' v t), s, orig)) + let x = zero_init_calloced_memory zeroinit x t in + mu (Blob (join x (do_update_offset ask x ofs value exp l' o' v t), s, zeroinit)) end - | Blob (x,s,orig), `Field(f, _) -> + | Blob (x,s,zeroinit), `Field(f, _) -> begin (* We only have Blob for dynamically allocated memory. In these cases t is the type of the lval used to access it, i.e. for a struct s {int x; int y;} a; accessed via a->x *) (* will be int. Here, we need a zero_init of the entire contents of the blob though, which we get by taking the associated f.fcomp. Putting [] for attributes is ok, as we don't *) (* consider them in VD *) let l', o' = shift_one_over l o in - let x = zero_init_calloced_memory orig x (TComp (f.fcomp, [])) in + let x = zero_init_calloced_memory zeroinit x (TComp (f.fcomp, [])) in (* Strong update of scalar variable is possible if the variable is unique and size of written value matches size of blob being written to. *) let do_strong_update = match v with @@ -996,14 +996,14 @@ struct | _ -> false in if do_strong_update then - Blob ((do_update_offset ask x offs value exp l' o' v t), s, orig) + Blob ((do_update_offset ask x offs value exp l' o' v t), s, zeroinit) else - mu (Blob (join x (do_update_offset ask x offs value exp l' o' v t), s, orig)) + mu (Blob (join x (do_update_offset ask x offs value exp l' o' v t), s, zeroinit)) end - | Blob (x,s,orig), _ -> + | Blob (x,s,zeroinit), _ -> begin let l', o' = shift_one_over l o in - let x = zero_init_calloced_memory orig x t in + let x = zero_init_calloced_memory zeroinit x t in (* Strong update of scalar variable is possible if the variable is unique and size of written value matches size of blob being written to. *) let do_strong_update = begin match v with @@ -1019,9 +1019,9 @@ struct end in if do_strong_update then - Blob ((do_update_offset ask x offs value exp l' o' v t), s, orig) + Blob ((do_update_offset ask x offs value exp l' o' v t), s, zeroinit) else - mu (Blob (join x (do_update_offset ask x offs value exp l' o' v t), s, orig)) + mu (Blob (join x (do_update_offset ask x offs value exp l' o' v t), s, zeroinit)) end | Thread _, _ -> (* hack for pthread_t variables *) @@ -1049,7 +1049,7 @@ struct match offs with | `NoOffset -> begin match value with - | Blob (y, s, orig) -> mu (Blob (join x y, s, orig)) + | Blob (y, s, zeroinit) -> mu (Blob (join x y, s, zeroinit)) | Int _ -> cast t value | _ -> value end @@ -1302,7 +1302,7 @@ and Unions: UnionDomain.S with type t = UnionDomain.Field.t * Compound.t and typ and CArrays: ArrayDomain.StrWithDomain with type value = Compound.t and type idx = ArrIdxDomain.t = ArrayDomain.AttributeConfiguredAndNullByteArrayDomain(Compound)(ArrIdxDomain) -and Blobs: Blob with type size = ID.t and type value = Compound.t and type origin = ZeroInit.t = Blob (Compound) (ID) +and Blobs: Blob with type size = ID.t and type value = Compound.t and type zeroinit = ZeroInit.t = Blob (Compound) (ID) module type InvariantArg = From 2a79e42601bcf03c3a446fd7dceafc22096358d1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 10:45:25 +0300 Subject: [PATCH 294/689] Add comment about multiple protecting mutexes for ghost invariants --- src/analyses/basePriv.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index c244e7f3bf..be261d96b7 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -868,6 +868,10 @@ struct Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) + (* Very conservative about multiple (write-)protecting mutexes: invariant is not claimed when any of them is held. + It should be possible to be more precise because writes only happen with all of them held, + but conjunction is unsound when one of the mutexes is temporarily unlocked. + Hypothetical read-protection is also somehow relevant. *) Q.AD.fold (fun m acc -> if LockDomain.Addr.equal m (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) then acc From 86be1d04d4db322cc8bf4504a778f18e910586ac Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 11:35:58 +0300 Subject: [PATCH 295/689] Add unsound test for unlocking non-definite mutex in privatizations --- .../13-privatized/93-unlock-idx-ambiguous.c | 27 +++++++ .../13-privatized/93-unlock-idx-ambiguous.t | 75 +++++++++++++++++++ tests/regression/13-privatized/dune | 2 + 3 files changed, 104 insertions(+) create mode 100644 tests/regression/13-privatized/93-unlock-idx-ambiguous.c create mode 100644 tests/regression/13-privatized/93-unlock-idx-ambiguous.t create mode 100644 tests/regression/13-privatized/dune diff --git a/tests/regression/13-privatized/93-unlock-idx-ambiguous.c b/tests/regression/13-privatized/93-unlock-idx-ambiguous.c new file mode 100644 index 0000000000..081302514b --- /dev/null +++ b/tests/regression/13-privatized/93-unlock-idx-ambiguous.c @@ -0,0 +1,27 @@ +// PARAM: --set ana.base.privatization protection --enable ana.sv-comp.functions +#include +#include +extern _Bool __VERIFIER_nondet_bool(); + +int g; +pthread_mutex_t m[2] = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[0]); + pthread_mutex_lock(&m[1]); // so we're unlocking a mutex we definitely hold + g++; + int r = __VERIFIER_nondet_bool(); + pthread_mutex_unlock(&m[r]); // TODO NOWARN (definitely held either way) + // could have unlocked m[0], so should have published g there + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m[0]); + __goblint_check(g == 0); // UNKNOWN! + pthread_mutex_unlock(&m[0]); + return 0; +} diff --git a/tests/regression/13-privatized/93-unlock-idx-ambiguous.t b/tests/regression/13-privatized/93-unlock-idx-ambiguous.t new file mode 100644 index 0000000000..f954ac1d4c --- /dev/null +++ b/tests/regression/13-privatized/93-unlock-idx-ambiguous.t @@ -0,0 +1,75 @@ +TODO: should not succeed + + $ goblint --set ana.base.privatization protection --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) + [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +TODO: should not succeed + + $ goblint --set ana.base.privatization mutex-meet --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) + [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +TODO: should not succeed + + $ goblint --set ana.base.privatization lock --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) + [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +TODO: should not succeed + + $ goblint --set ana.base.privatization write --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) + [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +TODO: should not succeed + + $ goblint --set ana.base.privatization mine-nothread --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) + [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + diff --git a/tests/regression/13-privatized/dune b/tests/regression/13-privatized/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/13-privatized/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) From 682eb0c183c897a31c8862c95a05bbc416437eb9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 13:15:22 +0300 Subject: [PATCH 296/689] Refactor many privatizations to use LockDomain.MustLockset --- src/analyses/apron/relationPriv.apron.ml | 4 +- src/analyses/basePriv.ml | 102 +++++++++++------------ src/analyses/commonPriv.ml | 14 ++-- src/cdomains/lockDomain.ml | 16 ++++ 4 files changed, 75 insertions(+), 61 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 61da6ddc42..cada5ff888 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -579,7 +579,7 @@ struct let lock ask getg (st: relation_components_t) m = let atomic = Param.handle_atomic && LockDomain.Addr.equal m (atomic_mutex) in (* TODO: somehow actually unneeded here? *) - if not atomic && Locksets.(not (Lockset.mem m (current_lockset ask))) then ( + if not atomic && Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( let rel = st.rel in let get_m = get_m_with_mutex_inits ask getg m in (* Additionally filter get_m in case it contains variables it no longer protects. E.g. in 36/22. *) @@ -1089,7 +1089,7 @@ struct let lock ask getg (st: relation_components_t) m = let atomic = Param.handle_atomic && LockDomain.Addr.equal m (atomic_mutex) in - if not atomic && Locksets.(not (Lockset.mem m (current_lockset ask))) then ( + if not atomic && Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( let rel = st.rel in let _,lmust,l = st.priv in let lm = LLock.mutex m in diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index cecc838b9e..f874232176 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -281,7 +281,7 @@ struct cpa' *) let lock ask getg (st: BaseComponents (D).t) m = - if Locksets.(not (Lockset.mem m (current_lockset ask))) then ( + if Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( let get_m = get_m_with_mutex_inits ask getg m in (* Really we want is_unprotected, but pthread_cond_wait emits unlock-lock events, where our (necessary) original context still has the mutex, @@ -377,7 +377,7 @@ struct cpa' *) let lock (ask: Queries.ask) getg (st: BaseComponents (D).t) m = - if Locksets.(not (Lockset.mem m (current_lockset ask))) then ( + if Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( let get_m = get_m_with_mutex_inits ask getg m in (* Additionally filter get_m in case it contains variables it no longer protects. *) let is_in_Gm x _ = is_protected_by ask m x in @@ -523,7 +523,7 @@ struct {st with cpa = cpa'; priv = (W.add x w,LMust.add lm lmust,l')} let lock (ask: Queries.ask) getg (st: BaseComponents (D).t) m = - if Locksets.(not (Lockset.mem m (current_lockset ask))) then ( + if Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( let _,lmust,l = st.priv in let lm = LLock.mutex m in let get_m = get_m_with_mutex_inits (not (LMust.mem lm lmust)) ask getg m in @@ -847,12 +847,12 @@ struct module GWeak = struct - include MapDomain.MapBot (Lockset) (WeakRange) + include MapDomain.MapBot (MustLockset) (WeakRange) let name () = "weak" end module GSync = struct - include MapDomain.MapBot (Lockset) (SyncRange) + include MapDomain.MapBot (MustLockset) (SyncRange) let name () = "synchronized" end module G = @@ -908,10 +908,10 @@ struct let invariant_vars ask getg st = let module VS = Set.Make (CilType.Varinfo) in let s = current_lockset ask in - Lockset.fold (fun m acc -> + MustLockset.fold (fun m acc -> GSync.fold (fun s' cpa' acc -> SyncRange.fold_sync_vars VS.add cpa' acc - ) (G.sync (getg (V.mutex m))) acc + ) (G.sync (getg (V.mutex_mustlock m))) acc ) s VS.empty |> VS.elements end @@ -987,7 +987,7 @@ struct let read_global ask getg (st: BaseComponents (D).t) x = let s = current_lockset ask in GWeak.fold (fun s' tm acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then ThreadMap.fold (fun t' v acc -> VD.join v acc ) tm acc @@ -1007,7 +1007,7 @@ struct let lock ask getg (st: BaseComponents (D).t) m = let s = current_lockset ask in let cpa' = GSync.fold (fun s' cpa' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then CPA.join cpa' acc else acc @@ -1016,13 +1016,13 @@ struct {st with cpa = cpa'} let unlock ask getg sideg (st: BaseComponents (D).t) m = - let s = Lockset.remove m (current_lockset ask) in + let s = MustLockset.remove_addr m (current_lockset ask) in let t = current_thread ask in let side_cpa = CPA.filter (fun x _ -> GWeak.fold (fun s' tm acc -> (* TODO: swap 2^M and T partitioning for lookup by t here first? *) let v = ThreadMap.find t tm in - (Lockset.mem m s' && not (VD.is_bot v)) || acc + (MustLockset.mem_addr m s' && not (VD.is_bot v)) || acc ) (G.weak (getg (V.global x))) false ) st.cpa in @@ -1048,7 +1048,7 @@ struct let read_global ask getg (st: BaseComponents (D).t) x = let s = current_lockset ask in GWeak.fold (fun s' v acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then VD.join v acc else acc @@ -1065,7 +1065,7 @@ struct let lock ask getg (st: BaseComponents (D).t) m = let s = current_lockset ask in let cpa' = GSync.fold (fun s' cpa' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then CPA.join cpa' acc else acc @@ -1074,10 +1074,10 @@ struct {st with cpa = cpa'} let unlock ask getg sideg (st: BaseComponents (D).t) m = - let s = Lockset.remove m (current_lockset ask) in + let s = MustLockset.remove_addr m (current_lockset ask) in let side_cpa = CPA.filter (fun x _ -> GWeak.fold (fun s' v acc -> - (Lockset.mem m s' && not (VD.is_bot v)) || acc + (MustLockset.mem_addr m s' && not (VD.is_bot v)) || acc ) (G.weak (getg (V.global x))) false ) st.cpa in @@ -1119,7 +1119,7 @@ struct let read_global ask getg (st: BaseComponents (D).t) x = let s = current_lockset ask in GWeak.fold (fun s' v acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then VD.join v acc else acc @@ -1140,7 +1140,7 @@ struct let lock ask getg (st: BaseComponents (D).t) m = let s = current_lockset ask in let cpa' = GSync.fold (fun s' cpa' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then CPA.join cpa' acc else acc @@ -1149,7 +1149,7 @@ struct {st with cpa = cpa'} let unlock ask getg sideg (st: BaseComponents (D).t) m = - let s = Lockset.remove m (current_lockset ask) in + let s = MustLockset.remove_addr m (current_lockset ask) in let is_in_W x _ = W.mem x st.priv in let side_cpa = CPA.filter is_in_W st.cpa in sideg (V.mutex m) (G.create_sync (GSync.singleton s side_cpa)); @@ -1169,7 +1169,7 @@ struct if Param.side_effect_global_init then ( CPA.fold (fun x v (st: BaseComponents (D).t) -> if is_global ask x then ( - sideg (V.global x) (G.create_weak (GWeak.singleton (Lockset.empty ()) v)); + sideg (V.global x) (G.create_weak (GWeak.singleton (MustLockset.empty ()) v)); {st with priv = W.add x st.priv} (* TODO: is this add necessary? *) ) else @@ -1222,7 +1222,7 @@ struct let startstate () = (DV.bot (), L.bot ()) - let lockset_init = Lockset.top () + let lockset_init = MustLockset.all () let distr_init getg x v = if get_bool "exp.priv-distr-init" then @@ -1241,7 +1241,7 @@ struct let syncs = UnwrappedG.sync (getg (V.mutex m)) in MinLocksets.fold (fun b acc -> GSync.fold (fun s' cpa' acc -> - if Lockset.disjoint b s' then + if MustLockset.disjoint b s' then let v = CPA.find x cpa' in VD.join v acc else @@ -1254,7 +1254,7 @@ struct in let weaks = UnwrappedG.weak (getg (V.global x)) in let d_weak = GWeak.fold (fun s' v acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then VD.join v acc else acc @@ -1301,7 +1301,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let sideg = Wrapper.sideg ask sideg in let getg = Wrapper.getg ask getg in - let s = Lockset.remove m (current_lockset ask) in + let s = MustLockset.remove_addr m (current_lockset ask) in let is_in_G x _ = is_global ask x in let side_cpa = CPA.filter is_in_G st.cpa in let side_cpa = CPA.mapi (fun x v -> @@ -1355,13 +1355,13 @@ struct module GWeakW = struct - include MapDomain.MapBot (Lockset) (VD) + include MapDomain.MapBot (MustLockset) (VD) let fold_weak f m a = fold (fun _ v a -> f v a) m a end module GSyncW = struct - include MapDomain.MapBot (Lockset) (LockCenteredBase.CPA) + include MapDomain.MapBot (MustLockset) (LockCenteredBase.CPA) let fold_sync_vars f m a = fold (fun _ cpa a -> @@ -1393,11 +1393,11 @@ struct let startstate () = (W.bot (), P.top ()) - let lockset_init = Lockset.top () + let lockset_init = MustLockset.all () let distr_init getg x v = if get_bool "exp.priv-distr-init" then - let v_init = GWeakW.find lockset_init (GWeak.find (Lockset.empty ()) (UnwrappedG.weak (getg (V.global x)))) in + let v_init = GWeakW.find lockset_init (GWeak.find (MustLockset.empty ()) (UnwrappedG.weak (getg (V.global x)))) in VD.join v v_init else v @@ -1408,13 +1408,13 @@ struct let (w, p) = st.priv in let p_x = P.find x p in let d_cpa = CPA.find x st.cpa in - let d_sync = Lockset.fold (fun m acc -> - if MinLocksets.exists (fun s''' -> not (Lockset.mem m s''')) p_x then - let syncs = UnwrappedG.sync (getg (V.mutex m)) in + let d_sync = MustLockset.fold (fun m acc -> + if MinLocksets.exists (fun s''' -> not (MustLockset.mem m s''')) p_x then + let syncs = UnwrappedG.sync (getg (V.mutex_mustlock m)) in GSync.fold (fun s' gsyncw' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then GSyncW.fold (fun w' cpa' acc -> - if MinLocksets.exists (fun s'' -> Lockset.disjoint s'' w') p_x then + if MinLocksets.exists (fun s'' -> MustLockset.disjoint s'' w') p_x then let v = CPA.find x cpa' in VD.join v acc else @@ -1429,9 +1429,9 @@ struct in let weaks = UnwrappedG.weak (getg (V.global x)) in let d_weak = GWeak.fold (fun s' gweakw' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then GWeakW.fold (fun w' v acc -> - if MinLocksets.exists (fun s'' -> Lockset.disjoint s'' w') p_x then + if MinLocksets.exists (fun s'' -> MustLockset.disjoint s'' w') p_x then VD.join v acc else acc @@ -1471,7 +1471,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let getg = Wrapper.getg ask getg in let sideg = Wrapper.sideg ask sideg in - let s = Lockset.remove m (current_lockset ask) in + let s = MustLockset.remove_addr m (current_lockset ask) in let (w, p) = st.priv in let p' = P.map (fun s' -> MinLocksets.add s s') p in if M.tracing then M.traceli "priv" "unlock %a %a" Lock.pretty m CPA.pretty st.cpa; @@ -1507,7 +1507,7 @@ struct if EscapeDomain.EscapedVars.mem x escaped then ( let (w, p) = st.priv in let p' = P.add x (MinLocksets.singleton s) p in - sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (Lockset.empty ()) (GWeakW.singleton lockset_init v))); + sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (MustLockset.empty ()) (GWeakW.singleton lockset_init v))); {st with cpa = CPA.remove x st.cpa; priv = (w, p')} ) else @@ -1518,7 +1518,7 @@ struct let sideg = Wrapper.sideg ask sideg in CPA.fold (fun x v (st: BaseComponents (D).t) -> if is_global ask x then ( - sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (Lockset.empty ()) (GWeakW.singleton lockset_init v))); + sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (MustLockset.empty ()) (GWeakW.singleton lockset_init v))); {st with cpa = CPA.remove x st.cpa} ) else @@ -1548,11 +1548,11 @@ struct let startstate () = ((W.bot (), P.top ()), (DV.bot (), L.bot ())) - let lockset_init = Lockset.top () + let lockset_init = MustLockset.all () let distr_init getg x v = if get_bool "exp.priv-distr-init" then - let v_init = GWeakW.find lockset_init (GWeak.find (Lockset.empty ()) (UnwrappedG.weak (getg (V.global x)))) in + let v_init = GWeakW.find lockset_init (GWeak.find (MustLockset.empty ()) (UnwrappedG.weak (getg (V.global x)))) in VD.join v v_init else v @@ -1568,9 +1568,9 @@ struct let syncs = UnwrappedG.sync (getg (V.mutex m)) in MinLocksets.fold (fun b acc -> GSync.fold (fun s' gsyncw' acc -> - if Lockset.disjoint b s' then + if MustLockset.disjoint b s' then GSyncW.fold (fun w' cpa' acc -> - if MinLocksets.exists (fun s'' -> Lockset.disjoint s'' w') p_x then + if MinLocksets.exists (fun s'' -> MustLockset.disjoint s'' w') p_x then let v = CPA.find x cpa' in VD.join v acc else @@ -1586,9 +1586,9 @@ struct in let weaks = UnwrappedG.weak (getg (V.global x)) in let d_m_weak = GWeak.fold (fun s' gweakw' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then GWeakW.fold (fun w' v acc -> - if MinLocksets.exists (fun s'' -> Lockset.disjoint s'' w') p_x then + if MinLocksets.exists (fun s'' -> MustLockset.disjoint s'' w') p_x then VD.join v acc else acc @@ -1598,13 +1598,13 @@ struct ) weaks (VD.bot ()) in let d_m = VD.join d_m_sync d_m_weak in - let d_g_sync = Lockset.fold (fun m acc -> - if MinLocksets.exists (fun s''' -> not (Lockset.mem m s''')) p_x then - let syncs = UnwrappedG.sync (getg (V.mutex m)) in + let d_g_sync = MustLockset.fold (fun m acc -> + if MinLocksets.exists (fun s''' -> not (MustLockset.mem m s''')) p_x then + let syncs = UnwrappedG.sync (getg (V.mutex_mustlock m)) in GSync.fold (fun s' gsyncw' acc -> - if Lockset.disjoint s s' then + if MustLockset.disjoint s s' then GSyncW.fold (fun w' cpa' acc -> - if MinLocksets.exists (fun s'' -> Lockset.disjoint s'' w') p_x then + if MinLocksets.exists (fun s'' -> MustLockset.disjoint s'' w') p_x then let v = CPA.find x cpa' in VD.join v acc else @@ -1656,7 +1656,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let getg = Wrapper.getg ask getg in let sideg = Wrapper.sideg ask sideg in - let s = Lockset.remove m (current_lockset ask) in + let s = MustLockset.remove_addr m (current_lockset ask) in let ((w, p), vl) = st.priv in let p' = P.map (fun s' -> MinLocksets.add s s') p in let side_gsyncw = CPA.fold (fun x v acc -> @@ -1689,7 +1689,7 @@ struct if EscapeDomain.EscapedVars.mem x escaped then ( let ((w, p), (vv, l)) = st.priv in let p' = P.add x (MinLocksets.singleton s) p in - sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (Lockset.empty ()) (GWeakW.singleton lockset_init v))); + sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (MustLockset.empty ()) (GWeakW.singleton lockset_init v))); {st with cpa = CPA.remove x st.cpa; priv = ((w, p'), (vv, l))} ) else @@ -1700,7 +1700,7 @@ struct let sideg = Wrapper.sideg ask sideg in CPA.fold (fun x v (st: BaseComponents (D).t) -> if is_global ask x then ( - sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (Lockset.empty ()) (GWeakW.singleton lockset_init v))); + sideg (V.global x) (UnwrappedG.create_weak (GWeak.singleton (MustLockset.empty ()) (GWeakW.singleton lockset_init v))); {st with cpa = CPA.remove x st.cpa} ) else diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index aa829c4606..2334d76918 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -106,6 +106,7 @@ struct include Printable.Either3Conf (struct include Printable.DefaultConf let expand2 = false end) (VMutex) (VMutexInits) (VGlobal) let name () = "MutexGlobals" let mutex x: t = `Left x + let mutex_mustlock x = mutex (Addr (LockDomain.MustLock.to_mval x)) let mutex_inits: t = `Middle () let global x: t = `Right x end @@ -136,17 +137,14 @@ struct let name () = "lock" end - module Lockset = SetDomain.ToppedSet (Lock) (struct let topname = "All locks" end) + module MustLockset = LockDomain.MustLockset - module MustLockset = SetDomain.Reverse (Lockset) - - let current_lockset (ask: Q.ask): Lockset.t = + let current_lockset (ask: Q.ask): MustLockset.t = (* TODO: remove this global_init workaround *) if !AnalysisState.global_initialization then - Lockset.empty () + MustLockset.empty () else - let mls = ask.f Queries.MustLockset in - LockDomain.MustLockset.fold (fun ml acc -> Lockset.add (Addr (LockDomain.MustLock.to_mval ml)) acc) mls (Lockset.empty ()) (* TODO: use MustLockset as Lockset *) + ask.f Queries.MustLockset (* TODO: reversed SetDomain.Hoare *) module MinLocksets = HoareDomain.Set_LiftTop (MustLockset) (struct let topname = "All locksets" end) (* reverse Lockset because Hoare keeps maximal, but we need minimal *) @@ -171,7 +169,7 @@ struct let name () = "P" (* TODO: change MinLocksets.exists/top instead? *) - let find x p = find_opt x p |? MinLocksets.singleton (Lockset.empty ()) (* ensure exists has something to check for thread returns *) + let find x p = find_opt x p |? MinLocksets.singleton (MustLockset.empty ()) (* ensure exists has something to check for thread returns *) end end diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 35d73e5f28..1c9fcb98c7 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -35,6 +35,22 @@ module MustLockset = struct include SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) + let mem_addr (a: Addr.t) (set: t) = (* TODO: replace with mem_mval *) + match Addr.to_mval a with + | Some mv when Mval.is_definite mv -> + let ml = MustLock.of_mval mv in + mem ml set + | _ -> + false + + let remove_addr (a: Addr.t) (set: t) = (* TODO: replace with remove_mval *) + match Addr.to_mval a with + | Some mv when Mval.is_definite mv -> + let ml = MustLock.of_mval mv in + remove ml set + | _ -> + set + let all (): t = `Top let is_all (set: t) = set = `Top end From e6429f02214a42d1f50bc1c1ab0d304018f516df Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 14:32:41 +0300 Subject: [PATCH 297/689] Fix base privatization unsoundness with non-definite mutex unlock --- src/analyses/base.ml | 34 +++++++++++++++---- .../13-privatized/93-unlock-idx-ambiguous.t | 20 +++-------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 67e6276239..13cf9f20da 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -3062,13 +3062,35 @@ struct match e with | Events.Lock (addr, _) when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) if M.tracing then M.tracel "priv" "LOCK EVENT %a" LockDomain.Addr.pretty addr; - Priv.lock ask (priv_getg ctx.global) st addr + begin match addr with + | UnknownPtr -> ctx.local + | Addr (v, _) when ctx.ask (IsMultiple v) -> ctx.local + | Addr (v, o) when Addr.Mval.is_definite (v, o) -> + Priv.lock ask (priv_getg ctx.global) st addr + | _ -> ctx.local + end | Events.Unlock addr when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) - if addr = UnknownPtr then - M.info ~category:Unsound "Unknown mutex unlocked, base privatization unsound"; (* TODO: something more sound *) - WideningTokens.with_local_side_tokens (fun () -> - Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st addr - ) + begin match addr with + | UnknownPtr -> + M.info ~category:Unsound "Unknown mutex unlocked, base privatization unsound"; (* TODO: something more sound *) + ctx.local (* TODO: remove all! *) + | Addr (v, o) when Addr.Mval.is_definite (v, o) -> + WideningTokens.with_local_side_tokens (fun () -> + Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st addr + ) + | Addr (v, o) -> + WideningTokens.with_local_side_tokens (fun () -> + let s = ctx.ask MustLockset in + LockDomain.MustLockset.fold (fun ml st -> + if LockDomain.MustLock.semantic_equal_mval ml (v, o) = Some false then + st + else + let addr = Addr.Addr (LockDomain.MustLock.to_mval ml) in + Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st addr + ) s st + ) + | _ -> ctx.local + end | Events.Escape escaped -> Priv.escape ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st escaped | Events.EnterMultiThreaded -> diff --git a/tests/regression/13-privatized/93-unlock-idx-ambiguous.t b/tests/regression/13-privatized/93-unlock-idx-ambiguous.t index f954ac1d4c..8f24d728bf 100644 --- a/tests/regression/13-privatized/93-unlock-idx-ambiguous.t +++ b/tests/regression/13-privatized/93-unlock-idx-ambiguous.t @@ -1,8 +1,6 @@ -TODO: should not succeed - $ goblint --set ana.base.privatization protection --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) - [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Warning][Assert] Assertion "g == 0" is unknown. (93-unlock-idx-ambiguous.c:24:3-24:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 @@ -13,11 +11,9 @@ TODO: should not succeed unsafe: 0 total memory locations: 1 -TODO: should not succeed - $ goblint --set ana.base.privatization mutex-meet --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) - [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Warning][Assert] Assertion "g == 0" is unknown. (93-unlock-idx-ambiguous.c:24:3-24:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 @@ -28,11 +24,9 @@ TODO: should not succeed unsafe: 0 total memory locations: 1 -TODO: should not succeed - $ goblint --set ana.base.privatization lock --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) - [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Warning][Assert] Assertion "g == 0" is unknown. (93-unlock-idx-ambiguous.c:24:3-24:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 @@ -43,11 +37,9 @@ TODO: should not succeed unsafe: 0 total memory locations: 1 -TODO: should not succeed - $ goblint --set ana.base.privatization write --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) - [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Warning][Assert] Assertion "g == 0" is unknown. (93-unlock-idx-ambiguous.c:24:3-24:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 @@ -58,11 +50,9 @@ TODO: should not succeed unsafe: 0 total memory locations: 1 -TODO: should not succeed - $ goblint --set ana.base.privatization mine-nothread --enable ana.sv-comp.functions 93-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (93-unlock-idx-ambiguous.c:14:3-14:30) - [Success][Assert] Assertion "g == 0" will succeed (93-unlock-idx-ambiguous.c:24:3-24:26) + [Warning][Assert] Assertion "g == 0" is unknown. (93-unlock-idx-ambiguous.c:24:3-24:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 From b5bdf56373ac0ffd02728e1e55d7a512241c9562 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Sun, 2 Jun 2024 18:26:57 +0200 Subject: [PATCH 298/689] int intervals: allow narrowing from widening thresholds --- src/cdomain/value/cdomains/intDomain.ml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 3bf81b1ba1..f482842ca8 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -572,6 +572,16 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct let min_ik' = Ints_t.to_bigint min_ik in let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in BatOption.map_default Ints_t.of_bigint min_ik t + let is_upper_threshold u = + let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in + let u = Ints_t.to_bigint u in + let t = List.find_opt (fun x -> Z.compare u x = 0) ts in + Option.is_some t + let is_lower_threshold l = + let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in + let l = Ints_t.to_bigint l in + let t = List.find_opt (fun x -> Z.compare l x = 0) ts in + Option.is_some t end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = @@ -702,9 +712,10 @@ struct match x, y with | _,None | None, _ -> None | Some (x1,x2), Some (y1,y2) -> + let threshold = get_interval_threshold_widening () in let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 then y2 else x2 in + let lr = if Ints_t.compare min_ik x1 = 0 || threshold && IArith.is_lower_threshold x1 then y1 else x1 in + let ur = if Ints_t.compare max_ik x2 = 0 || threshold && IArith.is_upper_threshold x2 then y2 else x2 in norm ik @@ Some (lr,ur) |> fst From 87d9a3b5c2b9848105805e08a2e30bb566c40595 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Tue, 4 Jun 2024 13:03:59 +0200 Subject: [PATCH 299/689] add test for narrowing from thresholds --- tests/regression/03-practical/33-threshold-narrowing.c | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/regression/03-practical/33-threshold-narrowing.c diff --git a/tests/regression/03-practical/33-threshold-narrowing.c b/tests/regression/03-practical/33-threshold-narrowing.c new file mode 100644 index 0000000000..0c713fa273 --- /dev/null +++ b/tests/regression/03-practical/33-threshold-narrowing.c @@ -0,0 +1,8 @@ +// PARAM: --enable ana.int.interval --enable ana.int.interval_threshold_widening --set ana.int.interval_threshold_widening_constants comparisons +#include + +int main() { + int i; + for(i = 0; i < 10 && i < 20; i += 3); + __goblint_check(i <= 12); +} From ee6a4fb363337cfeb3da593f9c1e0f3e1bc552bd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 15:10:30 +0300 Subject: [PATCH 300/689] Add unsound test for unlocking non-definite mutex in relational privatizations --- .../46-apron2/87-unlock-idx-ambiguous.c | 28 +++++++++++++ .../46-apron2/87-unlock-idx-ambiguous.t | 39 +++++++++++++++++++ tests/regression/46-apron2/dune | 3 ++ 3 files changed, 70 insertions(+) create mode 100644 tests/regression/46-apron2/87-unlock-idx-ambiguous.c create mode 100644 tests/regression/46-apron2/87-unlock-idx-ambiguous.t diff --git a/tests/regression/46-apron2/87-unlock-idx-ambiguous.c b/tests/regression/46-apron2/87-unlock-idx-ambiguous.c new file mode 100644 index 0000000000..97cada5369 --- /dev/null +++ b/tests/regression/46-apron2/87-unlock-idx-ambiguous.c @@ -0,0 +1,28 @@ +// PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag +// TODO: why nonterm without threadflag path-sens? +#include +#include +extern _Bool __VERIFIER_nondet_bool(); + +int g; +pthread_mutex_t m[2] = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[0]); + pthread_mutex_lock(&m[1]); // so we're unlocking a mutex we definitely hold + g++; + int r = __VERIFIER_nondet_bool(); + pthread_mutex_unlock(&m[r]); // TODO NOWARN (definitely held either way) + // could have unlocked m[0], so should have published g there + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m[0]); + __goblint_check(g == 0); // UNKNOWN! + pthread_mutex_unlock(&m[0]); + return 0; +} diff --git a/tests/regression/46-apron2/87-unlock-idx-ambiguous.t b/tests/regression/46-apron2/87-unlock-idx-ambiguous.t new file mode 100644 index 0000000000..5ff63babdc --- /dev/null +++ b/tests/regression/46-apron2/87-unlock-idx-ambiguous.t @@ -0,0 +1,39 @@ + $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 87-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (87-unlock-idx-ambiguous.c:15:3-15:30) + [Success][Assert] Assertion "g == 0" will succeed (87-unlock-idx-ambiguous.c:25:3-25:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 87-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (87-unlock-idx-ambiguous.c:15:3-15:30) + [Success][Assert] Assertion "g == 0" will succeed (87-unlock-idx-ambiguous.c:25:3-25:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid-cluster12 --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 87-unlock-idx-ambiguous.c + [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (87-unlock-idx-ambiguous.c:15:3-15:30) + [Success][Assert] Assertion "g == 0" will succeed (87-unlock-idx-ambiguous.c:25:3-25:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + diff --git a/tests/regression/46-apron2/dune b/tests/regression/46-apron2/dune index cc0c04185c..f88a15d505 100644 --- a/tests/regression/46-apron2/dune +++ b/tests/regression/46-apron2/dune @@ -8,3 +8,6 @@ (glob_files ??-*.c)) (locks /update_suite) (action (chdir ../../.. (run %{update_suite} group apron2 -q)))) + +(cram + (deps (glob_files *.c))) From 9d32c70dbe8f336293b09da1550666203fd5ee45 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 15:18:34 +0300 Subject: [PATCH 301/689] Port base privatization non-definite mutex unlock unsoundness fix to relation --- src/analyses/apron/relationAnalysis.apron.ml | 34 +++++++++++++++---- .../46-apron2/87-unlock-idx-ambiguous.t | 6 ++-- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 6c118dac7a..0431d19a3e 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -685,13 +685,35 @@ struct let st = ctx.local in match e with | Events.Lock (addr, _) when ThreadFlag.has_ever_been_multi (Analyses.ask_of_ctx ctx) -> (* TODO: is this condition sound? *) - Priv.lock (Analyses.ask_of_ctx ctx) ctx.global st addr + begin match addr with + | UnknownPtr -> ctx.local + | Addr (v, _) when ctx.ask (IsMultiple v) -> ctx.local + | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> + Priv.lock (Analyses.ask_of_ctx ctx) ctx.global st addr + | _ -> ctx.local + end | Events.Unlock addr when ThreadFlag.has_ever_been_multi (Analyses.ask_of_ctx ctx) -> (* TODO: is this condition sound? *) - if addr = UnknownPtr then - M.info ~category:Unsound "Unknown mutex unlocked, relation privatization unsound"; (* TODO: something more sound *) - WideningTokens.with_local_side_tokens (fun () -> - Priv.unlock (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st addr - ) + begin match addr with + | UnknownPtr -> + M.info ~category:Unsound "Unknown mutex unlocked, relation privatization unsound"; (* TODO: something more sound *) + ctx.local (* TODO: remove all! *) + | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> + WideningTokens.with_local_side_tokens (fun () -> + Priv.unlock (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st addr + ) + | Addr (v, o) -> + WideningTokens.with_local_side_tokens (fun () -> + let s = ctx.ask MustLockset in + LockDomain.MustLockset.fold (fun ml st -> + if LockDomain.MustLock.semantic_equal_mval ml (v, o) = Some false then + st + else + let addr = LockDomain.Addr.Addr (LockDomain.MustLock.to_mval ml) in + Priv.unlock (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st addr + ) s st + ) + | _ -> ctx.local + end | Events.EnterMultiThreaded -> Priv.enter_multithreaded (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st | Events.Escape escaped -> diff --git a/tests/regression/46-apron2/87-unlock-idx-ambiguous.t b/tests/regression/46-apron2/87-unlock-idx-ambiguous.t index 5ff63babdc..abbdd74f00 100644 --- a/tests/regression/46-apron2/87-unlock-idx-ambiguous.t +++ b/tests/regression/46-apron2/87-unlock-idx-ambiguous.t @@ -1,6 +1,6 @@ $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 87-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (87-unlock-idx-ambiguous.c:15:3-15:30) - [Success][Assert] Assertion "g == 0" will succeed (87-unlock-idx-ambiguous.c:25:3-25:26) + [Warning][Assert] Assertion "g == 0" is unknown. (87-unlock-idx-ambiguous.c:25:3-25:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 @@ -13,7 +13,7 @@ $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 87-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (87-unlock-idx-ambiguous.c:15:3-15:30) - [Success][Assert] Assertion "g == 0" will succeed (87-unlock-idx-ambiguous.c:25:3-25:26) + [Warning][Assert] Assertion "g == 0" is unknown. (87-unlock-idx-ambiguous.c:25:3-25:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 @@ -26,7 +26,7 @@ $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid-cluster12 --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 87-unlock-idx-ambiguous.c [Warning][Unknown] unlocking mutex (m[def_exc:Unknown int([0,1])]) which may not be held (87-unlock-idx-ambiguous.c:15:3-15:30) - [Success][Assert] Assertion "g == 0" will succeed (87-unlock-idx-ambiguous.c:25:3-25:26) + [Warning][Assert] Assertion "g == 0" is unknown. (87-unlock-idx-ambiguous.c:25:3-25:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 From 4caae9403f38049989689becb026137248c6c1de Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 15:42:26 +0300 Subject: [PATCH 302/689] Extract CommonPriv.lift_lock and lift_unlock --- src/analyses/apron/relationAnalysis.apron.ml | 41 ++++++-------------- src/analyses/base.ml | 36 ++++------------- src/analyses/commonPriv.ml | 27 +++++++++++++ 3 files changed, 46 insertions(+), 58 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 0431d19a3e..4a6b266c25 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -682,38 +682,19 @@ struct ctx.local let event ctx e octx = + let ask = Analyses.ask_of_ctx ctx in let st = ctx.local in match e with - | Events.Lock (addr, _) when ThreadFlag.has_ever_been_multi (Analyses.ask_of_ctx ctx) -> (* TODO: is this condition sound? *) - begin match addr with - | UnknownPtr -> ctx.local - | Addr (v, _) when ctx.ask (IsMultiple v) -> ctx.local - | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> - Priv.lock (Analyses.ask_of_ctx ctx) ctx.global st addr - | _ -> ctx.local - end - | Events.Unlock addr when ThreadFlag.has_ever_been_multi (Analyses.ask_of_ctx ctx) -> (* TODO: is this condition sound? *) - begin match addr with - | UnknownPtr -> - M.info ~category:Unsound "Unknown mutex unlocked, relation privatization unsound"; (* TODO: something more sound *) - ctx.local (* TODO: remove all! *) - | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> - WideningTokens.with_local_side_tokens (fun () -> - Priv.unlock (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st addr - ) - | Addr (v, o) -> - WideningTokens.with_local_side_tokens (fun () -> - let s = ctx.ask MustLockset in - LockDomain.MustLockset.fold (fun ml st -> - if LockDomain.MustLock.semantic_equal_mval ml (v, o) = Some false then - st - else - let addr = LockDomain.Addr.Addr (LockDomain.MustLock.to_mval ml) in - Priv.unlock (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st addr - ) s st - ) - | _ -> ctx.local - end + | Events.Lock (addr, _) when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) + CommonPriv.lift_lock ask (fun st m -> + Priv.lock ask ctx.global st m + ) st addr + | Events.Unlock addr when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) + WideningTokens.with_local_side_tokens (fun () -> + CommonPriv.lift_unlock ask (fun st m -> + Priv.unlock ask ctx.global ctx.sideg st m + ) st addr + ) | Events.EnterMultiThreaded -> Priv.enter_multithreaded (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st | Events.Escape escaped -> diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 13cf9f20da..fe4dc3e7de 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -3062,35 +3062,15 @@ struct match e with | Events.Lock (addr, _) when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) if M.tracing then M.tracel "priv" "LOCK EVENT %a" LockDomain.Addr.pretty addr; - begin match addr with - | UnknownPtr -> ctx.local - | Addr (v, _) when ctx.ask (IsMultiple v) -> ctx.local - | Addr (v, o) when Addr.Mval.is_definite (v, o) -> - Priv.lock ask (priv_getg ctx.global) st addr - | _ -> ctx.local - end + CommonPriv.lift_lock ask (fun st m -> + Priv.lock ask (priv_getg ctx.global) st m + ) st addr | Events.Unlock addr when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) - begin match addr with - | UnknownPtr -> - M.info ~category:Unsound "Unknown mutex unlocked, base privatization unsound"; (* TODO: something more sound *) - ctx.local (* TODO: remove all! *) - | Addr (v, o) when Addr.Mval.is_definite (v, o) -> - WideningTokens.with_local_side_tokens (fun () -> - Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st addr - ) - | Addr (v, o) -> - WideningTokens.with_local_side_tokens (fun () -> - let s = ctx.ask MustLockset in - LockDomain.MustLockset.fold (fun ml st -> - if LockDomain.MustLock.semantic_equal_mval ml (v, o) = Some false then - st - else - let addr = Addr.Addr (LockDomain.MustLock.to_mval ml) in - Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st addr - ) s st - ) - | _ -> ctx.local - end + WideningTokens.with_local_side_tokens (fun () -> + CommonPriv.lift_unlock ask (fun st m -> + Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st m + ) st addr + ) | Events.Escape escaped -> Priv.escape ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st escaped | Events.EnterMultiThreaded -> diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index aa829c4606..02ad65d8b6 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -305,3 +305,30 @@ struct let startstate () = W.bot (), LMust.top (), L.bot () end + + +let lift_lock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = + match addr with + | UnknownPtr -> st + | Addr (v, _) when ask.f (IsMultiple v) -> st + | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> + f st addr + | _ -> st + +let lift_unlock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = + match addr with + | UnknownPtr -> + M.info ~category:Unsound "Unknown mutex unlocked, privatization unsound"; (* TODO: something more sound *) + st (* TODO: remove all! *) + | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> + f st addr + | Addr (v, o) -> + let s = ask.f MustLockset in + LockDomain.MustLockset.fold (fun ml st -> + if LockDomain.MustLock.semantic_equal_mval ml (v, o) = Some false then + st + else + let addr = LockDomain.Addr.Addr (LockDomain.MustLock.to_mval ml) in + f st addr + ) s st + | _ -> st From ba3c020eb69b44ff7e1221f40103064c40ef3d0a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 15:54:35 +0300 Subject: [PATCH 303/689] Refactor CommonPriv.lift_lock and lift_unlock --- src/analyses/commonPriv.ml | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 02ad65d8b6..127dfe0383 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -308,27 +308,36 @@ end let lift_lock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = + (* Should be in sync with: + 1. LocksetAnalysis.MakeMust.event + 2. MutexAnalysis.Spec.Arg.add + 3. LockDomain.MustLocksetRW.add_mval_rw *) match addr with | UnknownPtr -> st | Addr (v, _) when ask.f (IsMultiple v) -> st - | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> - f st addr - | _ -> st + | Addr mv when LockDomain.Mval.is_definite mv -> f st addr + | Addr _ + | NullPtr + | StrPtr _ -> st let lift_unlock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = + (* Should be in sync with: + 1. LocksetAnalysis.MakeMust.event + 2. MutexAnalysis.Spec.Arg.remove + 3. MutexAnalysis.Spec.Arg.remove_all + 4. LockDomain.MustLocksetRW.remove_mval_rw *) match addr with | UnknownPtr -> M.info ~category:Unsound "Unknown mutex unlocked, privatization unsound"; (* TODO: something more sound *) st (* TODO: remove all! *) - | Addr (v, o) when LockDomain.Mval.is_definite (v, o) -> - f st addr - | Addr (v, o) -> - let s = ask.f MustLockset in + | StrPtr _ + | NullPtr -> st + | Addr mv when LockDomain.Mval.is_definite mv -> f st addr + | Addr mv -> LockDomain.MustLockset.fold (fun ml st -> - if LockDomain.MustLock.semantic_equal_mval ml (v, o) = Some false then + if LockDomain.MustLock.semantic_equal_mval ml mv = Some false then st else - let addr = LockDomain.Addr.Addr (LockDomain.MustLock.to_mval ml) in - f st addr - ) s st - | _ -> st + (* call privatization's unlock only with definite lock *) + f st (Addr (LockDomain.MustLock.to_mval ml)) (* TODO: no conversion *) + ) (ask.f MustLockset) st From 3dcf0c1c05173a5cb8dd7b4a7feb5e4235d4c542 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 16:00:46 +0300 Subject: [PATCH 304/689] Add unsound test for unlocking unknown mutex in privatizations --- .../13-privatized/94-unlock-unknown.c | 25 +++++++ .../13-privatized/94-unlock-unknown.t | 75 +++++++++++++++++++ .../regression/46-apron2/88-unlock-unknown.c | 25 +++++++ .../regression/46-apron2/88-unlock-unknown.t | 45 +++++++++++ 4 files changed, 170 insertions(+) create mode 100644 tests/regression/13-privatized/94-unlock-unknown.c create mode 100644 tests/regression/13-privatized/94-unlock-unknown.t create mode 100644 tests/regression/46-apron2/88-unlock-unknown.c create mode 100644 tests/regression/46-apron2/88-unlock-unknown.t diff --git a/tests/regression/13-privatized/94-unlock-unknown.c b/tests/regression/13-privatized/94-unlock-unknown.c new file mode 100644 index 0000000000..0897c38de8 --- /dev/null +++ b/tests/regression/13-privatized/94-unlock-unknown.c @@ -0,0 +1,25 @@ +// PARAM: --set ana.base.privatization protection --enable ana.sv-comp.functions +#include +#include + +int g; +pthread_mutex_t m[2] = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[0]); + g++; + pthread_mutex_t *r; // rand + pthread_mutex_unlock(r); + // could have unlocked m[0], so should have published g there + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m[0]); + __goblint_check(g == 0); // UNKNOWN! + pthread_mutex_unlock(&m[0]); + return 0; +} diff --git a/tests/regression/13-privatized/94-unlock-unknown.t b/tests/regression/13-privatized/94-unlock-unknown.t new file mode 100644 index 0000000000..2d4e0d97cc --- /dev/null +++ b/tests/regression/13-privatized/94-unlock-unknown.t @@ -0,0 +1,75 @@ + $ goblint --set ana.base.privatization protection --enable ana.sv-comp.functions 94-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.base.privatization mutex-meet --enable ana.sv-comp.functions 94-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.base.privatization lock --enable ana.sv-comp.functions 94-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.base.privatization write --enable ana.sv-comp.functions 94-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.base.privatization mine-nothread --enable ana.sv-comp.functions 94-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + diff --git a/tests/regression/46-apron2/88-unlock-unknown.c b/tests/regression/46-apron2/88-unlock-unknown.c new file mode 100644 index 0000000000..3e09ee8659 --- /dev/null +++ b/tests/regression/46-apron2/88-unlock-unknown.c @@ -0,0 +1,25 @@ +// PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions +#include +#include + +int g; +pthread_mutex_t m[2] = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[0]); + g++; + pthread_mutex_t *r; // rand + pthread_mutex_unlock(r); + // could have unlocked m[0], so should have published g there + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m[0]); + __goblint_check(g == 0); // UNKNOWN! + pthread_mutex_unlock(&m[0]); + return 0; +} diff --git a/tests/regression/46-apron2/88-unlock-unknown.t b/tests/regression/46-apron2/88-unlock-unknown.t new file mode 100644 index 0000000000..f6649a116e --- /dev/null +++ b/tests/regression/46-apron2/88-unlock-unknown.t @@ -0,0 +1,45 @@ + $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions 88-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (88-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (88-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (88-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (88-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 88-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (88-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (88-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (88-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (88-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid-cluster12 --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 88-unlock-unknown.c + [Info][Unsound] Unknown mutex unlocked, privatization unsound (88-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking unknown mutex which may not be held (88-unlock-unknown.c:12:3-12:26) + [Warning][Unknown] unlocking NULL mutex (88-unlock-unknown.c:12:3-12:26) + [Success][Assert] Assertion "g == 0" will succeed (88-unlock-unknown.c:22:3-22:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + From fade1823f0f44e3e20cbb61522b276a4c538feb6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 16:02:51 +0300 Subject: [PATCH 305/689] Fix privatization unlocking unknown mutex unsoundness --- src/analyses/commonPriv.ml | 6 ++++-- .../regression/13-privatized/94-unlock-unknown.t | 15 +++++---------- tests/regression/46-apron2/88-unlock-unknown.t | 9 +++------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 127dfe0383..fb5d0db142 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -328,8 +328,10 @@ let lift_unlock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = 4. LockDomain.MustLocksetRW.remove_mval_rw *) match addr with | UnknownPtr -> - M.info ~category:Unsound "Unknown mutex unlocked, privatization unsound"; (* TODO: something more sound *) - st (* TODO: remove all! *) + LockDomain.MustLockset.fold (fun ml st -> + (* call privatization's unlock only with definite lock *) + f st (LockDomain.Addr.Addr (LockDomain.MustLock.to_mval ml)) (* TODO: no conversion *) + ) (ask.f MustLockset) st | StrPtr _ | NullPtr -> st | Addr mv when LockDomain.Mval.is_definite mv -> f st addr diff --git a/tests/regression/13-privatized/94-unlock-unknown.t b/tests/regression/13-privatized/94-unlock-unknown.t index 2d4e0d97cc..cc0aa921fe 100644 --- a/tests/regression/13-privatized/94-unlock-unknown.t +++ b/tests/regression/13-privatized/94-unlock-unknown.t @@ -1,8 +1,7 @@ $ goblint --set ana.base.privatization protection --enable ana.sv-comp.functions 94-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (94-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 @@ -14,10 +13,9 @@ total memory locations: 1 $ goblint --set ana.base.privatization mutex-meet --enable ana.sv-comp.functions 94-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (94-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 @@ -29,10 +27,9 @@ total memory locations: 1 $ goblint --set ana.base.privatization lock --enable ana.sv-comp.functions 94-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (94-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 @@ -44,10 +41,9 @@ total memory locations: 1 $ goblint --set ana.base.privatization write --enable ana.sv-comp.functions 94-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (94-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 @@ -59,10 +55,9 @@ total memory locations: 1 $ goblint --set ana.base.privatization mine-nothread --enable ana.sv-comp.functions 94-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (94-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (94-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (94-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (94-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 diff --git a/tests/regression/46-apron2/88-unlock-unknown.t b/tests/regression/46-apron2/88-unlock-unknown.t index f6649a116e..35e4ec4503 100644 --- a/tests/regression/46-apron2/88-unlock-unknown.t +++ b/tests/regression/46-apron2/88-unlock-unknown.t @@ -1,8 +1,7 @@ $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions 88-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (88-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (88-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (88-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (88-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (88-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 @@ -14,10 +13,9 @@ total memory locations: 1 $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 88-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (88-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (88-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (88-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (88-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (88-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 @@ -29,10 +27,9 @@ total memory locations: 1 $ goblint --set ana.activated[+] apron --set ana.relation.privatization mutex-meet-tid-cluster12 --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag 88-unlock-unknown.c - [Info][Unsound] Unknown mutex unlocked, privatization unsound (88-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking unknown mutex which may not be held (88-unlock-unknown.c:12:3-12:26) [Warning][Unknown] unlocking NULL mutex (88-unlock-unknown.c:12:3-12:26) - [Success][Assert] Assertion "g == 0" will succeed (88-unlock-unknown.c:22:3-22:26) + [Warning][Assert] Assertion "g == 0" is unknown. (88-unlock-unknown.c:22:3-22:26) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 From aeae2a97d2d475bba55ed2f0b8af94d497e7ab1c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 16:37:20 +0300 Subject: [PATCH 306/689] Refactor privatizations' lock and unlock mutex type to Mustlock --- src/analyses/apron/relationPriv.apron.ml | 28 +++++++------- src/analyses/basePriv.ml | 48 ++++++++++++------------ src/analyses/basePriv.mli | 4 +- src/analyses/commonPriv.ml | 18 ++++----- src/cdomains/lockDomain.ml | 2 + 5 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index cada5ff888..1302fa3743 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -33,8 +33,8 @@ module type S = the state when following conditional guards. *) val write_global: ?invariant:bool -> Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> varinfo -> varinfo -> relation_components_t - val lock: Q.ask -> (V.t -> G.t) -> relation_components_t -> LockDomain.Addr.t -> relation_components_t - val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> LockDomain.Addr.t -> relation_components_t + val lock: Q.ask -> (V.t -> G.t) -> relation_components_t -> LockDomain.MustLock.t -> relation_components_t + val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> LockDomain.MustLock.t -> relation_components_t val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> [`Normal | `Join | `Return | `Init | `Thread] -> relation_components_t @@ -471,7 +471,7 @@ struct let startstate () = () - let atomic_mutex = LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var + let atomic_mutex = LockDomain.MustLock.of_var LibraryFunctions.verifier_atomic_var let get_m_with_mutex_inits ask getg m = let get_m = getg (V.mutex m) in @@ -577,9 +577,9 @@ struct let write_escape = write_global_internal ~skip_meet:true let lock ask getg (st: relation_components_t) m = - let atomic = Param.handle_atomic && LockDomain.Addr.equal m (atomic_mutex) in + let atomic = Param.handle_atomic && LockDomain.MustLock.equal m atomic_mutex in (* TODO: somehow actually unneeded here? *) - if not atomic && Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( + if not atomic && Locksets.(not (MustLockset.mem m (current_lockset ask))) then ( let rel = st.rel in let get_m = get_m_with_mutex_inits ask getg m in (* Additionally filter get_m in case it contains variables it no longer protects. E.g. in 36/22. *) @@ -592,7 +592,7 @@ struct st (* sound w.r.t. recursive lock *) let unlock ask getg sideg (st: relation_components_t) m: relation_components_t = - let atomic = Param.handle_atomic && LockDomain.Addr.equal m (atomic_mutex) in + let atomic = Param.handle_atomic && LockDomain.MustLock.equal m atomic_mutex in let rel = st.rel in if not atomic then ( let rel_side = keep_only_protected_globals ask m rel in @@ -703,7 +703,7 @@ module type ClusterArg = functor (RD: RelationDomain.RD) -> sig module LRD: Lattice.S - val keep_only_protected_globals: Q.ask -> LockDomain.Addr.t -> LRD.t -> LRD.t + val keep_only_protected_globals: Q.ask -> LockDomain.MustLock.t -> LRD.t -> LRD.t val keep_global: varinfo -> LRD.t -> LRD.t val lock: RD.t -> LRD.t -> LRD.t -> RD.t @@ -962,7 +962,7 @@ struct let get_m_with_mutex_inits inits ask getg m = let get_m = get_relevant_writes ask m (G.mutex @@ getg (V.mutex m)) in - if M.tracing then M.traceli "relationpriv" "get_m_with_mutex_inits %a\n get=%a" LockDomain.Addr.pretty m LRD.pretty get_m; + if M.tracing then M.traceli "relationpriv" "get_m_with_mutex_inits %a\n get=%a" LockDomain.MustLock.pretty m LRD.pretty get_m; let r = if not inits then get_m @@ -975,7 +975,7 @@ struct if M.tracing then M.traceu "relationpriv" "-> %a" LRD.pretty r; r - let atomic_mutex = LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var + let atomic_mutex = LockDomain.MustLock.of_var LibraryFunctions.verifier_atomic_var let get_mutex_global_g_with_mutex_inits inits ask getg g = let get_mutex_global_g = @@ -1088,8 +1088,8 @@ struct {rel = rel_local; priv = (W.add g w,lmust,l)} (* Keep write local as if it were protected by the atomic section. *) let lock ask getg (st: relation_components_t) m = - let atomic = Param.handle_atomic && LockDomain.Addr.equal m (atomic_mutex) in - if not atomic && Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( + let atomic = Param.handle_atomic && LockDomain.MustLock.equal m atomic_mutex in + if not atomic && Locksets.(not (MustLockset.mem m (current_lockset ask))) then ( let rel = st.rel in let _,lmust,l = st.priv in let lm = LLock.mutex m in @@ -1112,7 +1112,7 @@ struct RD.keep_filter oct protected let unlock ask getg sideg (st: relation_components_t) m: relation_components_t = - let atomic = Param.handle_atomic && LockDomain.Addr.equal m (atomic_mutex) in + let atomic = Param.handle_atomic && LockDomain.MustLock.equal m atomic_mutex in let rel = st.rel in let w,lmust,l = st.priv in if not atomic then ( @@ -1290,7 +1290,7 @@ struct r let lock ask getg st m = - if M.tracing then M.traceli "relationpriv" "lock %a" LockDomain.Addr.pretty m; + if M.tracing then M.traceli "relationpriv" "lock %a" LockDomain.MustLock.pretty m; if M.tracing then M.trace "relationpriv" "st: %a" RelComponents.pretty st; let getg x = let r = getg x in @@ -1302,7 +1302,7 @@ struct r let unlock ask getg sideg st m = - if M.tracing then M.traceli "relationpriv" "unlock %a" LockDomain.Addr.pretty m; + if M.tracing then M.traceli "relationpriv" "unlock %a" LockDomain.MustLock.pretty m; if M.tracing then M.trace "relationpriv" "st: %a" RelComponents.pretty st; let getg x = let r = getg x in diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index f874232176..9dbffe40b1 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -28,8 +28,8 @@ sig * the state when following conditional guards. *) val write_global: ?invariant:bool -> Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> varinfo -> VD.t -> BaseComponents (D).t - val lock: Q.ask -> (V.t -> G.t) -> BaseComponents (D).t -> LockDomain.Addr.t -> BaseComponents (D).t - val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> LockDomain.Addr.t -> BaseComponents (D).t + val lock: Q.ask -> (V.t -> G.t) -> BaseComponents (D).t -> LockDomain.MustLock.t -> BaseComponents (D).t + val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> LockDomain.MustLock.t -> BaseComponents (D).t val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> [`Normal | `Join | `Return | `Init | `Thread] -> BaseComponents (D).t @@ -191,7 +191,7 @@ struct let get_mutex_inits = getg V.mutex_inits in let is_in_Gm x _ = is_protected_by ask m x in let get_mutex_inits' = CPA.filter is_in_Gm get_mutex_inits in - if M.tracing then M.tracel "priv" "get_m_with_mutex_inits %a:\n get_m: %a\n get_mutex_inits: %a\n get_mutex_inits': %a" LockDomain.Addr.pretty m CPA.pretty get_m CPA.pretty get_mutex_inits CPA.pretty get_mutex_inits'; + if M.tracing then M.tracel "priv" "get_m_with_mutex_inits %a:\n get_m: %a\n get_mutex_inits: %a\n get_mutex_inits': %a" LockDomain.MustLock.pretty m CPA.pretty get_m CPA.pretty get_mutex_inits CPA.pretty get_mutex_inits'; CPA.join get_m get_mutex_inits' (** [get_m_with_mutex_inits] optimized for implementation-specialized [read_global]. *) @@ -281,7 +281,7 @@ struct cpa' *) let lock ask getg (st: BaseComponents (D).t) m = - if Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( + if Locksets.(not (MustLockset.mem m (current_lockset ask))) then ( let get_m = get_m_with_mutex_inits ask getg m in (* Really we want is_unprotected, but pthread_cond_wait emits unlock-lock events, where our (necessary) original context still has the mutex, @@ -292,7 +292,7 @@ struct No other privatization uses is_unprotected, so this hack is only needed here. *) let is_in_V x _ = is_protected_by ask m x && is_unprotected_without ask x m in let cpa' = CPA.filter is_in_V get_m in - if M.tracing then M.tracel "priv" "PerMutexOplusPriv.lock m=%a cpa'=%a" LockDomain.Addr.pretty m CPA.pretty cpa'; + if M.tracing then M.tracel "priv" "PerMutexOplusPriv.lock m=%a cpa'=%a" LockDomain.MustLock.pretty m CPA.pretty cpa'; {st with cpa = CPA.fold CPA.add cpa' st.cpa} ) else @@ -301,7 +301,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let is_in_Gm x _ = is_protected_by ask m x in let side_m_cpa = CPA.filter is_in_Gm st.cpa in - if M.tracing then M.tracel "priv" "PerMutexOplusPriv.unlock m=%a side_m_cpa=%a" LockDomain.Addr.pretty m CPA.pretty side_m_cpa; + if M.tracing then M.tracel "priv" "PerMutexOplusPriv.unlock m=%a side_m_cpa=%a" LockDomain.MustLock.pretty m CPA.pretty side_m_cpa; sideg (V.mutex m) side_m_cpa; st @@ -377,14 +377,14 @@ struct cpa' *) let lock (ask: Queries.ask) getg (st: BaseComponents (D).t) m = - if Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( + if Locksets.(not (MustLockset.mem m (current_lockset ask))) then ( let get_m = get_m_with_mutex_inits ask getg m in (* Additionally filter get_m in case it contains variables it no longer protects. *) let is_in_Gm x _ = is_protected_by ask m x in let get_m = CPA.filter is_in_Gm get_m in let long_meet m1 m2 = CPA.long_map2 VD.meet m1 m2 in let meet = long_meet st.cpa get_m in - if M.tracing then M.tracel "priv" "LOCK %a:\n get_m: %a\n meet: %a" LockDomain.Addr.pretty m CPA.pretty get_m CPA.pretty meet; + if M.tracing then M.tracel "priv" "LOCK %a:\n get_m: %a\n meet: %a" LockDomain.MustLock.pretty m CPA.pretty get_m CPA.pretty meet; {st with cpa = meet} ) else @@ -523,7 +523,7 @@ struct {st with cpa = cpa'; priv = (W.add x w,LMust.add lm lmust,l')} let lock (ask: Queries.ask) getg (st: BaseComponents (D).t) m = - if Locksets.(not (MustLockset.mem_addr m (current_lockset ask))) then ( + if Locksets.(not (MustLockset.mem m (current_lockset ask))) then ( let _,lmust,l = st.priv in let lm = LLock.mutex m in let get_m = get_m_with_mutex_inits (not (LMust.mem lm lmust)) ask getg m in @@ -750,7 +750,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let sideg = Wrapper.sideg ask sideg in - let atomic = Param.handle_atomic && LockDomain.Addr.equal m (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in + let atomic = Param.handle_atomic && LockDomain.MustLock.equal m (LockDomain.MustLock.of_var LibraryFunctions.verifier_atomic_var) in (* TODO: what about G_m globals in cpa that weren't actually written? *) CPA.fold (fun x v (st: BaseComponents (D).t) -> if is_protected_by ask m x then ( (* is_in_Gm *) @@ -1016,13 +1016,13 @@ struct {st with cpa = cpa'} let unlock ask getg sideg (st: BaseComponents (D).t) m = - let s = MustLockset.remove_addr m (current_lockset ask) in + let s = MustLockset.remove m (current_lockset ask) in let t = current_thread ask in let side_cpa = CPA.filter (fun x _ -> GWeak.fold (fun s' tm acc -> (* TODO: swap 2^M and T partitioning for lookup by t here first? *) let v = ThreadMap.find t tm in - (MustLockset.mem_addr m s' && not (VD.is_bot v)) || acc + (MustLockset.mem m s' && not (VD.is_bot v)) || acc ) (G.weak (getg (V.global x))) false ) st.cpa in @@ -1074,10 +1074,10 @@ struct {st with cpa = cpa'} let unlock ask getg sideg (st: BaseComponents (D).t) m = - let s = MustLockset.remove_addr m (current_lockset ask) in + let s = MustLockset.remove m (current_lockset ask) in let side_cpa = CPA.filter (fun x _ -> GWeak.fold (fun s' v acc -> - (MustLockset.mem_addr m s' && not (VD.is_bot v)) || acc + (MustLockset.mem m s' && not (VD.is_bot v)) || acc ) (G.weak (getg (V.global x))) false ) st.cpa in @@ -1149,7 +1149,7 @@ struct {st with cpa = cpa'} let unlock ask getg sideg (st: BaseComponents (D).t) m = - let s = MustLockset.remove_addr m (current_lockset ask) in + let s = MustLockset.remove m (current_lockset ask) in let is_in_W x _ = W.mem x st.priv in let side_cpa = CPA.filter is_in_W st.cpa in sideg (V.mutex m) (G.create_sync (GSync.singleton s side_cpa)); @@ -1192,13 +1192,13 @@ struct module DV = struct - include MapDomain.MapBot_LiftTop (Lock) (MustVars) + include MapDomain.MapBot_LiftTop (LockDomain.MustLock) (MustVars) let name () = "V" end module L = struct - include MapDomain.MapBot_LiftTop (Lock) (MinLocksets) + include MapDomain.MapBot_LiftTop (LockDomain.MustLock) (MinLocksets) let name () = "L" end end @@ -1301,7 +1301,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let sideg = Wrapper.sideg ask sideg in let getg = Wrapper.getg ask getg in - let s = MustLockset.remove_addr m (current_lockset ask) in + let s = MustLockset.remove m (current_lockset ask) in let is_in_G x _ = is_global ask x in let side_cpa = CPA.filter is_in_G st.cpa in let side_cpa = CPA.mapi (fun x v -> @@ -1471,10 +1471,10 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let getg = Wrapper.getg ask getg in let sideg = Wrapper.sideg ask sideg in - let s = MustLockset.remove_addr m (current_lockset ask) in + let s = MustLockset.remove m (current_lockset ask) in let (w, p) = st.priv in let p' = P.map (fun s' -> MinLocksets.add s s') p in - if M.tracing then M.traceli "priv" "unlock %a %a" Lock.pretty m CPA.pretty st.cpa; + if M.tracing then M.traceli "priv" "unlock %a %a" LockDomain.MustLock.pretty m CPA.pretty st.cpa; let side_gsyncw = CPA.fold (fun x v acc -> if is_global ask x then ( let w_x = W.find x w in @@ -1487,7 +1487,7 @@ struct acc ) st.cpa (GSyncW.bot ()) in - if M.tracing then M.traceu "priv" "unlock %a %a" Lock.pretty m GSyncW.pretty side_gsyncw; + if M.tracing then M.traceu "priv" "unlock %a %a" LockDomain.MustLock.pretty m GSyncW.pretty side_gsyncw; sideg (V.mutex m) (UnwrappedG.create_sync (GSync.singleton s side_gsyncw)); {st with priv = (w, p')} @@ -1656,7 +1656,7 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let getg = Wrapper.getg ask getg in let sideg = Wrapper.sideg ask sideg in - let s = MustLockset.remove_addr m (current_lockset ask) in + let s = MustLockset.remove m (current_lockset ask) in let ((w, p), vl) = st.priv in let p' = P.map (fun s' -> MinLocksets.add s s') p in let side_gsyncw = CPA.fold (fun x v acc -> @@ -1809,7 +1809,7 @@ struct r let lock ask getg st m = - if M.tracing then M.traceli "priv" "lock %a" LockDomain.Addr.pretty m; + if M.tracing then M.traceli "priv" "lock %a" LockDomain.MustLock.pretty m; if M.tracing then M.trace "priv" "st: %a" BaseComponents.pretty st; let getg x = let r = getg x in @@ -1821,7 +1821,7 @@ struct r let unlock ask getg sideg st m = - if M.tracing then M.traceli "priv" "unlock %a" LockDomain.Addr.pretty m; + if M.tracing then M.traceli "priv" "unlock %a" LockDomain.MustLock.pretty m; if M.tracing then M.trace "priv" "st: %a" BaseComponents.pretty st; let getg x = let r = getg x in diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index e176a450fa..03a40405c0 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -17,8 +17,8 @@ sig val read_global: Queries.ask -> (V.t -> G.t) -> BaseDomain.BaseComponents (D).t -> varinfo -> BaseDomain.VD.t val write_global: ?invariant:bool -> Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> varinfo -> BaseDomain.VD.t -> BaseDomain.BaseComponents (D).t - val lock: Queries.ask -> (V.t -> G.t) -> BaseDomain.BaseComponents (D).t -> LockDomain.Addr.t -> BaseDomain.BaseComponents (D).t - val unlock: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> LockDomain.Addr.t -> BaseDomain.BaseComponents (D).t + val lock: Queries.ask -> (V.t -> G.t) -> BaseDomain.BaseComponents (D).t -> LockDomain.MustLock.t -> BaseDomain.BaseComponents (D).t + val unlock: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> LockDomain.MustLock.t -> BaseDomain.BaseComponents (D).t val sync: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> [`Normal | `Join | `Return | `Init | `Thread] -> BaseDomain.BaseComponents (D).t diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index fe0611236c..5de56a8e59 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -74,12 +74,12 @@ struct let is_unprotected_without ask ?(write=true) ?(protection=Strong) x m: bool = (if protection = Weak then ThreadFlag.is_currently_multi ask else ThreadFlag.has_ever_been_multi ask) && - ask.f (Q.MayBePublicWithout {global=x; write; without_mutex=m; protection}) + ask.f (Q.MayBePublicWithout {global=x; write; without_mutex=Addr (LockDomain.MustLock.to_mval m); protection}) (* TODO: no mutex conversion? *) let is_protected_by ask ?(protection=Strong) m x: bool = is_global ask x && not (VD.is_immediate_type x.vtype) && - ask.f (Q.MustBeProtectedBy {mutex=m; global=x; write=true; protection}) + ask.f (Q.MustBeProtectedBy {mutex=Addr (LockDomain.MustLock.to_mval m); global=x; write=true; protection}) (* TODO: no mutex conversion? *) let protected_vars (ask: Q.ask): varinfo list = LockDomain.MustLockset.fold (fun ml acc -> @@ -92,7 +92,7 @@ module MutexGlobals = struct module VMutex = struct - include LockDomain.Addr + include LockDomain.MustLock let name () = "mutex" end module VMutexInits = Printable.UnitConf (struct let name = "MUTEX_INITS" end) @@ -106,7 +106,7 @@ struct include Printable.Either3Conf (struct include Printable.DefaultConf let expand2 = false end) (VMutex) (VMutexInits) (VGlobal) let name () = "MutexGlobals" let mutex x: t = `Left x - let mutex_mustlock x = mutex (Addr (LockDomain.MustLock.to_mval x)) + let mutex_mustlock x = mutex x (* TODO: remove *) let mutex_inits: t = `Middle () let global x: t = `Right x end @@ -250,7 +250,7 @@ struct module LLock = struct - include Printable.Either (Locksets.Lock) (struct include CilType.Varinfo let name () = "global" end) + include Printable.Either (LockDomain.MustLock) (struct include CilType.Varinfo let name () = "global" end) let mutex m = `Left m let global x = `Right x end @@ -313,7 +313,7 @@ let lift_lock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = match addr with | UnknownPtr -> st | Addr (v, _) when ask.f (IsMultiple v) -> st - | Addr mv when LockDomain.Mval.is_definite mv -> f st addr + | Addr mv when LockDomain.Mval.is_definite mv -> f st (LockDomain.MustLock.of_mval mv) | Addr _ | NullPtr | StrPtr _ -> st @@ -328,16 +328,16 @@ let lift_unlock (ask: Q.ask) f st (addr: LockDomain.Addr.t) = | UnknownPtr -> LockDomain.MustLockset.fold (fun ml st -> (* call privatization's unlock only with definite lock *) - f st (LockDomain.Addr.Addr (LockDomain.MustLock.to_mval ml)) (* TODO: no conversion *) + f st ml ) (ask.f MustLockset) st | StrPtr _ | NullPtr -> st - | Addr mv when LockDomain.Mval.is_definite mv -> f st addr + | Addr mv when LockDomain.Mval.is_definite mv -> f st (LockDomain.MustLock.of_mval mv) | Addr mv -> LockDomain.MustLockset.fold (fun ml st -> if LockDomain.MustLock.semantic_equal_mval ml mv = Some false then st else (* call privatization's unlock only with definite lock *) - f st (Addr (LockDomain.MustLock.to_mval ml)) (* TODO: no conversion *) + f st ml ) (ask.f MustLockset) st diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 1c9fcb98c7..be22ec1aea 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -24,6 +24,8 @@ struct else Some false + let of_var v: t = (v, `NoOffset) + let of_mval ((v, o): Mval.t): t = (v, Offset.Poly.map_indices (fun i -> IndexDomain.to_int i |> Option.get) o) From 500b45236ecd10ccb85b60c87d3eecea40d30821 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 16:38:33 +0300 Subject: [PATCH 307/689] Remove now-unnecessary must lockset functions --- src/analyses/basePriv.ml | 6 +++--- src/analyses/commonPriv.ml | 7 ------- src/cdomains/lockDomain.ml | 16 ---------------- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 9dbffe40b1..6deec0e8ca 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -911,7 +911,7 @@ struct MustLockset.fold (fun m acc -> GSync.fold (fun s' cpa' acc -> SyncRange.fold_sync_vars VS.add cpa' acc - ) (G.sync (getg (V.mutex_mustlock m))) acc + ) (G.sync (getg (V.mutex m))) acc ) s VS.empty |> VS.elements end @@ -1410,7 +1410,7 @@ struct let d_cpa = CPA.find x st.cpa in let d_sync = MustLockset.fold (fun m acc -> if MinLocksets.exists (fun s''' -> not (MustLockset.mem m s''')) p_x then - let syncs = UnwrappedG.sync (getg (V.mutex_mustlock m)) in + let syncs = UnwrappedG.sync (getg (V.mutex m)) in GSync.fold (fun s' gsyncw' acc -> if MustLockset.disjoint s s' then GSyncW.fold (fun w' cpa' acc -> @@ -1600,7 +1600,7 @@ struct let d_m = VD.join d_m_sync d_m_weak in let d_g_sync = MustLockset.fold (fun m acc -> if MinLocksets.exists (fun s''' -> not (MustLockset.mem m s''')) p_x then - let syncs = UnwrappedG.sync (getg (V.mutex_mustlock m)) in + let syncs = UnwrappedG.sync (getg (V.mutex m)) in GSync.fold (fun s' gsyncw' acc -> if MustLockset.disjoint s s' then GSyncW.fold (fun w' cpa' acc -> diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 5de56a8e59..257fe9a038 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -106,7 +106,6 @@ struct include Printable.Either3Conf (struct include Printable.DefaultConf let expand2 = false end) (VMutex) (VMutexInits) (VGlobal) let name () = "MutexGlobals" let mutex x: t = `Left x - let mutex_mustlock x = mutex x (* TODO: remove *) let mutex_inits: t = `Middle () let global x: t = `Right x end @@ -131,12 +130,6 @@ end module Locksets = struct - module Lock = - struct - include LockDomain.Addr - let name () = "lock" - end - module MustLockset = LockDomain.MustLockset let current_lockset (ask: Q.ask): MustLockset.t = diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index be22ec1aea..08353f4795 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -37,22 +37,6 @@ module MustLockset = struct include SetDomain.Reverse (SetDomain.ToppedSet (MustLock) (struct let topname = "All mutexes" end)) - let mem_addr (a: Addr.t) (set: t) = (* TODO: replace with mem_mval *) - match Addr.to_mval a with - | Some mv when Mval.is_definite mv -> - let ml = MustLock.of_mval mv in - mem ml set - | _ -> - false - - let remove_addr (a: Addr.t) (set: t) = (* TODO: replace with remove_mval *) - match Addr.to_mval a with - | Some mv when Mval.is_definite mv -> - let ml = MustLock.of_mval mv in - remove ml set - | _ -> - set - let all (): t = `Top let is_all (set: t) = set = `Top end From 90fc5aa1af4b0b734289917c3f713b5bf326a408 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 16:51:16 +0300 Subject: [PATCH 308/689] Refine MustBeProtectedBy and MayBePublicWithout query mutex type --- src/analyses/commonPriv.ml | 4 ++-- src/analyses/mutexAnalysis.ml | 5 ++--- src/domains/queries.ml | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 257fe9a038..3673991fda 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -74,12 +74,12 @@ struct let is_unprotected_without ask ?(write=true) ?(protection=Strong) x m: bool = (if protection = Weak then ThreadFlag.is_currently_multi ask else ThreadFlag.has_ever_been_multi ask) && - ask.f (Q.MayBePublicWithout {global=x; write; without_mutex=Addr (LockDomain.MustLock.to_mval m); protection}) (* TODO: no mutex conversion? *) + ask.f (Q.MayBePublicWithout {global=x; write; without_mutex=m; protection}) let is_protected_by ask ?(protection=Strong) m x: bool = is_global ask x && not (VD.is_immediate_type x.vtype) && - ask.f (Q.MustBeProtectedBy {mutex=Addr (LockDomain.MustLock.to_mval m); global=x; write=true; protection}) (* TODO: no mutex conversion? *) + ask.f (Q.MustBeProtectedBy {mutex=m; global=x; write=true; protection}) let protected_vars (ask: Q.ask): varinfo list = LockDomain.MustLockset.fold (fun ml acc -> diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index b44795b6da..9b6aa4f4ca 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -209,15 +209,14 @@ struct MustLockset.disjoint held_locks protecting | Queries.MayBePublicWithout _ when MustLocksetRW.is_all ls -> false | Queries.MayBePublicWithout {global=v; write; without_mutex; protection} -> - let held_locks = MustLocksetRW.to_must_lockset @@ fst @@ Arg.remove' ctx ~warn:false without_mutex in + let held_locks = MustLockset.remove without_mutex (MustLocksetRW.to_must_lockset ls) in let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if Mutexes.mem verifier_atomic (Lockset.export_locks (Lockset.remove (without_mutex, true) ctx.local)) then false else *) MustLockset.disjoint held_locks protecting - | Queries.MustBeProtectedBy {mutex = Addr mutex_mv; global=v; write; protection} when Mval.is_definite mutex_mv -> (* only definite Addrs can be in must-locksets to begin with, anything else cannot protect anything *) - let ml = LockDomain.MustLock.of_mval mutex_mv in + | Queries.MustBeProtectedBy {mutex = ml; global=v; write; protection} -> let protecting = protecting ~write protection v in (* TODO: unsound in 29/24, why did we do this before? *) (* if LockDomain.Addr.equal mutex (LockDomain.Addr.of_var LF.verifier_atomic_var) then diff --git a/src/domains/queries.ml b/src/domains/queries.ml index a904f696eb..edb5c44c56 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -49,8 +49,8 @@ end (* Helper definitions for deriving complex parts of Any.compare below. *) type maybepublic = {global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash] -type maybepublicwithout = {global: CilType.Varinfo.t; write: bool; without_mutex: PreValueDomain.Addr.t; protection: Protection.t} [@@deriving ord, hash] -type mustbeprotectedby = {mutex: PreValueDomain.Addr.t; global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash] +type maybepublicwithout = {global: CilType.Varinfo.t; write: bool; without_mutex: LockDomain.MustLock.t; protection: Protection.t} [@@deriving ord, hash] +type mustbeprotectedby = {mutex: LockDomain.MustLock.t; global: CilType.Varinfo.t; write: bool; protection: Protection.t} [@@deriving ord, hash] type mustprotectedvars = {mutex: LockDomain.MustLock.t; write: bool} [@@deriving ord, hash] type access = | Memory of {exp: CilType.Exp.t; var_opt: CilType.Varinfo.t option; kind: AccessKind.t} (** Memory location access (race). *) From 11526a831b47d0e408b4d56a2b0015f3e8c29978 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Tue, 4 Jun 2024 20:23:16 +0200 Subject: [PATCH 309/689] fix: narrow only when interval shrinks --- src/cdomain/value/cdomains/intDomain.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index f482842ca8..b882df732b 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -714,8 +714,8 @@ struct | Some (x1,x2), Some (y1,y2) -> let threshold = get_interval_threshold_widening () in let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && IArith.is_upper_threshold x2 then y2 else x2 in + let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in + let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in norm ik @@ Some (lr,ur) |> fst From d6456c87b6a206bc73116a82d385fbfe48431fff Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Tue, 4 Jun 2024 20:32:37 +0200 Subject: [PATCH 310/689] narrow thresholds for int interval sets --- src/cdomain/value/cdomains/intDomain.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index b882df732b..7f91c9d036 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -1393,8 +1393,9 @@ struct let min_ys = minimal ys |> Option.get in let max_ys = maximal ys |> Option.get in let min_range,max_range = range ik in - let min = if min_xs =. min_range then min_ys else min_xs in - let max = if max_xs =. max_range then max_ys else max_xs in + let threshold = get_interval_threshold_widening () in + let min = if min_xs =. min_range || threshold && min_ys <. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in + let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in xs |> (function (_, y)::z -> (min, y)::z | _ -> []) |> List.rev From 2e42c7bf1c664d07ab5844246338547f4d28f3c8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 12:36:10 +0300 Subject: [PATCH 311/689] Add ghost_variable and ghost_update YAML entry types to option --- conf/svcomp-ghost.json | 4 +++- src/analyses/mutexGhosts.ml | 3 +++ src/config/options.schema.json | 4 +++- src/witness/witnessGhost.ml | 3 +++ tests/regression/13-privatized/04-priv_multi.t | 4 ++-- tests/regression/13-privatized/25-struct_nr.t | 2 +- tests/regression/13-privatized/74-mutex.t | 6 +++--- tests/regression/13-privatized/92-idx_priv.t | 2 +- tests/regression/29-svcomp/16-atomic_priv.t | 4 ++-- tests/regression/36-apron/12-traces-min-rpb1.t | 2 +- tests/regression/56-witness/64-ghost-multiple-protecting.t | 6 +++--- tests/regression/56-witness/65-ghost-ambiguous-lock.t | 2 +- tests/regression/56-witness/66-ghost-alloc-lock.t | 2 +- tests/regression/56-witness/67-ghost-no-unlock.t | 2 +- tests/regression/56-witness/68-ghost-ambiguous-idx.t | 2 +- 15 files changed, 29 insertions(+), 19 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 229dd9ef46..84f127eb91 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -116,7 +116,9 @@ "enabled": true, "format-version": "0.1", "entry-types": [ - "flow_insensitive_invariant" + "flow_insensitive_invariant", + "ghost_variable", + "ghost_update" ] }, "invariant": { diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 159498cfb1..6e95504731 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -96,6 +96,9 @@ struct | Locked _ -> false | Multithreaded -> true + let ghost_var_available ctx v = + WitnessGhost.enabled () && ghost_var_available ctx v + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | GhostVarAvailable v -> ghost_var_available ctx v diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 4a77aae5f0..779b9bbf65 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2580,7 +2580,9 @@ "precondition_loop_invariant", "loop_invariant_certificate", "precondition_loop_invariant_certificate", - "invariant_set" + "invariant_set", + "ghost_variable", + "ghost_update" ] }, "default": [ diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index cdd26b36aa..91d513ceae 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,5 +1,8 @@ (** Ghost variables for YAML witnesses. *) +let enabled () = + YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type + module Var = WitnessGhostVar include Var diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index 952696a5c4..576c89ad4d 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -174,7 +174,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t index f3ebcd1c52..342cfaf99c 100644 --- a/tests/regression/13-privatized/25-struct_nr.t +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 25-struct_nr.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index a00f49eb1a..f6f2fa8463 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -84,7 +84,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -150,7 +150,7 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index 64a3309009..bd6db7e2ef 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 92-idx_priv.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c [Success][Assert] Assertion "data == 0" will succeed (92-idx_priv.c:22:3-22:29) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index b10265d4e8..83bc201a6c 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -43,7 +43,7 @@ Non-atomic privatization: - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 7aca1dea0b..1c3253afbc 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,4 +1,4 @@ - $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 53323355c5..943934a7be 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -144,7 +144,7 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -295,7 +295,7 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index 708e27ca64..d7d57d8a00 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 65-ghost-ambiguous-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 23 dead: 0 diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index e4d128b71e..e4268ec1cb 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 66-ghost-alloc-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) [Info][Deadcode] Logical lines of code (LLoC) summary: diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t index 491dd9cf44..aed0ac3414 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.t +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 67-ghost-no-unlock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 48837fcabb..9f50ab7429 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 68-ghost-ambiguous-idx.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) [Info][Deadcode] Logical lines of code (LLoC) summary: From e7931ffe4afc2be4872b15d94a4ab3aa4ed66453 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 12:53:02 +0300 Subject: [PATCH 312/689] Make InvariantGlobalNodes query lazy in YAML witness generation --- src/witness/yamlWitness.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index b7bf11a31c..fd8f4b5249 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -325,7 +325,7 @@ struct (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( - let ns = R.ask_global InvariantGlobalNodes in + let ns = lazy (R.ask_global InvariantGlobalNodes) in GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) @@ -352,7 +352,7 @@ struct entry :: acc ) acc invs | None -> acc - ) ns acc + ) (Lazy.force ns) acc | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end From 36ff6217074eb8c25a2528979ebc634d3cba789e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 13:46:04 +0300 Subject: [PATCH 313/689] Fix comment about YamlEntryGlobal --- src/witness/yamlWitness.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index fd8f4b5249..596a35f631 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -364,7 +364,7 @@ struct entries in - (* Generate flow-insensitive invariants *) + (* Generate flow-insensitive entries (ghost variables and ghost updates) *) let entries = if true then ( GHT.fold (fun g v acc -> From 1e37e0b3a20c976ec89de5cd49618a3c70e5e58b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 14:10:38 +0300 Subject: [PATCH 314/689] Use GobOption.exists instead of Option.is_some && Option.get --- src/cdomain/value/cdomains/valueDomain.ml | 15 ++++++++------- src/solver/generic.ml | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/cdomain/value/cdomains/valueDomain.ml b/src/cdomain/value/cdomains/valueDomain.ml index de64fde807..be089f0ca5 100644 --- a/src/cdomain/value/cdomains/valueDomain.ml +++ b/src/cdomain/value/cdomains/valueDomain.ml @@ -978,8 +978,9 @@ struct let blob_size_opt = ID.to_int s in not @@ ask.is_multiple var && not @@ Cil.isVoidType t (* Size of value is known *) - && Option.is_some blob_size_opt (* Size of blob is known *) - && Z.equal (Option.get blob_size_opt) (Z.of_int @@ Cil.bitsSizeOf (TComp (toptype, []))/8) + && GobOption.exists (fun blob_size -> (* Size of blob is known *) + Z.equal blob_size (Z.of_int @@ Cil.bitsSizeOf (TComp (toptype, []))/8) + ) blob_size_opt | _ -> false in if do_strong_update then @@ -997,11 +998,11 @@ struct | (Var var, _) -> let blob_size_opt = ID.to_int s in not @@ ask.is_multiple var - && Option.is_some blob_size_opt (* Size of blob is known *) - && (( - not @@ Cil.isVoidType t (* Size of value is known *) - && Z.equal (Option.get blob_size_opt) (Z.of_int @@ Cil.alignOf_int t) - ) || blob_destructive) + && GobOption.exists (fun blob_size -> (* Size of blob is known *) + (not @@ Cil.isVoidType t (* Size of value is known *) + && Z.equal blob_size (Z.of_int @@ Cil.alignOf_int t)) + || blob_destructive + ) blob_size_opt | _ -> false end in diff --git a/src/solver/generic.ml b/src/solver/generic.ml index 1f0df57843..737aba6762 100644 --- a/src/solver/generic.ml +++ b/src/solver/generic.ml @@ -44,7 +44,7 @@ struct let histo = HM.create 1024 let increase (v:Var.t) = let set v c = - if not full_trace && (c > start_c && c > !max_c && (Option.is_none !max_var || not (Var.equal (Option.get !max_var) v))) then begin + if not full_trace && (c > start_c && c > !max_c && not (GobOption.exists (Var.equal v) !max_var)) then begin if tracing then trace "sol" "Switched tracing to %a" Var.pretty_trace v; max_c := c; max_var := Some v @@ -75,7 +75,7 @@ struct let update_var_event x o n = if tracing then increase x; - if full_trace || ((not (Dom.is_bot o)) && Option.is_some !max_var && Var.equal (Option.get !max_var) x) then begin + if full_trace || (not (Dom.is_bot o) && GobOption.exists (Var.equal x) !max_var) then begin if tracing then tracei "sol_max" "(%d) Update to %a" !max_c Var.pretty_trace x; if tracing then traceu "sol_max" "%a" Dom.pretty_diff (n, o) end From 67af68adb8834cf446cd24bdf41325db4de91b18 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 14:11:13 +0300 Subject: [PATCH 315/689] Remove redundant match guard in condVars If is None, then body handles it anyway with Option.map and defaults to d. --- src/analyses/condVars.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/condVars.ml b/src/analyses/condVars.ml index 22b9db1cd4..448e3a79e5 100644 --- a/src/analyses/condVars.ml +++ b/src/analyses/condVars.ml @@ -116,7 +116,7 @@ struct match rval with | BinOp (op, _, _, _) when is_cmp op -> (* logical expression *) save_expr lval rval - | Lval k when Option.is_some (mustPointTo ctx (AddrOf k) >? flip D.get d) -> (* var-eq for transitive closure *) + | Lval k -> (* var-eq for transitive closure *) mustPointTo ctx (AddrOf k) >? flip D.get_elt d |> Option.map (save_expr lval) |? d | _ -> d From 3f8f8bf129dd26fc005422a3f43a07c5dfcc2b4b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 14:12:03 +0300 Subject: [PATCH 316/689] Avoid intermediate lists in AddressSet.string_writing_defined Just check existance on set directly. --- src/cdomain/value/cdomains/addressDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/addressDomain.ml b/src/cdomain/value/cdomains/addressDomain.ml index dc1ebfff7d..da684cc4f4 100644 --- a/src/cdomain/value/cdomains/addressDomain.ml +++ b/src/cdomain/value/cdomains/addressDomain.ml @@ -320,7 +320,7 @@ struct let string_writing_defined dest = (* if the destination address set contains a StrPtr, writing to such a string literal is undefined behavior *) - if List.exists Option.is_some (List.map Addr.to_c_string (elements dest)) then + if exists (fun a -> Option.is_some (Addr.to_c_string a)) dest then (M.warn ~category:M.Category.Behavior.Undefined.other "May write to a string literal, which leads to a segmentation fault in most cases"; false) else From ad73869770c75b3aa7ed144c605079d86026ee36 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Wed, 5 Jun 2024 13:51:10 +0200 Subject: [PATCH 317/689] integrate comments --- src/cdomain/value/cdomains/intDomain.ml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 7f91c9d036..a67740e9db 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -575,13 +575,11 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct let is_upper_threshold u = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in let u = Ints_t.to_bigint u in - let t = List.find_opt (fun x -> Z.compare u x = 0) ts in - Option.is_some t + List.exists (fun x -> Z.compare u x = 0) ts let is_lower_threshold l = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in let l = Ints_t.to_bigint l in - let t = List.find_opt (fun x -> Z.compare l x = 0) ts in - Option.is_some t + List.exists (fun x -> Z.compare l x = 0) ts end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = @@ -1394,7 +1392,7 @@ struct let max_ys = maximal ys |> Option.get in let min_range,max_range = range ik in let threshold = get_interval_threshold_widening () in - let min = if min_xs =. min_range || threshold && min_ys <. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in + let min = if min_xs =. min_range || threshold && min_ys >. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in xs |> (function (_, y)::z -> (min, y)::z | _ -> []) From 94a31d4ef61f6e4227c0329f96342ae1f471eeb5 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Wed, 5 Jun 2024 14:53:00 +0200 Subject: [PATCH 318/689] test interval-set narrowing and lower bounds --- ...rrowing.c => 33-threshold-narrowing-intervals.c} | 5 +++++ .../34-threshold-narrowing-interval-sets.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) rename tests/regression/03-practical/{33-threshold-narrowing.c => 33-threshold-narrowing-intervals.c} (74%) create mode 100644 tests/regression/03-practical/34-threshold-narrowing-interval-sets.c diff --git a/tests/regression/03-practical/33-threshold-narrowing.c b/tests/regression/03-practical/33-threshold-narrowing-intervals.c similarity index 74% rename from tests/regression/03-practical/33-threshold-narrowing.c rename to tests/regression/03-practical/33-threshold-narrowing-intervals.c index 0c713fa273..ef38c151da 100644 --- a/tests/regression/03-practical/33-threshold-narrowing.c +++ b/tests/regression/03-practical/33-threshold-narrowing-intervals.c @@ -5,4 +5,9 @@ int main() { int i; for(i = 0; i < 10 && i < 20; i += 3); __goblint_check(i <= 12); + + int j; + for(j = 0; j > -10 && j > -20; j-= 3); + __goblint_check(j >= -12); + } diff --git a/tests/regression/03-practical/34-threshold-narrowing-interval-sets.c b/tests/regression/03-practical/34-threshold-narrowing-interval-sets.c new file mode 100644 index 0000000000..c1f11c091e --- /dev/null +++ b/tests/regression/03-practical/34-threshold-narrowing-interval-sets.c @@ -0,0 +1,13 @@ +// PARAM: --enable ana.int.interval_set --enable ana.int.interval_threshold_widening --set ana.int.interval_threshold_widening_constants comparisons +#include + +int main() { + int i; + for(i = 0; i < 10 && i < 20; i += 3); + __goblint_check(i <= 12); + + int j; + for(j = 0; j > -10 && j > -20; j-= 3); + __goblint_check(j >= -12); + +} From 8aa9c4f4f0be045e0ba0363dd12bc72790907a27 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Wed, 5 Jun 2024 14:54:16 +0200 Subject: [PATCH 319/689] add unit test for interval(-set) narrowing --- tests/unit/cdomains/intDomainTest.ml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/unit/cdomains/intDomainTest.ml b/tests/unit/cdomains/intDomainTest.ml index e697b022eb..a60b7a6cb1 100644 --- a/tests/unit/cdomains/intDomainTest.ml +++ b/tests/unit/cdomains/intDomainTest.ml @@ -205,6 +205,7 @@ struct let i65536 = I.of_interval ik (Z.zero, of_int 65536) let i65537 = I.of_interval ik (Z.zero, of_int 65537) let imax = I.of_interval ik (Z.zero, of_int 2147483647) + let imin = I.of_interval ik (of_int (-2147483648), Z.zero) let assert_equal x y = assert_equal ~cmp:I.equal ~printer:I.show x y @@ -218,9 +219,34 @@ struct assert_equal imax (I.widen ik i65536 i65537); assert_equal imax (I.widen ik i65536 imax) + let test_interval_narrow _ = + GobConfig.set_bool "ana.int.interval_threshold_widening" true; + GobConfig.set_string "ana.int.interval_threshold_widening_constants" "comparisons"; + let i_zero_one = I.of_interval ik (Z.zero, Z.one) in + let i_zero_five = I.of_interval ik (Z.zero, of_int 5) in + let to_widen = I.of_interval ik (Z.zero, Z.zero) in + (* this should widen to [0, x], where x is the next largest threshold above 5 or the maximal int*) + let widened = I.widen ik to_widen i_zero_five in + (* either way, narrowing from [0, x] to [0, 1] should be possible *) + let narrowed = I.narrow ik widened i_zero_one in + (* however, narrowing should not allow [0, x] to grow *) + let narrowed2 = I.narrow ik widened imax in + assert_equal i_zero_one narrowed; + assert_equal widened narrowed2; + + (* the same tests, but for lower bounds *) + let i_minus_one_zero = I.of_interval ik (Z.minus_one, Z.zero) in + let i_minus_five_zero = I.of_interval ik (of_int (-5), Z.zero) in + let widened = I.widen ik to_widen i_minus_five_zero in + let narrowed = I.narrow ik widened i_minus_one_zero in + let narrowed2 = I.narrow ik widened imin in + assert_equal i_minus_one_zero narrowed; + assert_equal widened narrowed2 + let test () = [ "test_interval_rem" >:: test_interval_rem; "test_interval_widen" >:: test_interval_widen; + "test_interval_narrow" >:: test_interval_narrow; ] end From a384886cd8424cbdada153072647a68c703c789b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 5 Jun 2024 18:58:45 +0300 Subject: [PATCH 320/689] Make `to_float` return float instead float option --- src/cdomain/value/cdomains/floatDomain.ml | 4 ++-- src/common/cdomains/floatOps/floatOps.ml | 6 ++--- src/common/cdomains/floatOps/floatOps.mli | 2 +- tests/unit/cdomains/floatDomainTest.ml | 28 +++++++++++------------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cdomain/value/cdomains/floatDomain.ml b/src/cdomain/value/cdomains/floatDomain.ml index c86770826c..0977c68890 100644 --- a/src/cdomain/value/cdomains/floatDomain.ml +++ b/src/cdomain/value/cdomains/floatDomain.ml @@ -241,12 +241,12 @@ module FloatIntervalImpl(Float_t : CFloatType) = struct let minimal = function | Bot -> raise (ArithmeticOnFloatBot (Printf.sprintf "minimal %s" (show Bot))) - | Interval (l, _) -> Float_t.to_float l + | Interval (l, _) -> Some (Float_t.to_float l) | _ -> None let maximal = function | Bot -> raise (ArithmeticOnFloatBot (Printf.sprintf "maximal %s" (show Bot))) - | Interval (_, h) -> Float_t.to_float h + | Interval (_, h) -> Some (Float_t.to_float h) | _ -> None let is_exact = function diff --git a/src/common/cdomains/floatOps/floatOps.ml b/src/common/cdomains/floatOps/floatOps.ml index 80946b1749..eced6af248 100644 --- a/src/common/cdomains/floatOps/floatOps.ml +++ b/src/common/cdomains/floatOps/floatOps.ml @@ -16,7 +16,7 @@ module type CFloatType = sig val pi : t val of_float: round_mode -> float -> t - val to_float: t -> float option + val to_float: t -> float val to_big_int: t -> Z.t val is_finite: t -> bool @@ -68,7 +68,7 @@ module CDouble = struct let pi = Float.pi let of_float _ x = x - let to_float x = Some x + let to_float x = x let to_big_int = big_int_of_float let is_finite = Float.is_finite @@ -112,7 +112,7 @@ module CFloat = struct let smallest = smallest' () let pi = pi' () - let to_float x = Some x + let to_float x = x let to_big_int = big_int_of_float let is_finite x = Float.is_finite x && x >= lower_bound && x <= upper_bound diff --git a/src/common/cdomains/floatOps/floatOps.mli b/src/common/cdomains/floatOps/floatOps.mli index 7cd74f7e7d..a07582f442 100644 --- a/src/common/cdomains/floatOps/floatOps.mli +++ b/src/common/cdomains/floatOps/floatOps.mli @@ -17,7 +17,7 @@ module type CFloatType = sig val pi : t val of_float: round_mode -> float -> t - val to_float: t -> float option + val to_float: t -> float val to_big_int: t -> Z.t val is_finite: t -> bool diff --git a/tests/unit/cdomains/floatDomainTest.ml b/tests/unit/cdomains/floatDomainTest.ml index 5f3cd4db47..c6cb18500a 100644 --- a/tests/unit/cdomains/floatDomainTest.ml +++ b/tests/unit/cdomains/floatDomainTest.ml @@ -14,12 +14,12 @@ struct let mul = Float_t.mul let div = Float_t.div - let pred x = Option.get (to_float (Float_t.pred (of_float Nearest x))) - let succ x = Option.get (to_float (Float_t.succ (of_float Nearest x))) + let pred x = to_float (Float_t.pred (of_float Nearest x)) + let succ x = to_float (Float_t.succ (of_float Nearest x)) - let fmax = Option.get (to_float Float_t.upper_bound) - let fmin = Option.get (to_float Float_t.lower_bound) - let fsmall = Option.get (to_float Float_t.smallest) + let fmax = to_float Float_t.upper_bound + let fmin = to_float Float_t.lower_bound + let fsmall = to_float Float_t.smallest let fi_zero = FI.of_const 0. let fi_one = FI.of_const 1. @@ -53,7 +53,7 @@ struct FI.top () + FI.top () = FI.top (); (FI.of_const fmin) + (FI.of_const fmax) = fi_zero; (FI.of_const fsmall) + (FI.of_const fsmall) = FI.of_const (fsmall +. fsmall); - let one_plus_fsmall = Option.get (to_float (Float_t.add Up (Float_t.of_float Up 1.) Float_t.smallest)) in + let one_plus_fsmall = to_float (Float_t.add Up (Float_t.of_float Up 1.) Float_t.smallest) in (FI.of_const fsmall) + (FI.of_const 1.) = FI.of_interval (1., one_plus_fsmall); (FI.of_interval (1., 2.)) + (FI.of_interval (2., 3.)) = FI.of_interval (3., 5.); (FI.of_interval (-. 2., 3.)) + (FI.of_interval (-. 100., 20.)) = FI.of_interval (-. 102., 23.); @@ -286,27 +286,27 @@ struct let test_FI_add = QCheck.Test.make ~name:"test_FI_add" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.add (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (Option.get (to_float (add Up (of_float Nearest arg1) (of_float Nearest arg2))))) result) && - (FI.leq (FI.of_const (Option.get (to_float (add Down (of_float Nearest arg1) (of_float Nearest arg2))))) result)) + (FI.leq (FI.of_const (to_float (add Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (add Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) let test_FI_sub = QCheck.Test.make ~name:"test_FI_sub" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.sub (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (Option.get (to_float (sub Up (of_float Nearest arg1) (of_float Nearest arg2))))) result) && - (FI.leq (FI.of_const (Option.get (to_float (sub Down (of_float Nearest arg1) (of_float Nearest arg2))))) result)) + (FI.leq (FI.of_const (to_float (sub Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (sub Down (of_float Nearest arg1) (of_float Nearest arg2))))) result) let test_FI_mul = QCheck.Test.make ~name:"test_FI_mul" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.mul (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (Option.get (to_float (mul Up (of_float Nearest arg1) (of_float Nearest arg2))))) result) && - (FI.leq (FI.of_const (Option.get (to_float (mul Down (of_float Nearest arg1) (of_float Nearest arg2))))) result)) + (FI.leq (FI.of_const (to_float (mul Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (mul Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) let test_FI_div = QCheck.Test.make ~name:"test_FI_div" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.div (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (Option.get (to_float (div Up (of_float Nearest arg1) (of_float Nearest arg2))))) result) && - (FI.leq (FI.of_const (Option.get (to_float (div Down (of_float Nearest arg1) (of_float Nearest arg2))))) result)) + (FI.leq (FI.of_const (to_float (div Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (div Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) let test () = [ From 1cbf7aca72bfbc8073a223f13723080b0d3c67ac Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 5 Jun 2024 19:13:38 +0300 Subject: [PATCH 321/689] Define CFloatType t = float --- src/common/cdomains/floatOps/floatOps.ml | 4 ++-- src/common/cdomains/floatOps/floatOps.mli | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/cdomains/floatOps/floatOps.ml b/src/common/cdomains/floatOps/floatOps.ml index eced6af248..002f382aff 100644 --- a/src/common/cdomains/floatOps/floatOps.ml +++ b/src/common/cdomains/floatOps/floatOps.ml @@ -6,7 +6,7 @@ type round_mode = | Down module type CFloatType = sig - type t + type t = float val name: string val zero: t @@ -97,7 +97,7 @@ module CDouble = struct external atof: round_mode -> string -> t = "atof_double" end -module CFloat = struct +module CFloat : CFloatType = struct type t = float [@@deriving eq, ord, hash, to_yojson] let name = "float" diff --git a/src/common/cdomains/floatOps/floatOps.mli b/src/common/cdomains/floatOps/floatOps.mli index a07582f442..f45785a7d5 100644 --- a/src/common/cdomains/floatOps/floatOps.mli +++ b/src/common/cdomains/floatOps/floatOps.mli @@ -7,7 +7,7 @@ type round_mode = | Down module type CFloatType = sig - type t + type t = float val name: string val zero: t From 87f60f3b16b25261b29f3e999cc7d53b90ade7da Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 5 Jun 2024 19:27:10 +0300 Subject: [PATCH 322/689] Remove identity function `to_float` --- src/cdomain/value/cdomains/floatDomain.ml | 4 ++-- src/common/cdomains/floatOps/floatOps.ml | 3 --- src/common/cdomains/floatOps/floatOps.mli | 1 - tests/unit/cdomains/floatDomainTest.ml | 29 +++++++++++------------ 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/cdomain/value/cdomains/floatDomain.ml b/src/cdomain/value/cdomains/floatDomain.ml index 0977c68890..db6e4eccb5 100644 --- a/src/cdomain/value/cdomains/floatDomain.ml +++ b/src/cdomain/value/cdomains/floatDomain.ml @@ -241,12 +241,12 @@ module FloatIntervalImpl(Float_t : CFloatType) = struct let minimal = function | Bot -> raise (ArithmeticOnFloatBot (Printf.sprintf "minimal %s" (show Bot))) - | Interval (l, _) -> Some (Float_t.to_float l) + | Interval (l, _) -> Some l | _ -> None let maximal = function | Bot -> raise (ArithmeticOnFloatBot (Printf.sprintf "maximal %s" (show Bot))) - | Interval (_, h) -> Some (Float_t.to_float h) + | Interval (_, h) -> Some h | _ -> None let is_exact = function diff --git a/src/common/cdomains/floatOps/floatOps.ml b/src/common/cdomains/floatOps/floatOps.ml index 002f382aff..6088fa9447 100644 --- a/src/common/cdomains/floatOps/floatOps.ml +++ b/src/common/cdomains/floatOps/floatOps.ml @@ -16,7 +16,6 @@ module type CFloatType = sig val pi : t val of_float: round_mode -> float -> t - val to_float: t -> float val to_big_int: t -> Z.t val is_finite: t -> bool @@ -68,7 +67,6 @@ module CDouble = struct let pi = Float.pi let of_float _ x = x - let to_float x = x let to_big_int = big_int_of_float let is_finite = Float.is_finite @@ -112,7 +110,6 @@ module CFloat : CFloatType = struct let smallest = smallest' () let pi = pi' () - let to_float x = x let to_big_int = big_int_of_float let is_finite x = Float.is_finite x && x >= lower_bound && x <= upper_bound diff --git a/src/common/cdomains/floatOps/floatOps.mli b/src/common/cdomains/floatOps/floatOps.mli index f45785a7d5..2deb55a764 100644 --- a/src/common/cdomains/floatOps/floatOps.mli +++ b/src/common/cdomains/floatOps/floatOps.mli @@ -17,7 +17,6 @@ module type CFloatType = sig val pi : t val of_float: round_mode -> float -> t - val to_float: t -> float val to_big_int: t -> Z.t val is_finite: t -> bool diff --git a/tests/unit/cdomains/floatDomainTest.ml b/tests/unit/cdomains/floatDomainTest.ml index c6cb18500a..6b49d21a1a 100644 --- a/tests/unit/cdomains/floatDomainTest.ml +++ b/tests/unit/cdomains/floatDomainTest.ml @@ -7,19 +7,18 @@ struct module FI = Domain_t module IT = IntDomain.IntDomTuple - let to_float = Float_t.to_float let of_float = Float_t.of_float let add = Float_t.add let sub = Float_t.sub let mul = Float_t.mul let div = Float_t.div - let pred x = to_float (Float_t.pred (of_float Nearest x)) - let succ x = to_float (Float_t.succ (of_float Nearest x)) + let pred x = Float_t.pred (of_float Nearest x) + let succ x = Float_t.succ (of_float Nearest x) - let fmax = to_float Float_t.upper_bound - let fmin = to_float Float_t.lower_bound - let fsmall = to_float Float_t.smallest + let fmax = Float_t.upper_bound + let fmin = Float_t.lower_bound + let fsmall = Float_t.smallest let fi_zero = FI.of_const 0. let fi_one = FI.of_const 1. @@ -53,7 +52,7 @@ struct FI.top () + FI.top () = FI.top (); (FI.of_const fmin) + (FI.of_const fmax) = fi_zero; (FI.of_const fsmall) + (FI.of_const fsmall) = FI.of_const (fsmall +. fsmall); - let one_plus_fsmall = to_float (Float_t.add Up (Float_t.of_float Up 1.) Float_t.smallest) in + let one_plus_fsmall = Float_t.add Up (Float_t.of_float Up 1.) Float_t.smallest in (FI.of_const fsmall) + (FI.of_const 1.) = FI.of_interval (1., one_plus_fsmall); (FI.of_interval (1., 2.)) + (FI.of_interval (2., 3.)) = FI.of_interval (3., 5.); (FI.of_interval (-. 2., 3.)) + (FI.of_interval (-. 100., 20.)) = FI.of_interval (-. 102., 23.); @@ -286,27 +285,27 @@ struct let test_FI_add = QCheck.Test.make ~name:"test_FI_add" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.add (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (to_float (add Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && - (FI.leq (FI.of_const (to_float (add Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) + (FI.leq (FI.of_const (add Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && + (FI.leq (FI.of_const (add Down (of_float Nearest arg1) (of_float Nearest arg2))) result)) let test_FI_sub = QCheck.Test.make ~name:"test_FI_sub" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.sub (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (to_float (sub Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && - (FI.leq (FI.of_const (to_float (sub Down (of_float Nearest arg1) (of_float Nearest arg2))))) result) + (FI.leq (FI.of_const (sub Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && + (FI.leq (FI.of_const (sub Down (of_float Nearest arg1) (of_float Nearest arg2)))) result) let test_FI_mul = QCheck.Test.make ~name:"test_FI_mul" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.mul (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (to_float (mul Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && - (FI.leq (FI.of_const (to_float (mul Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) + (FI.leq (FI.of_const (mul Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && + (FI.leq (FI.of_const (mul Down (of_float Nearest arg1) (of_float Nearest arg2))) result)) let test_FI_div = QCheck.Test.make ~name:"test_FI_div" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.div (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (to_float (div Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && - (FI.leq (FI.of_const (to_float (div Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) + (FI.leq (FI.of_const (div Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && + (FI.leq (FI.of_const (div Down (of_float Nearest arg1) (of_float Nearest arg2))) result)) let test () = [ From f990f47f0baec95a744e3784ceadcce7f6b0e2cd Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 6 Jun 2024 12:40:44 +0300 Subject: [PATCH 323/689] Replace usages of `Option.get` with `Option.fold` --- src/cdomain/value/cdomains/intDomain.ml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 3bf81b1ba1..f0ba026ccb 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2256,9 +2256,8 @@ struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let x_min = minimal x in - let y_min = minimal y in - if x_min = None || y_min = None || Z.compare (Option.get x_min) Z.zero < 0 || Z.compare (Option.get y_min) Z.zero < 0 then + let is_negative = Stdlib.Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in + if is_negative (minimal x) || is_negative (minimal y) then top_of ik else norm ik @@ lift2 shift_op_big_int ik x y @@ -2616,9 +2615,8 @@ module Enums : S with type int_t = Z.t = struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let x_min = minimal x in - let y_min = minimal y in - if x_min = None || y_min = None || Z.compare (Option.get x_min) Z.zero < 0 || Z.compare (Option.get y_min) Z.zero < 0 then + let is_negative = Stdlib.Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in + if is_negative (minimal x) || is_negative (minimal y) then top_of ik else lift2 shift_op_big_int ik x y) From d61ec3e2ee08e8595828abad3964fb95f176b855 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 6 Jun 2024 12:45:19 +0300 Subject: [PATCH 324/689] Remove `open Batteries` --- src/cdomain/value/cdomains/intDomain.ml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index f0ba026ccb..69125a0d7a 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2256,7 +2256,7 @@ struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = Stdlib.Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in + let is_negative = Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in if is_negative (minimal x) || is_negative (minimal y) then top_of ik else @@ -2403,7 +2403,6 @@ module Booleans = MakeBooleans ( (* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) module Enums : S with type int_t = Z.t = struct - open Batteries module R = Interval32 (* range for exclusion *) let range_ikind = Cil.IInt @@ -2513,7 +2512,8 @@ module Enums : S with type int_t = Z.t = struct let ex = if Z.gt x Z.zero || Z.lt y Z.zero then BISet.singleton Z.zero else BISet.empty () in norm ik @@ (Exc (ex, r)) - let join ik = curry @@ function + let join _ x y = + match x, y with | Inc x, Inc y -> Inc (BISet.union x y) | Exc (x,r1), Exc (y,r2) -> Exc (BISet.inter x y, R.join r1 r2) | Exc (x,r), Inc y @@ -2521,13 +2521,14 @@ module Enums : S with type int_t = Z.t = struct let r = if BISet.is_empty y then r else - let (min_el_range, max_el_range) = Tuple2.mapn (fun x -> R.of_interval range_ikind (Size.min_range_sign_agnostic x)) (BISet.min_elt y, BISet.max_elt y) in + let (min_el_range, max_el_range) = Batteries.Tuple2.mapn (fun x -> R.of_interval range_ikind (Size.min_range_sign_agnostic x)) (BISet.min_elt y, BISet.max_elt y) in let range = R.join min_el_range max_el_range in R.join r range in Exc (BISet.diff x y, r) - let meet ikind = curry @@ function + let meet _ x y = + match x, y with | Inc x, Inc y -> Inc (BISet.inter x y) | Exc (x,r1), Exc (y,r2) -> let r = R.meet r1 r2 in @@ -2581,7 +2582,8 @@ module Enums : S with type int_t = Z.t = struct try lift2 f ikind a b with Division_by_zero -> top_of ikind let neg ?no_ov = lift1 Z.neg - let add ?no_ov ikind = curry @@ function + let add ?no_ov ikind a b = + match a, b with | Inc z,x when BISet.is_singleton z && BISet.choose z = Z.zero -> x | x,Inc z when BISet.is_singleton z && BISet.choose z = Z.zero -> x | x,y -> lift2 Z.add ikind x y @@ -2615,7 +2617,7 @@ module Enums : S with type int_t = Z.t = struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = Stdlib.Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in + let is_negative = Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in if is_negative (minimal x) || is_negative (minimal y) then top_of ik else From a3d43f673debd47eb5d95c7b2d1cdf1bdd9cf8a3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Jun 2024 13:31:43 +0300 Subject: [PATCH 325/689] Add SKIP to Apron tests (PR #1500) --- tests/regression/46-apron2/87-unlock-idx-ambiguous.c | 2 +- tests/regression/46-apron2/88-unlock-unknown.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/46-apron2/87-unlock-idx-ambiguous.c b/tests/regression/46-apron2/87-unlock-idx-ambiguous.c index 97cada5369..ff6461217e 100644 --- a/tests/regression/46-apron2/87-unlock-idx-ambiguous.c +++ b/tests/regression/46-apron2/87-unlock-idx-ambiguous.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag +// SKIP PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions --set ana.path_sens[+] threadflag // TODO: why nonterm without threadflag path-sens? #include #include diff --git a/tests/regression/46-apron2/88-unlock-unknown.c b/tests/regression/46-apron2/88-unlock-unknown.c index 3e09ee8659..dbdc4b9f77 100644 --- a/tests/regression/46-apron2/88-unlock-unknown.c +++ b/tests/regression/46-apron2/88-unlock-unknown.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions +// SKIP PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet --enable ana.sv-comp.functions #include #include From 8998e4776338305956ac6681fb751ba2a0e6bcba Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 6 Jun 2024 17:37:39 +0300 Subject: [PATCH 326/689] Add enabled_if to Apron cram tests (PR #1500) --- tests/regression/46-apron2/dune | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/regression/46-apron2/dune b/tests/regression/46-apron2/dune index f88a15d505..89efde3083 100644 --- a/tests/regression/46-apron2/dune +++ b/tests/regression/46-apron2/dune @@ -10,4 +10,6 @@ (action (chdir ../../.. (run %{update_suite} group apron2 -q)))) (cram + (alias runaprontest) + (enabled_if %{lib-available:apron}) (deps (glob_files *.c))) From b9badb75d61cc013352afdb39e3bd29aad3ff53f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sat, 8 Jun 2024 11:19:22 +0300 Subject: [PATCH 327/689] Bump and pin apron to v0.9.15 For breaking change: https://github.com/antoinemine/apron/pull/108. --- dune-project | 2 +- goblint.opam | 6 +++++- goblint.opam.locked | 6 +++++- goblint.opam.template | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/dune-project b/dune-project index 878abd3b4f..751876f6b0 100644 --- a/dune-project +++ b/dune-project @@ -54,7 +54,7 @@ conf-gcc ; ensures opam-repository CI installs real gcc from homebrew on MacOS ) (depopts - apron + (apron (>= v0.9.15)) z3 ) (conflicts diff --git a/goblint.opam b/goblint.opam index 692625c965..ec6a1f8fcb 100644 --- a/goblint.opam +++ b/goblint.opam @@ -51,7 +51,10 @@ depends: [ "benchmark" {with-test} "conf-gcc" ] -depopts: ["apron" "z3"] +depopts: [ + "apron" {>= "v0.9.15"} + "z3" +] conflicts: [ "result" {< "1.5"} "ez-conf-lib" {= "1"} @@ -81,6 +84,7 @@ pin-depends: [ [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] # 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" ] + [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#b3172bd51e4bb0135716a300cab424a56970d96f" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index f8de683948..8b184e189d 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -22,7 +22,7 @@ doc: "https://goblint.readthedocs.io/en/latest/" bug-reports: "https://github.com/goblint/analyzer/issues" depends: [ "angstrom" {= "0.15.0"} - "apron" {= "v0.9.14~beta.2"} + "apron" {= "v0.9.15"} "arg-complete" {= "0.1.0"} "astring" {= "0.8.5"} "base-bigarray" {= "base"} @@ -140,5 +140,9 @@ pin-depends: [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ] + [ + "apron.v0.9.15" + "git+https://github.com/antoinemine/apron.git#b3172bd51e4bb0135716a300cab424a56970d96f" + ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.template b/goblint.opam.template index 2d5ef10bc9..27be21015f 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -6,6 +6,7 @@ pin-depends: [ [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] # 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" ] + [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#b3172bd51e4bb0135716a300cab424a56970d96f" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} From ec675d4afc599d86b00e3b25b4f04946215f225f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sat, 8 Jun 2024 11:26:27 +0300 Subject: [PATCH 328/689] Use Apron.Environment.cmp --- src/cdomains/apron/affineEqualityDomain.apron.ml | 4 ++-- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/affineEqualityDomain.apron.ml b/src/cdomains/apron/affineEqualityDomain.apron.ml index 7e60cce74b..75c12a0e63 100644 --- a/src/cdomains/apron/affineEqualityDomain.apron.ml +++ b/src/cdomains/apron/affineEqualityDomain.apron.ml @@ -257,7 +257,7 @@ struct let meet t1 t2 = timing_wrap "meet" (meet t1) t2 let leq t1 t2 = - let env_comp = Environment.compare t1.env t2.env in (* Apron's Environment.compare has defined return values. *) + let env_comp = Environment.cmp t1.env t2.env in (* Apron's Environment.cmp has defined return values. *) if env_comp = -2 || env_comp > 0 then (* -2: environments are not compatible (a variable has different types in the 2 environements *) (* -1: if env1 is a subset of env2, (OK) *) @@ -334,7 +334,7 @@ struct else match Option.get a.d, Option.get b.d with | x, y when is_top_env a || is_top_env b -> {d = Some (Matrix.empty ()); env = Environment.lce a.env b.env} - | x, y when (Environment.compare a.env b.env <> 0) -> + | x, y when (Environment.cmp a.env b.env <> 0) -> let sup_env = Environment.lce a.env b.env in let mod_x = dim_add (Environment.dimchange a.env sup_env) x in let mod_y = dim_add (Environment.dimchange b.env sup_env) y in diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 67bd67f4e5..b5f3bb5304 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -386,7 +386,7 @@ struct let meet t1 t2 = timing_wrap "meet" (meet t1) t2 let leq t1 t2 = - let env_comp = Environment.compare t1.env t2.env in (* Apron's Environment.compare has defined return values. *) + let env_comp = Environment.cmp t1.env t2.env in (* Apron's Environment.cmp has defined return values. *) let implies ts i (var, b) = let tuple_cmp = Tuple2.eq (Option.eq ~eq:Int.equal) (Z.equal) in match var with @@ -450,7 +450,7 @@ struct | Some x, Some y when is_top a || is_top b -> let new_env = Environment.lce a.env b.env in top_of new_env - | Some x, Some y when (Environment.compare a.env b.env <> 0) -> + | Some x, Some y when (Environment.cmp a.env b.env <> 0) -> let sup_env = Environment.lce a.env b.env in let mod_x = dim_add (Environment.dimchange a.env sup_env) x in let mod_y = dim_add (Environment.dimchange b.env sup_env) y in From 794b6ec21cc24bbd790518ede62bb85bbce5b98e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sat, 8 Jun 2024 11:28:50 +0300 Subject: [PATCH 329/689] Implement GobApron.Environment.compare with TODO --- src/cdomains/apron/gobApron.apron.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index c39a3e42db..40867f4889 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -42,6 +42,10 @@ module Environment = struct include Environment + let compare (x: t) (y: t): int = + (* TODO: implement total Environment order in OCaml *) + failwith "Apron.Environment doesn't have total order" (* https://github.com/antoinemine/apron/issues/99 *) + let ivars_only env = let ivs, fvs = Environment.vars env in assert (Array.length fvs = 0); (* shouldn't ever contain floats *) From a371b96d6c08177ff90545fc490ca40c69917077 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Sat, 8 Jun 2024 11:35:02 +0300 Subject: [PATCH 330/689] Remove broken Apron.Abstract1.compare --- src/cdomains/apron/apronDomain.apron.ml | 6 +++--- src/cdomains/apron/gobApron.apron.ml | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/apronDomain.apron.ml b/src/cdomains/apron/apronDomain.apron.ml index d0ef268ca6..9bf17b2f92 100644 --- a/src/cdomains/apron/apronDomain.apron.ml +++ b/src/cdomains/apron/apronDomain.apron.ml @@ -451,9 +451,9 @@ struct let hash (x:t) = A.hash Man.mgr x - let compare (x:t) y: int = - (* there is no A.compare, but polymorphic compare should delegate to Abstract0 and Environment compare's implemented in Apron's C *) - Stdlib.compare x y + let compare (x: t) (y: t): int = + failwith "Apron.Abstract1 doesn't have total order" (* https://github.com/antoinemine/apron/issues/99 *) + let printXml f x = BatPrintf.fprintf f "\n\n\nconstraints\n\n\n%s\n\nenv\n\n\n%s\n\n\n" (XmlUtil.escape (Format.asprintf "%a" A.print x)) (XmlUtil.escape (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (A.env x))) let to_yojson (x: t) = diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index 40867f4889..46a0bbc28d 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -12,7 +12,9 @@ struct include Lincons1 let show = Format.asprintf "%a" print - let compare x y = String.compare (show x) (show y) (* HACK *) + let compare x y = + (* TODO: implement proper total Lincons1 order *) + String.compare (show x) (show y) (* HACK *) let num_vars x = (* Apron.Linexpr0.get_size returns some internal nonsense, so we count ourselves. *) From 36328e613fce1d102c99aae01b0ae4022c822e72 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 10 Jun 2024 12:49:02 +0300 Subject: [PATCH 331/689] Revert "Define CFloatType t = float" This reverts commit 1cbf7aca72bfbc8073a223f13723080b0d3c67ac. --- src/common/cdomains/floatOps/floatOps.ml | 4 ++-- src/common/cdomains/floatOps/floatOps.mli | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/cdomains/floatOps/floatOps.ml b/src/common/cdomains/floatOps/floatOps.ml index 6088fa9447..214b0d6c04 100644 --- a/src/common/cdomains/floatOps/floatOps.ml +++ b/src/common/cdomains/floatOps/floatOps.ml @@ -6,7 +6,7 @@ type round_mode = | Down module type CFloatType = sig - type t = float + type t val name: string val zero: t @@ -95,7 +95,7 @@ module CDouble = struct external atof: round_mode -> string -> t = "atof_double" end -module CFloat : CFloatType = struct +module CFloat = struct type t = float [@@deriving eq, ord, hash, to_yojson] let name = "float" diff --git a/src/common/cdomains/floatOps/floatOps.mli b/src/common/cdomains/floatOps/floatOps.mli index 2deb55a764..f956fe426d 100644 --- a/src/common/cdomains/floatOps/floatOps.mli +++ b/src/common/cdomains/floatOps/floatOps.mli @@ -7,7 +7,7 @@ type round_mode = | Down module type CFloatType = sig - type t = float + type t val name: string val zero: t From 682ce29f7a356abb269ded03e9bfcf0030f6ca3b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 10 Jun 2024 12:49:10 +0300 Subject: [PATCH 332/689] Revert "Remove identity function `to_float`" This reverts commit 87f60f3b16b25261b29f3e999cc7d53b90ade7da. --- src/cdomain/value/cdomains/floatDomain.ml | 4 ++-- src/common/cdomains/floatOps/floatOps.ml | 3 +++ src/common/cdomains/floatOps/floatOps.mli | 1 + tests/unit/cdomains/floatDomainTest.ml | 29 ++++++++++++----------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/cdomain/value/cdomains/floatDomain.ml b/src/cdomain/value/cdomains/floatDomain.ml index db6e4eccb5..0977c68890 100644 --- a/src/cdomain/value/cdomains/floatDomain.ml +++ b/src/cdomain/value/cdomains/floatDomain.ml @@ -241,12 +241,12 @@ module FloatIntervalImpl(Float_t : CFloatType) = struct let minimal = function | Bot -> raise (ArithmeticOnFloatBot (Printf.sprintf "minimal %s" (show Bot))) - | Interval (l, _) -> Some l + | Interval (l, _) -> Some (Float_t.to_float l) | _ -> None let maximal = function | Bot -> raise (ArithmeticOnFloatBot (Printf.sprintf "maximal %s" (show Bot))) - | Interval (_, h) -> Some h + | Interval (_, h) -> Some (Float_t.to_float h) | _ -> None let is_exact = function diff --git a/src/common/cdomains/floatOps/floatOps.ml b/src/common/cdomains/floatOps/floatOps.ml index 214b0d6c04..eced6af248 100644 --- a/src/common/cdomains/floatOps/floatOps.ml +++ b/src/common/cdomains/floatOps/floatOps.ml @@ -16,6 +16,7 @@ module type CFloatType = sig val pi : t val of_float: round_mode -> float -> t + val to_float: t -> float val to_big_int: t -> Z.t val is_finite: t -> bool @@ -67,6 +68,7 @@ module CDouble = struct let pi = Float.pi let of_float _ x = x + let to_float x = x let to_big_int = big_int_of_float let is_finite = Float.is_finite @@ -110,6 +112,7 @@ module CFloat = struct let smallest = smallest' () let pi = pi' () + let to_float x = x let to_big_int = big_int_of_float let is_finite x = Float.is_finite x && x >= lower_bound && x <= upper_bound diff --git a/src/common/cdomains/floatOps/floatOps.mli b/src/common/cdomains/floatOps/floatOps.mli index f956fe426d..a07582f442 100644 --- a/src/common/cdomains/floatOps/floatOps.mli +++ b/src/common/cdomains/floatOps/floatOps.mli @@ -17,6 +17,7 @@ module type CFloatType = sig val pi : t val of_float: round_mode -> float -> t + val to_float: t -> float val to_big_int: t -> Z.t val is_finite: t -> bool diff --git a/tests/unit/cdomains/floatDomainTest.ml b/tests/unit/cdomains/floatDomainTest.ml index 6b49d21a1a..c6cb18500a 100644 --- a/tests/unit/cdomains/floatDomainTest.ml +++ b/tests/unit/cdomains/floatDomainTest.ml @@ -7,18 +7,19 @@ struct module FI = Domain_t module IT = IntDomain.IntDomTuple + let to_float = Float_t.to_float let of_float = Float_t.of_float let add = Float_t.add let sub = Float_t.sub let mul = Float_t.mul let div = Float_t.div - let pred x = Float_t.pred (of_float Nearest x) - let succ x = Float_t.succ (of_float Nearest x) + let pred x = to_float (Float_t.pred (of_float Nearest x)) + let succ x = to_float (Float_t.succ (of_float Nearest x)) - let fmax = Float_t.upper_bound - let fmin = Float_t.lower_bound - let fsmall = Float_t.smallest + let fmax = to_float Float_t.upper_bound + let fmin = to_float Float_t.lower_bound + let fsmall = to_float Float_t.smallest let fi_zero = FI.of_const 0. let fi_one = FI.of_const 1. @@ -52,7 +53,7 @@ struct FI.top () + FI.top () = FI.top (); (FI.of_const fmin) + (FI.of_const fmax) = fi_zero; (FI.of_const fsmall) + (FI.of_const fsmall) = FI.of_const (fsmall +. fsmall); - let one_plus_fsmall = Float_t.add Up (Float_t.of_float Up 1.) Float_t.smallest in + let one_plus_fsmall = to_float (Float_t.add Up (Float_t.of_float Up 1.) Float_t.smallest) in (FI.of_const fsmall) + (FI.of_const 1.) = FI.of_interval (1., one_plus_fsmall); (FI.of_interval (1., 2.)) + (FI.of_interval (2., 3.)) = FI.of_interval (3., 5.); (FI.of_interval (-. 2., 3.)) + (FI.of_interval (-. 100., 20.)) = FI.of_interval (-. 102., 23.); @@ -285,27 +286,27 @@ struct let test_FI_add = QCheck.Test.make ~name:"test_FI_add" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.add (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (add Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && - (FI.leq (FI.of_const (add Down (of_float Nearest arg1) (of_float Nearest arg2))) result)) + (FI.leq (FI.of_const (to_float (add Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (add Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) let test_FI_sub = QCheck.Test.make ~name:"test_FI_sub" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.sub (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (sub Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && - (FI.leq (FI.of_const (sub Down (of_float Nearest arg1) (of_float Nearest arg2)))) result) + (FI.leq (FI.of_const (to_float (sub Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (sub Down (of_float Nearest arg1) (of_float Nearest arg2))))) result) let test_FI_mul = QCheck.Test.make ~name:"test_FI_mul" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.mul (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (mul Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && - (FI.leq (FI.of_const (mul Down (of_float Nearest arg1) (of_float Nearest arg2))) result)) + (FI.leq (FI.of_const (to_float (mul Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (mul Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) let test_FI_div = QCheck.Test.make ~name:"test_FI_div" (QCheck.pair QCheck.float QCheck.float) (fun (arg1, arg2) -> let result = FI.div (FI.of_const arg1) (FI.of_const arg2) in - (FI.leq (FI.of_const (div Up (of_float Nearest arg1) (of_float Nearest arg2))) result) && - (FI.leq (FI.of_const (div Down (of_float Nearest arg1) (of_float Nearest arg2))) result)) + (FI.leq (FI.of_const (to_float (div Up (of_float Nearest arg1) (of_float Nearest arg2)))) result) && + (FI.leq (FI.of_const (to_float (div Down (of_float Nearest arg1) (of_float Nearest arg2)))) result)) let test () = [ From aed4cec86fb4c66c8b134ff9ea7a420327e49fb3 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Mon, 10 Jun 2024 14:00:18 +0200 Subject: [PATCH 333/689] added treatment of speculative computations in relational analyses --- src/cdomains/apron/sharedFunctions.apron.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 827dc252fc..e163ebf8ff 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -104,12 +104,13 @@ struct let texpr1_expr_of_cil_exp (ask:Queries.ask) d env exp no_ov = let conv exp = let query e ik = + if M.tracing then M.trace "relation-query" "before: texpr1_expr_of_cil_exp/query: %a" d_plainexp e; let res = match ask.f (EvalInt e) with | `Bot -> raise (Unsupported_CilExp Exp_not_supported) (* This should never happen according to Michael Schwarz *) | `Top -> IntDomain.IntDomTuple.top_of ik | `Lifted x -> x (* Cast should be unnecessary because it should be taken care of by EvalInt. *) in - if M.tracing then M.trace "relation" "texpr1_expr_of_cil_exp/query: %a -> %a" d_plainexp e IntDomain.IntDomTuple.pretty res; + if M.tracing then M.trace "relation-query" "texpr1_expr_of_cil_exp/query: %a -> %a" d_plainexp e IntDomain.IntDomTuple.pretty res; res in (* recurse without env and ask arguments *) @@ -138,10 +139,12 @@ struct this query is answered by the 2 var equalities domain itself. This normalizes arbitrary expressions to a point where they might be able to be represented by means of 2 var equalities *) let simplify e = + AnalysisState.executing_speculative_computations := true; let ikind = try (Cilfacade.get_ikind_exp e) with Invalid_argument _ -> raise (Unsupported_CilExp Exp_not_supported) in let simp = query e ikind in let const = IntDomain.IntDomTuple.to_int @@ IntDomain.IntDomTuple.cast_to ikind simp in if M.tracing then M.trace "relation" "texpr1_expr_of_cil_exp/simplify: %a -> %a" d_plainexp e IntDomain.IntDomTuple.pretty simp; + AnalysisState.executing_speculative_computations := false; BatOption.map_default (fun c -> Const (CInt (c, ikind, None))) e const in let texpr1 e = texpr1_expr_of_cil_exp (simplify e) in From 3df598090095223e6c4394bb271fa21e440861f8 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Tue, 11 Jun 2024 10:22:39 +0200 Subject: [PATCH 334/689] tweaks from MS' PR comments --- .../apron/linearTwoVarEqualityDomain.apron.ml | 61 +++++++++---------- src/cdomains/apron/sharedFunctions.apron.ml | 4 +- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 923229ca96..069983344e 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -36,17 +36,17 @@ module Rhs = struct let rhs=show_rhs_formatted (Printf.sprintf "var_%d") (v,o,d) in if not (Z.equal d Z.one) then "(" ^ rhs ^ ")/" ^ (Z.to_string d) else rhs - (** factor out gcd from all terms, i.e. ax=by+c is the canonical form for adx+bdy+cd *) + (** factor out gcd from all terms, i.e. ax=by+c with a positive is the canonical form for adx+bdy+cd *) let canonicalize (v,o,d) = let gcd = Z.gcd o d in (* gcd of coefficients *) let gcd = Option.map_default (fun (c,_) -> Z.gcd c gcd) gcd v in (* include monomial in gcd computation *) - let commondivisor = if Z.(lt d zero) then Z.neg gcd else gcd in (* cannonical form dictates d being positive *) - (BatOption.map (fun (coeff,i) -> (Z.div coeff commondivisor,i)) v,Z.div o commondivisor, Z.div d commondivisor) + let commondivisor = if Z.(lt d zero) then Z.neg gcd else gcd in (* canonical form dictates d being positive *) + (BatOption.map (fun (coeff,i) -> (Z.div coeff commondivisor,i)) v, Z.div o commondivisor, Z.div d commondivisor) (** Substitute rhs for varx in rhs' *) let subst rhs varx rhs' = match rhs,rhs' with - | (monom,o,d),(Some (c',x'),o',d') when x'=varx -> canonicalize (Option.map (fun (c,x) -> (Z.mul c c',x)) monom,Z.((o*c')+(d*o')),Z.mul d d') + | (monom, o, d), (Some (c', x'), o', d') when x'=varx -> canonicalize (Option.map (fun (c,x) -> (Z.mul c c',x)) monom, Z.((o*c')+(d*o')), Z.mul d d') | _ -> rhs' end @@ -59,7 +59,7 @@ module EqualitiesConjunction = struct let show_formatted formatter econ = if IntMap.is_empty econ then "{}" else - let str = IntMap.fold (fun i (ref,off,divi) acc -> Printf.sprintf "%s%s=%s ∧ %s" (Rhs.show_coeff divi) (formatter i) (Rhs.show_rhs_formatted formatter (ref,off,divi)) acc) econ "" in + let str = IntMap.fold (fun i (refmonom,off,divi) acc -> Printf.sprintf "%s%s=%s ∧ %s" (Rhs.show_coeff divi) (formatter i) (Rhs.show_rhs_formatted formatter (refmonom,off,divi)) acc) econ "" in "{" ^ String.sub str 0 (String.length str - 4) ^ "}" let show econ = show_formatted (Printf.sprintf "var_%d") econ @@ -76,7 +76,7 @@ module EqualitiesConjunction = struct let nontrivial (_,econmap) lhs = IntMap.mem lhs econmap (** turn x = (cy+o)/d into y = (dx-o)/c*) - let inverse x (c,y,o,d) = (y,(Some (d,x),Z.neg o,c)) + let inverse x (c,y,o,d) = (y, (Some (d, x), Z.neg o, c)) (** sparse implementation of get rhs for lhs, but will default to no mapping for sparse entries *) let get_rhs (_,econmap) lhs = IntMap.find_default (Rhs.var_zero lhs) lhs econmap @@ -89,10 +89,9 @@ module EqualitiesConjunction = struct IntMap.add lhs rhs map ) - (** canonicalize equation, and set_rhs, staying loyal to immutable, sparse map underneath,*) + (** canonicalize equation, and set_rhs, staying loyal to immutable, sparse map underneath *) let canonicalize_and_set (dim,map) lhs rhs = set_rhs (dim,map) lhs (Rhs.canonicalize rhs) - (** add a new equality to the domain *) let copy = identity @@ -104,7 +103,7 @@ module EqualitiesConjunction = struct let offsetlist = Array.to_list indexes in let rec bumpvar delta i = function (* bump the variable i by delta; find delta by counting indices in offsetlist until we reach a larger index then our current parameter *) | head::rest when i>=head -> bumpvar (delta+1) i rest (* rec call even when =, in order to correctly interpret double bumps *) - | _ (* i let res = op i delta in res + | _ (* i op i delta in let memobumpvar = (* Memoized version of bumpvar *) let module IntHash = struct type t = int [@@deriving eq,hash] end in @@ -117,7 +116,8 @@ module EqualitiesConjunction = struct IntHashtbl.add h x r; r) in - let rec bumpentry k (refvar,offset,divi) = function (* directly bumps lhs-variable during a run through indexes, bumping refvar explicitely with a new lookup in indexes *) + let rec bumpentry k (refvar,offset,divi) = function (* directly bumps lhs-variable during a run through indexes, bumping refvar explicitly with a new lookup in indexes *) + | (tbl,delta,head::rest) when k>=head -> bumpentry k (refvar,offset,divi) (tbl,delta+1,rest) (* rec call even when =, in order to correctly interpret double bumps *) | (tbl,delta,lyst) (* k (IntMap.add (op k delta) (BatOption.map (fun (c,v) -> (c,memobumpvar v)) refvar,offset,divi) tbl, delta, lyst) in @@ -148,7 +148,7 @@ module EqualitiesConjunction = struct if M.tracing then M.trace "forget" "headvar var_%d" var; (* var is the reference variable of its connected component *) (let cluster = List.sort (Int.compare) @@ IntMap.fold - (fun i (ref,_,_) l -> BatOption.map_default (fun (coeff,ref) -> if (ref=ref_var) then i::l else l) l ref) (snd d) [] in + (fun i (refe,_,_) l -> BatOption.map_default (fun (coeff,refe) -> if (refe=ref_var) then i::l else l) l refe) (snd d) [] in if M.tracing then M.trace "forget" "cluster varindices: [%s]" (String.concat ", " (List.map (string_of_int) cluster)); (* obtain cluster with common reference variable ref_var*) match cluster with (* new ref_var is taken from head of the cluster *) @@ -157,7 +157,7 @@ module EqualitiesConjunction = struct (* divi*x = coeff*y + offs =inverse=> y =( divi*x - offs)/coeff *) let (newref,offs,divi) = (get_rhs d head) in let (coeff,y) = BatOption.get newref in - let (y,yrhs)= inverse head (coeff,y,offs,divi) in (* reassemble yrhs out of components *) + let (y,yrhs) = inverse head (coeff,y,offs,divi) in (* reassemble yrhs out of components *) let shifted_cluster = (List.fold (fun map i -> let irhs = (get_rhs d i) in (* old entry is i = irhs *) Rhs.subst yrhs y irhs |> (* new entry for i is irhs [yrhs/y] *) @@ -198,14 +198,15 @@ module EqualitiesConjunction = struct let meet_with_one_conj ts i (var, offs, divi) = let (var,offs,divi) = Rhs.canonicalize (var,offs,divi) in (* make sure that the one new conj is properly canonicalized *) let res = - let subst_var tsi x (vary, o, d) = + let subst_var (dim,econj) x (vary, o, d) = (* [[x substby (cy+o)/d ]] ((c'x+o')/d') *) (* =====> (c'cy + c'o+o'd)/(dd') *) let adjust = function - | (Some (c',varx), o',d') when varx = x -> Rhs.canonicalize (BatOption.map (fun (c,y)->(Z.mul c c',y)) vary, Z.((c'*o)+(o'*d)),Z.(d'*d)) + | (Some (c',varx), o',d') when varx = x -> + let open Z in Rhs.canonicalize (BatOption.map (fun (c, y)-> (c * c', y)) vary, c'*o + o'*d, d'*d) | e -> e in - (fst tsi, IntMap.add x (vary, o, d) @@ IntMap.map adjust (snd tsi)) (* in case of sparse representation, make sure that the equality is now included in the conjunction *) + (dim, IntMap.add x (vary, o, d) @@ IntMap.map adjust econj) (* in case of sparse representation, make sure that the equality is now included in the conjunction *) in (match var, (get_rhs ts i) with (*| new conj , old conj *) @@ -230,8 +231,8 @@ module EqualitiesConjunction = struct | (Some (coeff2,h2), o2, divi2) as normalizedj -> if h1 = h2 then (* this is the case where x_i and x_j already where in the same equivalence class; let's see whether the new equality contradicts the old one *) let normalizedi= Rhs.subst normalizedj j (Some(coeff,j),offs,divi) in - (if not @@ Rhs.equal normalizedi oldi then raise Contradiction else ts) - else if h1 < h2 (* good, we no unite the two equvalence classes; let's decide upon the representant *) + if not @@ Rhs.equal normalizedi oldi then raise Contradiction else ts + else if h1 < h2 (* good, we now unite the two equvalence classes; let's decide upon the representative *) then (* express h2 in terms of h1: *) let (_,newh2)= inverse j (coeff2,h2,o2,divi2) in let newh2 = Rhs.subst oldi i (Rhs.subst (snd @@ inverse i (coeff,j,offs,divi)) j newh2) in @@ -244,13 +245,10 @@ module EqualitiesConjunction = struct ; res (** affine transform variable i allover conj with transformer (Some (coeff,i)+offs)/divi *) - let affine_transform econ i (var,offs,divi) = - if nontrivial econ i then (** i cannot occur on any other rhs apart from itself *) - set_rhs econ i (Rhs.subst (get_rhs econ i) i (var,offs,divi)) + let affine_transform econ i (coeff, j, offs, divi) = + if nontrivial econ i then (* i cannot occur on any other rhs apart from itself *) + set_rhs econ i (Rhs.subst (get_rhs econ i) i (Some (coeff,j), offs, divi)) else (* var_i = var_i, i.e. it may occur on the rhs of other equalities *) - match var with - | None -> failwith "this is not a valid affine transformation" - | Some (coeff,j) -> (* so now, we transform with the inverse of the transformer: *) let inv = snd (inverse i (coeff,j,offs,divi)) in IntMap.fold (fun k v acc -> @@ -276,12 +274,10 @@ struct let open Apron.Texpr1 in let exception NotLinearExpr in let exception ScalarIsInfinity in - let negate coeff_var_list = List.map (function - | (Some(coeff,i),offs,divi) -> (Some(Z.neg coeff,i),Z.neg offs,divi) - | (None ,offs,divi) -> (None ,Z.neg offs,divi)) coeff_var_list in - let multiply_with_Q dividend divisor coeff_var_list = List.map (function - | (Some (coeff, var),offs,divi) -> Rhs.canonicalize (Some(Z.mul dividend coeff,var),Z.(dividend * offs),Z.mul divi divisor) - | (None,offs,divi) -> Rhs.canonicalize (None,Z.mul dividend offs,Z.mul divi divisor)) coeff_var_list in + let negate coeff_var_list = + List.map (fun (monom, offs, divi) -> Z.(BatOption.map (fun (coeff,i) -> (neg coeff, i)) monom, neg offs, divi)) coeff_var_list in + let multiply_with_Q dividend divisor coeff_var_list = + List.map (fun (monom, offs, divi) -> Rhs.canonicalize Z.(BatOption.map (fun (coeff,i) -> (dividend*coeff,i)) monom, dividend*offs, divi*divisor) ) coeff_var_list in let multiply a b = (* if one of them is a constant, then multiply. Otherwise, the expression is not linear *) match a, b with @@ -614,7 +610,7 @@ struct assign_const (forget_var t var) var_i off divi | Some (Some (coeff_var,exp_var), off, divi) when var_i = exp_var -> (* Statement "assigned_var = (coeff_var*assigned_var + off) / divi" *) - {d=Some (EConj.affine_transform d var_i (Some (coeff_var, var_i), off, divi)); env=t.env } + {d=Some (EConj.affine_transform d var_i (coeff_var, var_i, off, divi)); env=t.env } | Some (Some monomial, off, divi) -> (* Statement "assigned_var = (monomial) + off / divi" (assigned_var is not the same as exp_var) *) meet_with_one_conj (forget_var t var) var_i (Some (monomial), off, divi) @@ -742,10 +738,11 @@ struct | EQ -> (* c1*var1/d1 + c2*var2/d2 +constant/divisor = 0*) (* ======> c1*divisor*d2 * var1 = -c2*divisor*d1 * var2 +constant*-d1*d2*) (* \/ c2*divisor*d1 * var2 = -c1*divisor*d2 * var1 +constant*-d1*d2*) + let open Z in if var1 < var2 then - meet_with_one_conj t var2 (Rhs.canonicalize (Some (Z.neg @@ Z.(c1*divisor),var1),Z.neg @@ Z.(constant*d2*d1),Z.(c2*divisor*d1))) + meet_with_one_conj t var2 (Rhs.canonicalize (Some (neg @@ c1*divisor,var1),neg @@ constant*d2*d1,c2*divisor*d1)) else - meet_with_one_conj t var1 (Rhs.canonicalize (Some (Z.neg @@ Z.(c2*divisor),var2),Z.neg @@ Z.(constant*d2*d1),Z.(c1*divisor*d2))) + meet_with_one_conj t var1 (Rhs.canonicalize (Some (neg @@ c2*divisor,var2),neg @@ constant*d2*d1,c1*divisor*d2)) | _-> t (* Not supported in equality based 2vars without coeffiients *) end | _ -> t (* For equalities of more then 2 vars we just return t *)) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index e163ebf8ff..6b1993d381 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -104,7 +104,6 @@ struct let texpr1_expr_of_cil_exp (ask:Queries.ask) d env exp no_ov = let conv exp = let query e ik = - if M.tracing then M.trace "relation-query" "before: texpr1_expr_of_cil_exp/query: %a" d_plainexp e; let res = match ask.f (EvalInt e) with | `Bot -> raise (Unsupported_CilExp Exp_not_supported) (* This should never happen according to Michael Schwarz *) @@ -139,12 +138,11 @@ struct this query is answered by the 2 var equalities domain itself. This normalizes arbitrary expressions to a point where they might be able to be represented by means of 2 var equalities *) let simplify e = - AnalysisState.executing_speculative_computations := true; + GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> let ikind = try (Cilfacade.get_ikind_exp e) with Invalid_argument _ -> raise (Unsupported_CilExp Exp_not_supported) in let simp = query e ikind in let const = IntDomain.IntDomTuple.to_int @@ IntDomain.IntDomTuple.cast_to ikind simp in if M.tracing then M.trace "relation" "texpr1_expr_of_cil_exp/simplify: %a -> %a" d_plainexp e IntDomain.IntDomTuple.pretty simp; - AnalysisState.executing_speculative_computations := false; BatOption.map_default (fun c -> Const (CInt (c, ikind, None))) e const in let texpr1 e = texpr1_expr_of_cil_exp (simplify e) in From ca31b6e0eb0b7be74c359fd127e1267274836fef Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Tue, 11 Jun 2024 10:27:29 +0200 Subject: [PATCH 335/689] added explanation --- src/cdomains/apron/sharedFunctions.apron.ml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 6b1993d381..8c94c996b0 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -136,7 +136,13 @@ struct let expr = (** simplify asks for a constant value of some subexpression e, similar to a constant fold. In particular but not exclusively this query is answered by the 2 var equalities domain itself. This normalizes arbitrary expressions to a point where they - might be able to be represented by means of 2 var equalities *) + might be able to be represented by means of 2 var equalities + + This simplification happens during a time, when there are temporary variables a#in and a#out part of the expression, + but are not represented in the ctx, thus queries may result in top for these variables. Wrapping this in speculative + mode is a stop-gap measure to avoid flagging overflows. We however should address simplification in a more generally useful way. + outside of the apron-related expression conversion. + *) let simplify e = GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> let ikind = try (Cilfacade.get_ikind_exp e) with Invalid_argument _ -> raise (Unsupported_CilExp Exp_not_supported) in From 87e1e33843caaddaee111560287585b2bb1e28f8 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 11 Jun 2024 12:26:38 +0300 Subject: [PATCH 336/689] Use GobOption.forall instead Option.fold --- src/cdomain/value/cdomains/intDomain.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 69125a0d7a..7b3a8f955e 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2256,7 +2256,7 @@ struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in + let is_negative = GobOption.for_all (fun x -> Z.compare x Z.zero < 0) in if is_negative (minimal x) || is_negative (minimal y) then top_of ik else @@ -2617,7 +2617,7 @@ module Enums : S with type int_t = Z.t = struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = Option.fold ~none:true ~some:(fun x -> Z.compare x Z.zero < 0) in + let is_negative = GobOption.for_all (fun x -> Z.compare x Z.zero < 0) in if is_negative (minimal x) || is_negative (minimal y) then top_of ik else From ae12610b61efeae7c91d9ccdfb50a0d342dc43d1 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 11 Jun 2024 12:27:10 +0300 Subject: [PATCH 337/689] Use Z.lt instead Z.compare --- src/cdomain/value/cdomains/intDomain.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 7b3a8f955e..d75c12527b 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2256,7 +2256,7 @@ struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.compare x Z.zero < 0) in + let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in if is_negative (minimal x) || is_negative (minimal y) then top_of ik else @@ -2617,7 +2617,7 @@ module Enums : S with type int_t = Z.t = struct shift_op a b in (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.compare x Z.zero < 0) in + let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in if is_negative (minimal x) || is_negative (minimal y) then top_of ik else From f0c2c45c4003d222d8f86e6ee703f79f8a15b256 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Tue, 11 Jun 2024 13:15:36 +0200 Subject: [PATCH 338/689] simplify threshold search for narrowing --- src/cdomain/value/cdomains/intDomain.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index a67740e9db..efbab22b43 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -575,11 +575,11 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct let is_upper_threshold u = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in let u = Ints_t.to_bigint u in - List.exists (fun x -> Z.compare u x = 0) ts + List.exists (Z.equal u) ts let is_lower_threshold l = let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in let l = Ints_t.to_bigint l in - List.exists (fun x -> Z.compare l x = 0) ts + List.exists (Z.equal l) ts end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = From bde040e3f0214fdd966a5df9b8ef28dfa315581a Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Tue, 11 Jun 2024 15:42:47 +0200 Subject: [PATCH 339/689] frac_of_scalar instead of int_of_scalar --- src/cdomains/apron/sharedFunctions.apron.ml | 22 ++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index b287bb9bae..7c69cefda4 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -6,6 +6,14 @@ open GobApron module M = Messages +let frac_of_scalar scalar = + if Scalar.is_infty scalar <> 0 then (* infinity means unbounded *) + None + else match scalar with + | Float f -> if Stdlib.Float.is_integer f then Some (Q.of_float f) else None + | Mpqf f -> Some (Z_mlgmpidl.q_of_mpqf f) + | _ -> failwith "frac_of_scalar: unsupported" + let int_of_scalar ?round (scalar: Scalar.t) = if Scalar.is_infty scalar <> 0 then (* infinity means unbounded *) None @@ -20,21 +28,21 @@ let int_of_scalar ?round (scalar: Scalar.t) = | None when Stdlib.Float.is_integer f -> Some f | None -> None in - Q.make (Z.of_float f) Z.one + Z.of_float f | Mpqf scalar -> (* octMPQ, boxMPQ, polkaMPQ *) let n = Mpqf.get_num scalar in let d = Mpqf.get_den scalar in - let+ (n,d) = + let+ z = if Mpzf.cmp_int d 1 = 0 then (* exact integer (denominator 1) *) - Some (n,Mpzf.of_int 1) + Some n else begin match round with - | Some `Floor -> Some (Mpzf.fdiv_q n d, Mpzf.of_int 1) (* floor division *) - | Some `Ceil -> Some (Mpzf.cdiv_q n d, Mpzf.of_int 1) (* ceiling division *) - | None -> Some (n,d) + | Some `Floor -> Some (Mpzf.fdiv_q n d) (* floor division *) + | Some `Ceil -> Some (Mpzf.cdiv_q n d) (* ceiling division *) + | None -> None end in - Q.make (Z_mlgmpidl.z_of_mpzf n) (Z_mlgmpidl.z_of_mpzf d) + Z_mlgmpidl.z_of_mpzf z | _ -> failwith ("int_of_scalar: unsupported: " ^ Scalar.to_string scalar) From 60ecfe7eb23fcdd927eed52da45c9da755dc7fa3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 12 Jun 2024 10:03:42 +0300 Subject: [PATCH 340/689] Fix LinearTwoVarEqualityDomain indentation (PR #1466) --- .../apron/linearTwoVarEqualityDomain.apron.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 069983344e..5558bc2c96 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -249,13 +249,13 @@ module EqualitiesConjunction = struct if nontrivial econ i then (* i cannot occur on any other rhs apart from itself *) set_rhs econ i (Rhs.subst (get_rhs econ i) i (Some (coeff,j), offs, divi)) else (* var_i = var_i, i.e. it may occur on the rhs of other equalities *) - (* so now, we transform with the inverse of the transformer: *) - let inv = snd (inverse i (coeff,j,offs,divi)) in - IntMap.fold (fun k v acc -> - match v with - | (Some (c,x),o,d) when x=i-> set_rhs acc k (Rhs.subst inv i v) - | _ -> acc - ) (snd econ) econ + (* so now, we transform with the inverse of the transformer: *) + let inv = snd (inverse i (coeff,j,offs,divi)) in + IntMap.fold (fun k v acc -> + match v with + | (Some (c,x),o,d) when x=i-> set_rhs acc k (Rhs.subst inv i v) + | _ -> acc + ) (snd econ) econ end From 19164253deacf3d6140fd4e917c7bc5b58be395d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 12 Jun 2024 11:46:33 +0200 Subject: [PATCH 341/689] Introduce sync reason "SyncJoin" Helps avoid "sync" calls for function start nodes when threadflag is context-sensitive. Previsouly, it was only avoided when the flag was path-sensitive --- src/analyses/apron/relationAnalysis.apron.ml | 2 +- src/analyses/apron/relationPriv.apron.ml | 80 +++++++++++++------- src/analyses/base.ml | 2 +- src/analyses/basePriv.ml | 43 +++++++++-- src/analyses/basePriv.mli | 2 +- src/analyses/commonPriv.ml | 15 ++++ src/framework/analyses.ml | 2 +- src/framework/constraints.ml | 5 +- tests/regression/46-apron2/89-sides-pp.c | 27 +++++++ 9 files changed, 136 insertions(+), 42 deletions(-) create mode 100644 tests/regression/46-apron2/89-sides-pp.c diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index 72b91d71b7..a42d78d71a 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -772,7 +772,7 @@ struct PCU.RH.replace results ctx.node new_value; end; WideningTokens.with_local_side_tokens (fun () -> - Priv.sync (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg ctx.local (reason :> [`Normal | `Join | `Return | `Init | `Thread]) + Priv.sync (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg ctx.local (reason :> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread]) ) let init marshal = diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 61da6ddc42..6f75ddbfe5 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -36,7 +36,7 @@ module type S = val lock: Q.ask -> (V.t -> G.t) -> relation_components_t -> LockDomain.Addr.t -> relation_components_t val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> LockDomain.Addr.t -> relation_components_t - val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> [`Normal | `Join | `Return | `Init | `Thread] -> relation_components_t + val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread] -> relation_components_t val escape: Node.t -> Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> EscapeDomain.EscapedVars.t -> relation_components_t val enter_multithreaded: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> relation_components_t @@ -96,8 +96,7 @@ struct { st with rel = rel_local } let sync (ask: Q.ask) getg sideg (st: relation_components_t) reason = - match reason with - | `Join when ConfCheck.branched_thread_creation () -> + let branched_sync () = if ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else @@ -110,7 +109,14 @@ struct ) in {st with rel = rel_local} + in + match reason with + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation () -> + branched_sync () | `Join + | `JoinCall | `Normal | `Init | `Thread @@ -337,17 +343,8 @@ struct let thread_join ?(force=false) ask getg exp st = st let thread_return ask getg sideg tid st = st - let sync ask getg sideg (st: relation_components_t) reason = - match reason with - | `Return -> (* required for thread return *) - (* TODO: implement? *) - begin match ThreadId.get_current ask with - | `Lifted x (* when CPA.mem x st.cpa *) -> - st - | _ -> - st - end - | `Join when ConfCheck.branched_thread_creation () -> + let sync (ask:Q.ask) getg sideg (st: relation_components_t) reason = + let branched_sync () = if ask.f (Q.MustBeSingleThreaded { since_start= true }) then st else @@ -376,7 +373,22 @@ struct let rel_local' = RD.meet rel_local (getg ()) in {st with rel = rel_local'} *) st + in + match reason with + | `Return -> (* required for thread return *) + (* TODO: implement? *) + begin match ThreadId.get_current ask with + | `Lifted x (* when CPA.mem x st.cpa *) -> + st + | _ -> + st + end + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + branched_sync () | `Join + | `JoinCall | `Normal | `Init | `Thread -> @@ -626,17 +638,8 @@ struct let thread_join ?(force=false) ask getg exp st = st let thread_return ask getg sideg tid st = st - let sync ask getg sideg (st: relation_components_t) reason = - match reason with - | `Return -> (* required for thread return *) - (* TODO: implement? *) - begin match ThreadId.get_current ask with - | `Lifted x (* when CPA.mem x st.cpa *) -> - st - | _ -> - st - end - | `Join when ConfCheck.branched_thread_creation () -> + let sync (ask:Q.ask) getg sideg (st: relation_components_t) reason = + let branched_sync () = if ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else @@ -659,7 +662,22 @@ struct ) in {st with rel = rel_local} + in + match reason with + | `Return -> (* required for thread return *) + (* TODO: implement? *) + begin match ThreadId.get_current ask with + | `Lifted x (* when CPA.mem x st.cpa *) -> + st + | _ -> + st + end + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + branched_sync () | `Join + | `JoinCall | `Normal | `Init | `Thread -> @@ -1192,9 +1210,7 @@ struct st let sync (ask:Q.ask) getg sideg (st: relation_components_t) reason = - match reason with - | `Return -> st (* TODO: implement? *) - | `Join when ConfCheck.branched_thread_creation () -> + let branched_sync () = if ask.f (Q.MustBeSingleThreaded {since_start = true}) then st else @@ -1209,7 +1225,15 @@ struct ) in {st with rel = rel_local} + in + match reason with + | `Return -> st (* TODO: implement? *) + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + branched_sync () | `Join + | `JoinCall | `Normal | `Init | `Thread -> diff --git a/src/analyses/base.ml b/src/analyses/base.ml index b80ac59d7f..102e22b5a7 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -451,7 +451,7 @@ struct else ctx.local - let sync ctx reason = sync' (reason :> [`Normal | `Join | `Return | `Init | `Thread]) ctx + let sync ctx reason = sync' (reason :> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread]) ctx let publish_all ctx reason = ignore (sync' reason ctx) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index cecc838b9e..878a86d85e 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -31,7 +31,7 @@ sig val lock: Q.ask -> (V.t -> G.t) -> BaseComponents (D).t -> LockDomain.Addr.t -> BaseComponents (D).t val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> LockDomain.Addr.t -> BaseComponents (D).t - val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> [`Normal | `Join | `Return | `Init | `Thread] -> BaseComponents (D).t + val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread] -> BaseComponents (D).t val escape: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseComponents (D).t val enter_multithreaded: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> BaseComponents (D).t @@ -306,8 +306,8 @@ struct st let sync ask getg sideg (st: BaseComponents (D).t) reason = - match reason with - | `Join when ConfCheck.branched_thread_creation () -> (* required for branched thread creation *) + let branched_sync () = + (* required for branched thread creation *) let global_cpa = CPA.filter (fun x _ -> is_global ask x && is_unprotected ask x) st.cpa in sideg V.mutex_inits global_cpa; (* must be like enter_multithreaded *) (* TODO: this makes mutex-oplus less precise in 28-race_reach/10-ptrmunge_racefree and 28-race_reach/trylock2_racefree, why? *) @@ -318,7 +318,14 @@ struct sideg (V.global x) (CPA.singleton x v) ) st.cpa; st + in + match reason with + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + branched_sync () | `Join + | `JoinCall | `Return | `Normal | `Init @@ -404,8 +411,8 @@ struct {st with cpa = cpa'} let sync ask getg sideg (st: BaseComponents (D).t) reason = - match reason with - | `Join when ConfCheck.branched_thread_creation () -> (* required for branched thread creation *) + let branched_sync () = + (* required for branched thread creation *) let global_cpa = CPA.filter (fun x _ -> is_global ask x && is_unprotected ask x) st.cpa in sideg V.mutex_inits global_cpa; (* must be like enter_multithreaded *) @@ -422,7 +429,14 @@ struct ) st.cpa st.cpa in {st with cpa = cpa'} + in + match reason with + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + branched_sync () | `Join + | `JoinCall | `Return | `Normal | `Init @@ -772,9 +786,9 @@ struct ) st.cpa st let sync ask getg sideg (st: BaseComponents (D).t) reason = - let sideg = Wrapper.sideg ask sideg in - match reason with - | `Join when ConfCheck.branched_thread_creation () -> (* required for branched thread creation *) + let branched_sync () = + (* required for branched thread creation *) + let sideg = Wrapper.sideg ask sideg in CPA.fold (fun x v (st: BaseComponents (D).t) -> if is_global ask x && is_unprotected ask x then ( sideg (V.unprotected x) v; @@ -784,7 +798,14 @@ struct else st ) st.cpa st + in + match reason with + | `Join when ConfCheck.branched_thread_creation () -> + branched_sync () + | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + branched_sync () | `Join + | `JoinCall | `Return | `Normal | `Init @@ -1034,6 +1055,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) + | `JoinCall | `Init | `Thread -> st @@ -1089,6 +1111,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) + | `JoinCall | `Init | `Thread -> st @@ -1160,6 +1183,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) + | `JoinCall | `Init | `Thread -> st @@ -1318,6 +1342,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) + | `JoinCall | `Init | `Thread -> st @@ -1496,6 +1521,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) + | `JoinCall | `Init | `Thread -> st @@ -1678,6 +1704,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) + | `JoinCall | `Init | `Thread -> st diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index e176a450fa..87b17e5ad0 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -20,7 +20,7 @@ sig val lock: Queries.ask -> (V.t -> G.t) -> BaseDomain.BaseComponents (D).t -> LockDomain.Addr.t -> BaseDomain.BaseComponents (D).t val unlock: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> LockDomain.Addr.t -> BaseDomain.BaseComponents (D).t - val sync: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> [`Normal | `Join | `Return | `Init | `Thread] -> BaseDomain.BaseComponents (D).t + val sync: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread] -> BaseDomain.BaseComponents (D).t val escape: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseDomain.BaseComponents (D).t val enter_multithreaded: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index fb5d0db142..9f87f35b38 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -59,6 +59,21 @@ struct not threadflag_path_sens else true + + (** Whether branched thread creation at start nodes of procedures needs to be handled by [sync `JoinCall] of privatization. *) + let branched_thread_creation_at_call () = + let threadflag_active = List.mem "threadflag" (GobConfig.get_string_list "ana.activated") in + if threadflag_active then + let sens = GobConfig.get_string_list "ana.ctx_sens" in + let threadflag_ctx_sens = match sens with + | [] -> (* use values of "ana.ctx_insens" (blacklist) *) + not (List.mem "threadflag" @@ GobConfig.get_string_list "ana.ctx_insens") + | sens -> (* use values of "ana.ctx_sens" (whitelist) *) + List.mem "threadflag" sens + in + not threadflag_ctx_sens + else + true end module Protection = diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 4ef98358f4..1ea01c99fb 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -209,7 +209,7 @@ sig val context: (D.t, G.t, C.t, V.t) ctx -> fundec -> D.t -> C.t val startcontext: unit -> C.t - val sync : (D.t, G.t, C.t, V.t) ctx -> [`Normal | `Join | `Return] -> D.t + val sync : (D.t, G.t, C.t, V.t) ctx -> [`Normal | `Join | `JoinCall | `Return] -> D.t val query : (D.t, G.t, C.t, V.t) ctx -> 'a Queries.t -> 'a Queries.result (** A transfer function which handles the assignment of a rval to a lval, i.e., diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 07180d54dd..6a1eae3ed1 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -624,9 +624,10 @@ struct let sync ctx = match ctx.prev_node, Cfg.prev ctx.prev_node with - | _, _ :: _ :: _ (* Join in CFG. *) - | FunctionEntry _, _ -> (* Function entry, also needs sync because partial contexts joined by solver, see 00-sanity/35-join-contexts. *) + | _, _ :: _ :: _ -> (* Join in CFG. *) S.sync ctx `Join + | FunctionEntry _, _ -> (* Function entry, also needs sync because partial contexts joined by solver, see 00-sanity/35-join-contexts. *) + S.sync ctx `JoinCall | _, _ -> S.sync ctx `Normal let side_context sideg f c = diff --git a/tests/regression/46-apron2/89-sides-pp.c b/tests/regression/46-apron2/89-sides-pp.c new file mode 100644 index 0000000000..10fc5f8d1e --- /dev/null +++ b/tests/regression/46-apron2/89-sides-pp.c @@ -0,0 +1,27 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet +// NOTIMEOUT +#include +#include + +int g; +pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + +void fn() { + // Just do nothing + return; +} + +void *t_fun(void *arg) { + pthread_mutex_lock(&m); + g = g+1; + fn(); + pthread_mutex_unlock(&m); + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + return 0; +} From 496b5ef26373e4e7b06832657f0ba196db671806 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 12 Jun 2024 18:05:34 +0200 Subject: [PATCH 342/689] Add misbehaving program with gas --- src/config/options.schema.json | 2 +- tests/regression/80-context_gas/21-sync.c | 35 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/regression/80-context_gas/21-sync.c diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 488fc494b0..acf85abed9 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -980,7 +980,7 @@ }, "gas_value": { "title": "ana.context.gas_value", - "description": "Denotes the gas value x for the ContextGasLifter. Negative values deactivate the context gas, zero yields a context-insensitve analysis. If enabled, the first x recursive calls of the call stack are analyzed context-sensitively. Any calls deeper in the call stack are analyzed with the same (empty) context.", + "description": "Denotes the gas value x for the ContextGasLifter. Negative values deactivate the context gas, zero yields a context-insensitive analysis. If enabled, the first x recursive calls of the call stack are analyzed context-sensitively. Any calls deeper in the call stack are analyzed with the same (empty) context.", "type": "integer", "default": -1 }, diff --git a/tests/regression/80-context_gas/21-sync.c b/tests/regression/80-context_gas/21-sync.c new file mode 100644 index 0000000000..5769ffaa67 --- /dev/null +++ b/tests/regression/80-context_gas/21-sync.c @@ -0,0 +1,35 @@ +// PARAM: --set ana.context.gas_value 3 +// Like 00/35 but with gas this time! +// Misbehaves for gas <= 3 +#include +#include + +int g = 1; + +void foo() { + // Single-threaded: g = 1 in local state + // Multi-threaded: g = 2 in global unprotected invariant + // Joined contexts: g is unprotected, so read g = 2 from global unprotected invariant (only) + // Was soundly claiming that check will succeed! + int x = g; + __goblint_check(x == 2); // UNKNOWN! +} + +void *t_fun(void *arg) { + foo(); +} + +int do_stuff() { + foo(); + g = 2; + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + return 0; +} + +int main() { + do_stuff(); + return 0; +} From e613e13d64ede078c23b85401a8176107f81d567 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 12 Jun 2024 18:53:17 +0200 Subject: [PATCH 343/689] Make sound for context gas --- src/analyses/apron/relationPriv.apron.ml | 6 ++-- src/analyses/basePriv.ml | 6 ++-- src/analyses/commonPriv.ml | 7 ++-- src/analyses/mCP.ml | 7 ++++ src/domains/queries.ml | 5 +++ src/framework/constraints.ml | 8 ++++- tests/regression/80-context_gas/21-sync.c | 2 +- .../80-context_gas/22-sync-precision.c | 36 +++++++++++++++++++ 8 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 tests/regression/80-context_gas/22-sync-precision.c diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 6f75ddbfe5..3ecfb713d7 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -385,7 +385,7 @@ struct end | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> branched_sync () | `Join | `JoinCall @@ -674,7 +674,7 @@ struct end | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> branched_sync () | `Join | `JoinCall @@ -1230,7 +1230,7 @@ struct | `Return -> st (* TODO: implement? *) | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> branched_sync () | `Join | `JoinCall diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 878a86d85e..efa0575bf4 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -322,7 +322,7 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> branched_sync () | `Join | `JoinCall @@ -433,7 +433,7 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> branched_sync () | `Join | `JoinCall @@ -802,7 +802,7 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call () -> + | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> branched_sync () | `Join | `JoinCall diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 9f87f35b38..1ece8dcc60 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -61,7 +61,7 @@ struct true (** Whether branched thread creation at start nodes of procedures needs to be handled by [sync `JoinCall] of privatization. *) - let branched_thread_creation_at_call () = + let branched_thread_creation_at_call (ask:Queries.ask) = let threadflag_active = List.mem "threadflag" (GobConfig.get_string_list "ana.activated") in if threadflag_active then let sens = GobConfig.get_string_list "ana.ctx_sens" in @@ -71,7 +71,10 @@ struct | sens -> (* use values of "ana.ctx_sens" (whitelist) *) List.mem "threadflag" sens in - not threadflag_ctx_sens + if not threadflag_ctx_sens then + true + else + ask.f (Queries.GasExhausted) else true end diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 71c887dda5..e4c0e261e4 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -318,6 +318,13 @@ struct f (Result.top ()) (!base_id, spec !base_id, assoc !base_id ctx.local) *) | Queries.DYojson -> `Lifted (D.to_yojson ctx.local) + | Queries.GasExhausted -> + if (get_int "ana.context.gas_value" >= 0) then + (* There is a lifter above this that will answer it, save to ask *) + ctx.ask (Queries.GasExhausted) + else + (* Abort to avoid infinite recursion *) + false | _ -> let r = fold_left (f ~q) (Result.top ()) @@ spec_list ctx.local in do_sideg ctx !sides; diff --git a/src/domains/queries.ml b/src/domains/queries.ml index a904f696eb..1ceb91ef1d 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -126,6 +126,7 @@ type _ t = | IsEverMultiThreaded: MayBool.t t | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t + | GasExhausted: MustBool.t t type 'a result = 'a @@ -196,6 +197,7 @@ struct | IsEverMultiThreaded -> (module MayBool) | TmpSpecial _ -> (module ML) | MaySignedOverflow _ -> (module MayBool) + | GasExhausted -> (module MustBool) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -265,6 +267,7 @@ struct | IsEverMultiThreaded -> MayBool.top () | TmpSpecial _ -> ML.top () | MaySignedOverflow _ -> MayBool.top () + | GasExhausted -> MustBool.top () end (* The type any_query can't be directly defined in Any as t, @@ -331,6 +334,7 @@ struct | Any (TmpSpecial _) -> 56 | Any (IsAllocVar _) -> 57 | Any (MaySignedOverflow _) -> 58 + | Any GasExhausted -> 59 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -490,6 +494,7 @@ struct | Any IsEverMultiThreaded -> Pretty.dprintf "IsEverMultiThreaded" | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e + | Any GasExhausted -> Pretty.dprintf "GasExhausted" end let to_value_domain_ask (ask: ask) = diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 6a1eae3ed1..e0e36801ed 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -575,8 +575,14 @@ struct let liftmap f = List.map (fun (x) -> (x, max 0 (cg_val ctx - 1))) f in liftmap (S.threadenter (conv ctx) ~multiple lval f args) + let query ctx (type a) (q: a Queries.t):a Queries.result = + match q with + | Queries.GasExhausted -> + let (d,i) = ctx.local in + (i <= 0) + | _ -> S.query (conv ctx) q + let sync ctx reason = S.sync (conv ctx) reason, cg_val ctx - let query ctx q = S.query (conv ctx) q let assign ctx lval expr = S.assign (conv ctx) lval expr, cg_val ctx let vdecl ctx v = S.vdecl (conv ctx) v, cg_val ctx let body ctx fundec = S.body (conv ctx) fundec, cg_val ctx diff --git a/tests/regression/80-context_gas/21-sync.c b/tests/regression/80-context_gas/21-sync.c index 5769ffaa67..33edf254e5 100644 --- a/tests/regression/80-context_gas/21-sync.c +++ b/tests/regression/80-context_gas/21-sync.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.context.gas_value 3 +// PARAM: --set ana.context.gas_value 1 // Like 00/35 but with gas this time! // Misbehaves for gas <= 3 #include diff --git a/tests/regression/80-context_gas/22-sync-precision.c b/tests/regression/80-context_gas/22-sync-precision.c new file mode 100644 index 0000000000..8fc1dd7779 --- /dev/null +++ b/tests/regression/80-context_gas/22-sync-precision.c @@ -0,0 +1,36 @@ +// PARAM: --set ana.context.gas_value 4 +// Like 00/35 but with gas this time! +// Misbehaves for gas <= 3 +#include +#include + +int g = 1; + +void foo() { + // Check that we don't lose precision due to JoinCall + int x = g; + int x2 = g; + // A hack: In both contexts g has a single possible value, so we check that x = x2 + // to verify there is no precision loss + + __goblint_check(x == x2); +} + +void *t_fun(void *arg) { + foo(); +} + +int do_stuff() { + foo(); + g = 2; + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + return 0; +} + +int main() { + do_stuff(); + return 0; +} From 2e915afaac498209620aee7fc0f5e547d2f7d300 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 13 Jun 2024 11:09:03 +0300 Subject: [PATCH 344/689] Enable pthreadMutexType analysis by default --- conf/examples/medium-program.json | 2 ++ conf/examples/very-precise.json | 2 ++ src/config/options.schema.json | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/conf/examples/medium-program.json b/conf/examples/medium-program.json index 2c1e7c7346..5afc1aa2f8 100644 --- a/conf/examples/medium-program.json +++ b/conf/examples/medium-program.json @@ -9,6 +9,7 @@ "base", "threadid", "threadflag", + "threadreturn", "mallocWrapper", "mutexEvents", "mutex", @@ -18,6 +19,7 @@ "expRelation", "mhp", "assert", + "pthreadMutexType", "var_eq", "symb_locks", "region", diff --git a/conf/examples/very-precise.json b/conf/examples/very-precise.json index 2197335eaf..074d448a85 100644 --- a/conf/examples/very-precise.json +++ b/conf/examples/very-precise.json @@ -22,6 +22,7 @@ "base", "threadid", "threadflag", + "threadreturn", "mallocWrapper", "mutexEvents", "mutex", @@ -31,6 +32,7 @@ "expRelation", "mhp", "assert", + "pthreadMutexType", "var_eq", "symb_locks", "region", diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 488fc494b0..7068cce719 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -344,7 +344,7 @@ "default": [ "expRelation", "base", "threadid", "threadflag", "threadreturn", "escape", "mutexEvents", "mutex", "access", "race", "mallocWrapper", "mhp", - "assert" + "assert", "pthreadMutexType" ] }, "path_sens": { From 5962aedde36fa0caadaf77123ae6bf80b90ecc28 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 13 Jun 2024 11:09:48 +0300 Subject: [PATCH 345/689] Add pthreadMutexType to single-threaded autotuner --- src/autoTune.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 434b4fb0b2..8ec77739e7 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -186,7 +186,7 @@ let enableAnalyses anas = (*escape is also still enabled, because otherwise we get a warning*) (*does not consider dynamic calls!*) -let notNeccessaryThreadAnalyses = ["race"; "deadlock"; "maylocks"; "symb_locks"; "thread"; "threadid"; "threadJoins"; "threadreturn"; "mhp"; "region"] +let notNeccessaryThreadAnalyses = ["race"; "deadlock"; "maylocks"; "symb_locks"; "thread"; "threadid"; "threadJoins"; "threadreturn"; "mhp"; "region"; "pthreadMutexType"] let reduceThreadAnalyses () = let isThreadCreate = function | LibraryDesc.ThreadCreate _ -> true From 30aeb975856b1fe4686bd82648cbd43c15ce686c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 13 Jun 2024 11:10:19 +0300 Subject: [PATCH 346/689] Use Mval.Unit for MutexTypeAnalysis.V --- src/analyses/mutexTypeAnalysis.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analyses/mutexTypeAnalysis.ml b/src/analyses/mutexTypeAnalysis.ml index 441f2e9953..e8edddd41e 100644 --- a/src/analyses/mutexTypeAnalysis.ml +++ b/src/analyses/mutexTypeAnalysis.ml @@ -15,8 +15,9 @@ struct (* Removing indexes here avoids complicated lookups and allows to have the LVals as vars here, at the price that different types of mutexes in arrays are not dinstinguished *) module O = Offset.Unit - module V = struct - include Printable.Prod(CilType.Varinfo)(O) (* TODO: use Mval.Unit *) + module V = + struct + include Mval.Unit let is_write_only _ = false end From 10fe38ecd5eab38d0a567e4551e99928508ca0b9 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 13 Jun 2024 11:10:48 +0300 Subject: [PATCH 347/689] Binary operations on pointer types should not generate overflow warnings in SV-COMP --- src/analyses/base.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index b80ac59d7f..6f768cc1d1 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -885,7 +885,11 @@ struct | None -> evalbinop ~ctx st LOr ~e1 ~e2 typ (* fallback to general case *) end | BinOp (op,e1,e2,typ) -> - evalbinop ~ctx st op ~e1 ~e2 typ + begin match typ with + | TPtr _ -> (* Binary operations on pointer types should not generate warnings in SV-COMP *) + GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> evalbinop ~ctx st op ~e1 ~e2 typ + | _ -> evalbinop ~ctx st op ~e1 ~e2 typ + end (* Unary operators *) | UnOp (op,arg1,typ) -> let a1 = eval_rv ~ctx st arg1 in From 578ca314fd3831f5dce193b0c6df49f60e47904b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 13 Jun 2024 12:03:16 +0300 Subject: [PATCH 348/689] Revert "Binary operations on pointer types should not generate overflow warnings in SV-COMP" This reverts commit 10fe38ecd5eab38d0a567e4551e99928508ca0b9. --- src/analyses/base.ml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 6f768cc1d1..b80ac59d7f 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -885,11 +885,7 @@ struct | None -> evalbinop ~ctx st LOr ~e1 ~e2 typ (* fallback to general case *) end | BinOp (op,e1,e2,typ) -> - begin match typ with - | TPtr _ -> (* Binary operations on pointer types should not generate warnings in SV-COMP *) - GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> evalbinop ~ctx st op ~e1 ~e2 typ - | _ -> evalbinop ~ctx st op ~e1 ~e2 typ - end + evalbinop ~ctx st op ~e1 ~e2 typ (* Unary operators *) | UnOp (op,arg1,typ) -> let a1 = eval_rv ~ctx st arg1 in From c818f0fd92cada2785aa3659ef5961dcc7036fc6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 13 Jun 2024 12:08:01 +0300 Subject: [PATCH 349/689] Binary operations on pointer types should not generate overflow warnings in SV-COMP --- src/analyses/base.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index b80ac59d7f..2e89f98bb2 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -261,6 +261,8 @@ struct (* adds n to the last offset *) let rec addToOffset n (t:typ option) = function | `Index (i, `NoOffset) -> + (* Binary operations on pointer types should not generate warnings in SV-COMP *) + GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> (* If we have arrived at the last Offset and it is an Index, we add our integer to it *) `Index(IdxDom.add i (iDtoIdx n), `NoOffset) | `Field (f, `NoOffset) -> From eec5f2c747d6afae162501a0a94f28637f5d2f81 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Thu, 13 Jun 2024 14:49:28 +0200 Subject: [PATCH 350/689] Rename test and add reference --- tests/regression/46-apron2/{89-sides-pp.c => 89-flag-ctx-sens.c} | 1 + 1 file changed, 1 insertion(+) rename tests/regression/46-apron2/{89-sides-pp.c => 89-flag-ctx-sens.c} (89%) diff --git a/tests/regression/46-apron2/89-sides-pp.c b/tests/regression/46-apron2/89-flag-ctx-sens.c similarity index 89% rename from tests/regression/46-apron2/89-sides-pp.c rename to tests/regression/46-apron2/89-flag-ctx-sens.c index 10fc5f8d1e..41e4f02520 100644 --- a/tests/regression/46-apron2/89-sides-pp.c +++ b/tests/regression/46-apron2/89-flag-ctx-sens.c @@ -1,5 +1,6 @@ // SKIP PARAM: --set ana.activated[+] apron --set ana.relation.privatization mutex-meet // NOTIMEOUT +// See https://github.com/goblint/analyzer/pull/1508 #include #include From a3b436284771cea0e1d86bda1a5b32da12f5e849 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 13 Jun 2024 18:04:33 +0300 Subject: [PATCH 351/689] Add YAML witness violation_sequence entry type --- src/witness/yamlWitnessType.ml | 200 +++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 1630e05b69..526d52d327 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -426,6 +426,200 @@ struct let entry_type = "precondition_loop_invariant_certificate" end +module ViolationSequence = +struct + + module Constraint = + struct + type t = { + value: string; + format: string; + } + [@@deriving ord] + + let to_yaml {value; format} = + `O [ + ("value", `String value); + ("format", `String format); + ] + + let of_yaml y = + let open GobYaml in + let+ value = y |> find "value" >>= to_string + and+ format = y |> find "format" >>= to_string in + {value; format} + end + + module Assumption = + struct + type t = { + location: Location.t; + action: string; + constraint_: Constraint.t; + } + [@@deriving ord] + + let waypoint_type = "assumption" + + let to_yaml' {location; action; constraint_} = + [ + ("location", Location.to_yaml location); + ("action", `String action); + ("constraint", Constraint.to_yaml constraint_); + ] + + let of_yaml y = + let open GobYaml in + let+ location = y |> find "location" >>= Location.of_yaml + and+ action = y |> find "action" >>= to_string + and+ constraint_ = y |> find "constraint" >>= Constraint.of_yaml in + {location; action; constraint_} + end + + module Target = + struct + type t = { + location: Location.t; + action: string; + } + [@@deriving ord] + + let waypoint_type = "target" + + let to_yaml' {location; action} = + [ + ("location", Location.to_yaml location); + ("action", `String action); + ] + + let of_yaml y = + let open GobYaml in + let+ location = y |> find "location" >>= Location.of_yaml + and+ action = y |> find "action" >>= to_string in + {location; action} + end + + module FunctionEnter = + struct + include Target + + let waypoint_type = "function_enter" + end + + module FunctionReturn = + struct + include Assumption + + let waypoint_type = "function_return" + end + + module Branching = + struct + include Assumption + + let waypoint_type = "branching" + end + + (* TODO: could maybe use GADT, but adds ugly existential layer to entry type pattern matching *) + module WaypointType = + struct + type t = + | Assumption of Assumption.t + | Target of Target.t + | FunctionEnter of FunctionEnter.t + | FunctionReturn of FunctionReturn.t + | Branching of Branching.t + [@@deriving ord] + + let waypoint_type = function + | Assumption _ -> Assumption.waypoint_type + | Target _ -> Target.waypoint_type + | FunctionEnter _ -> FunctionEnter.waypoint_type + | FunctionReturn _ -> FunctionReturn.waypoint_type + | Branching _ -> Branching.waypoint_type + + let to_yaml' = function + | Assumption x -> Assumption.to_yaml' x + | Target x -> Target.to_yaml' x + | FunctionEnter x -> FunctionEnter.to_yaml' x + | FunctionReturn x -> FunctionReturn.to_yaml' x + | Branching x -> Branching.to_yaml' x + + let of_yaml y = + let open GobYaml in + let* waypoint_type = y |> find "type" >>= to_string in + if waypoint_type = Assumption.waypoint_type then + let+ x = y |> Assumption.of_yaml in + Assumption x + else if waypoint_type = Target.waypoint_type then + let+ x = y |> Target.of_yaml in + Target x + else if waypoint_type = FunctionEnter.waypoint_type then + let+ x = y |> FunctionEnter.of_yaml in + FunctionEnter x + else if waypoint_type = FunctionReturn.waypoint_type then + let+ x = y |> FunctionReturn.of_yaml in + FunctionReturn x + else if waypoint_type = Branching.waypoint_type then + let+ x = y |> Branching.of_yaml in + Branching x + else + Error (`Msg "type") + end + + module Waypoint = + struct + type t = { + waypoint_type: WaypointType.t; + } + [@@deriving ord] + + let to_yaml {waypoint_type} = + `O [ + ("waypoint", `O ([ + ("type", `String (WaypointType.waypoint_type waypoint_type)); + ] @ WaypointType.to_yaml' waypoint_type) + ) + ] + + let of_yaml y = + let open GobYaml in + let+ waypoint_type = y |> find "waypoint" >>= WaypointType.of_yaml in + {waypoint_type} + end + + module Segment = + struct + type t = { + segment: Waypoint.t list; + } + [@@deriving ord] + + let to_yaml {segment} = + `O [("segment", `A (List.map Waypoint.to_yaml segment))] + + let of_yaml y = + let open GobYaml in + let+ segment = y |> find "segment" >>= list >>= list_map Waypoint.of_yaml in + {segment} + end + + type t = { + content: Segment.t list; + } + [@@deriving ord] + + let entry_type = "violation_sequence" + + let to_yaml' {content} = + [("content", `A (List.map Segment.to_yaml content))] + + let of_yaml y = + let open GobYaml in + let+ content = y |> find "content" >>= list >>= list_map Segment.of_yaml in + {content} +end + (* TODO: could maybe use GADT, but adds ugly existential layer to entry type pattern matching *) module EntryType = struct @@ -437,6 +631,7 @@ struct | LoopInvariantCertificate of LoopInvariantCertificate.t | PreconditionLoopInvariantCertificate of PreconditionLoopInvariantCertificate.t | InvariantSet of InvariantSet.t + | ViolationSequence of ViolationSequence.t [@@deriving ord] let entry_type = function @@ -447,6 +642,7 @@ struct | LoopInvariantCertificate _ -> LoopInvariantCertificate.entry_type | PreconditionLoopInvariantCertificate _ -> PreconditionLoopInvariantCertificate.entry_type | InvariantSet _ -> InvariantSet.entry_type + | ViolationSequence _ -> ViolationSequence.entry_type let to_yaml' = function | LocationInvariant x -> LocationInvariant.to_yaml' x @@ -456,6 +652,7 @@ struct | LoopInvariantCertificate x -> LoopInvariantCertificate.to_yaml' x | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate.to_yaml' x | InvariantSet x -> InvariantSet.to_yaml' x + | ViolationSequence x -> ViolationSequence.to_yaml' x let of_yaml y = let open GobYaml in @@ -481,6 +678,9 @@ struct else if entry_type = InvariantSet.entry_type then let+ x = y |> InvariantSet.of_yaml in InvariantSet x + else if entry_type = ViolationSequence.entry_type then + let+ x = y |> ViolationSequence.of_yaml in + ViolationSequence x else Error (`Msg "entry_type") end From a98da9d0c838a6073aff78515de848fb9d01047e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 12:19:38 +0300 Subject: [PATCH 352/689] Implement violation_sequence in yamlWitnessStrip --- tests/util/yamlWitnessStrip.ml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 8a5046d6ff..75c6cf3583 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -26,6 +26,25 @@ struct in {invariant_type} in + let waypoint_strip_file_hash ({waypoint_type}: ViolationSequence.Waypoint.t): ViolationSequence.Waypoint.t = + let waypoint_type: ViolationSequence.WaypointType.t = + match waypoint_type with + | Assumption x -> + Assumption {x with location = location_strip_file_hash x.location} + | Target x -> + Target {x with location = location_strip_file_hash x.location} + | FunctionEnter x -> + FunctionEnter {x with location = location_strip_file_hash x.location} + | FunctionReturn x -> + FunctionReturn {x with location = location_strip_file_hash x.location} + | Branching x -> + Branching {x with location = location_strip_file_hash x.location} + in + {waypoint_type} + in + let segment_strip_file_hash ({segment}: ViolationSequence.Segment.t): ViolationSequence.Segment.t = + {segment = List.map waypoint_strip_file_hash segment} + in let entry_type: EntryType.t = match entry_type with | LocationInvariant x -> @@ -42,6 +61,8 @@ struct PreconditionLoopInvariantCertificate {x with target = target_strip_file_hash x.target} | InvariantSet x -> InvariantSet {content = List.map invariant_strip_file_hash x.content} + | ViolationSequence x -> + ViolationSequence {content = List.map segment_strip_file_hash x.content} in {entry_type} From c4c4b258463442305d5837e08a6ef493a2afd304 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 14 Jun 2024 12:59:06 +0300 Subject: [PATCH 353/689] Add test for loop unrolling causing a signed integer overflow warning to appear --- .../55-loop-unrolling/12-loop-no-overflows.c | 37 ++++++++++ .../13-unrolled-loop-no-overflows.c | 72 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 tests/regression/55-loop-unrolling/12-loop-no-overflows.c create mode 100644 tests/regression/55-loop-unrolling/13-unrolled-loop-no-overflows.c diff --git a/tests/regression/55-loop-unrolling/12-loop-no-overflows.c b/tests/regression/55-loop-unrolling/12-loop-no-overflows.c new file mode 100644 index 0000000000..03554e06c5 --- /dev/null +++ b/tests/regression/55-loop-unrolling/12-loop-no-overflows.c @@ -0,0 +1,37 @@ +// PARAM: --enable ana.int.interval_set +// extracted from SV-COMP task ldv-memsafety/memleaks_test12-2.i + +typedef unsigned int size_t; +struct ldv_list_head { + struct ldv_list_head *next, *prev; +}; +struct ldv_list_head ldv_global_msg_list = {&(ldv_global_msg_list), &(ldv_global_msg_list)}; +struct ldv_msg { + void *data; + struct ldv_list_head list; +}; + +static inline void __ldv_list_del(struct ldv_list_head *prev, struct ldv_list_head *next) { + next->prev = prev; + prev->next = next; +} + +static inline void ldv_list_del(struct ldv_list_head *entry) { + __ldv_list_del(entry->prev, entry->next); +} + +void ldv_msg_free(struct ldv_msg *msg) { + free(msg->data); + free(msg); +} + +// ldv_destroy_msgs +void main(void) { + struct ldv_msg *msg; + struct ldv_msg *n; + for (msg = ({ const typeof( ((typeof(*msg) *)0)->list ) *__mptr = ((&ldv_global_msg_list)->next); (typeof(*msg) *)( (char *)__mptr - ((size_t) &((typeof(*msg) *)0)->list) ); }), n = ({ const typeof( ((typeof(*(msg)) *)0)->list ) *__mptr = ((msg)->list.next); (typeof(*(msg)) *)( (char *)__mptr - ((size_t) &((typeof(*(msg)) *)0)->list) ); }); &msg->list != (&ldv_global_msg_list); msg = n, n = ({ const typeof( ((typeof(*(n)) *)0)->list ) *__mptr = ((n)->list.next); (typeof(*(n)) *)( (char *)__mptr - ((size_t) &((typeof(*(n)) *)0)->list) ); })) // NOWARN + { + ldv_list_del(&msg->list); + ldv_msg_free(msg); + } +} \ No newline at end of file diff --git a/tests/regression/55-loop-unrolling/13-unrolled-loop-no-overflows.c b/tests/regression/55-loop-unrolling/13-unrolled-loop-no-overflows.c new file mode 100644 index 0000000000..84700ac9da --- /dev/null +++ b/tests/regression/55-loop-unrolling/13-unrolled-loop-no-overflows.c @@ -0,0 +1,72 @@ +// PARAM: --enable ana.int.interval_set +// extracted from SV-COMP task ldv-memsafety/memleaks_test12-2.i with --set exp.unrolling-factor 1 + +typedef unsigned int size_t; +struct ldv_list_head { + struct ldv_list_head *next, *prev; +}; +struct ldv_list_head ldv_global_msg_list = {&(ldv_global_msg_list), &(ldv_global_msg_list)}; +struct ldv_msg { + void *data; + struct ldv_list_head list; +}; + +__inline static void __ldv_list_del(struct ldv_list_head *prev, struct ldv_list_head *next) { + next->prev = prev; + prev->next = next; + return; +} + +__inline static void ldv_list_del(struct ldv_list_head *entry) { + __ldv_list_del(entry->prev, entry->next); + return; +} + +void ldv_msg_free(struct ldv_msg *msg) { + free(msg->data); + free((void *)msg); + return; +} + +// ldv_destroy_msgs +void main(void) { + struct ldv_msg *msg; + struct ldv_msg *n; + struct ldv_list_head const *__mptr; + struct ldv_list_head const *__mptr___0; + struct ldv_list_head const *__mptr___1; + + __mptr = (struct ldv_list_head const *)ldv_global_msg_list.next; + msg = (struct ldv_msg *)((char *)__mptr - (size_t)(&((struct ldv_msg *)0)->list)); + __mptr___0 = (struct ldv_list_head const *)msg->list.next; + n = (struct ldv_msg *)((char *)__mptr___0 - (size_t)(&((struct ldv_msg *)0)->list)); + + if (!((unsigned long)(&msg->list) != (unsigned long)(&ldv_global_msg_list))) { // NOWARN + goto loop_end; + } + + ldv_list_del(&msg->list); + ldv_msg_free(msg); + msg = n; + __mptr___1 = (struct ldv_list_head const *)n->list.next; + n = (struct ldv_msg *)((char *)__mptr___1 - (size_t)(&((struct ldv_msg *)0)->list)); + + loop_continue_0: /* CIL Label */; + { + while (1) { + while_continue: /* CIL Label */; + if (!((unsigned long)(&msg->list) != (unsigned long)(&ldv_global_msg_list))) { + goto while_break; + } + + ldv_list_del(&msg->list); + ldv_msg_free(msg); + msg = n; + __mptr___1 = (struct ldv_list_head const *)n->list.next; + n = (struct ldv_msg *)((char *)__mptr___1 - (size_t)(&((struct ldv_msg *)0)->list)); + } + while_break: /* CIL Label */; + } + loop_end: /* CIL Label */; + return; +} \ No newline at end of file From 44600c993976793a79c89177c68abc3b543a863d Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 14 Jun 2024 13:04:05 +0300 Subject: [PATCH 354/689] Binops on offsets should not generate overflow warnings in SV-COMP --- src/cdomain/value/cdomains/offset.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/offset.ml b/src/cdomain/value/cdomains/offset.ml index 9c9c5c3333..fa64f71daa 100644 --- a/src/cdomain/value/cdomains/offset.ml +++ b/src/cdomain/value/cdomains/offset.ml @@ -223,9 +223,10 @@ struct | _ -> (None, Idx.top ()) in - let bits_offset = Idx.mul item_size_in_bits x in + (* Binary operations on offsets should not generate overflow warnings in SV-COMP *) + let bits_offset = GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> Idx.mul item_size_in_bits x in let remaining_offset = offset_to_index_offset ?typ:item_typ o in - Idx.add bits_offset remaining_offset + GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> Idx.add bits_offset remaining_offset in offset_to_index_offset ?typ offs From e286a48decb04641f2e9bbe7fa1b96d1ba845293 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 13:50:46 +0300 Subject: [PATCH 355/689] Make YAML witness location function optional In updated version 2.0 schema. --- src/witness/yamlWitness.ml | 2 +- src/witness/yamlWitnessType.ml | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 42254f30de..f5a8ae94e2 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -48,7 +48,7 @@ struct file_hash = sha256_file loc.file; line = loc.line; column = loc.column; - function_ = location_function; + function_ = Some location_function; } let invariant invariant: Invariant.t = { diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 1630e05b69..ff11fcbe9d 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -109,18 +109,23 @@ struct file_hash: string; line: int; column: int; - function_: string; + function_: string option; } [@@deriving ord] let to_yaml {file_name; file_hash; line; column; function_} = - `O [ - ("file_name", `String file_name); - ("file_hash", `String file_hash); - ("line", `Float (float_of_int line)); - ("column", `Float (float_of_int column)); - ("function", `String function_); - ] + `O ([ + ("file_name", `String file_name); + ("file_hash", `String file_hash); + ("line", `Float (float_of_int line)); + ("column", `Float (float_of_int column)); + ] @ match function_ with + | Some function_ -> [ + ("function", `String function_); + ] + | None -> + [] + ) let of_yaml y = let open GobYaml in @@ -128,7 +133,7 @@ struct and+ file_hash = y |> find "file_hash" >>= to_string and+ line = y |> find "line" >>= to_int and+ column = y |> find "column" >>= to_int - and+ function_ = y |> find "function" >>= to_string in + and+ function_ = y |> Yaml.Util.find "function" >>= option_map to_string in {file_name; file_hash; line; column; function_} end From 6a3569521a4dec529ceef50d82854db1ed350b0d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 13:55:14 +0300 Subject: [PATCH 356/689] Make YAML witness location column optional In updated version 2.0 schema. --- src/analyses/unassumeAnalysis.ml | 22 +++++----------------- src/witness/yamlWitness.ml | 24 ++++++++++++------------ src/witness/yamlWitnessType.ml | 25 +++++++++++++++---------- 3 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 265e9c6925..ae7a8bc9a8 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -71,18 +71,6 @@ struct | _ -> () ); - let loc_of_location (location: YamlWitnessType.Location.t): Cil.location = { - file = location.file_name; - line = location.line; - column = location.column; - byte = -1; - endLine = -1; - endColumn = -1; - endByte = -1; - synthetic = false; - } - in - let yaml = match Yaml_unix.of_file (Fpath.v (GobConfig.get_string "witness.yaml.unassume")) with | Ok yaml -> yaml | Error (`Msg m) -> failwith ("Yaml_unix.of_file: " ^ m) @@ -123,7 +111,7 @@ struct in let unassume_location_invariant (location_invariant: YamlWitnessType.LocationInvariant.t) = - let loc = loc_of_location location_invariant.location in + let loc = YamlWitness.loc_of_location location_invariant.location in let inv = location_invariant.location_invariant.string in let msgLoc: M.Location.t = CilLocation loc in @@ -135,7 +123,7 @@ struct in let unassume_loop_invariant (loop_invariant: YamlWitnessType.LoopInvariant.t) = - let loc = loc_of_location loop_invariant.location in + let loc = YamlWitness.loc_of_location loop_invariant.location in let inv = loop_invariant.loop_invariant.string in let msgLoc: M.Location.t = CilLocation loc in @@ -185,7 +173,7 @@ struct in let unassume_precondition_loop_invariant (precondition_loop_invariant: YamlWitnessType.PreconditionLoopInvariant.t) = - let loc = loc_of_location precondition_loop_invariant.location in + let loc = YamlWitness.loc_of_location precondition_loop_invariant.location in let pre = precondition_loop_invariant.precondition.string in let inv = precondition_loop_invariant.loop_invariant.string in let msgLoc: M.Location.t = CilLocation loc in @@ -200,7 +188,7 @@ struct let unassume_invariant_set (invariant_set: YamlWitnessType.InvariantSet.t) = let unassume_location_invariant (location_invariant: YamlWitnessType.InvariantSet.LocationInvariant.t) = - let loc = loc_of_location location_invariant.location in + let loc = YamlWitness.loc_of_location location_invariant.location in let inv = location_invariant.value in let msgLoc: M.Location.t = CilLocation loc in @@ -212,7 +200,7 @@ struct in let unassume_loop_invariant (loop_invariant: YamlWitnessType.InvariantSet.LoopInvariant.t) = - let loc = loc_of_location loop_invariant.location in + let loc = YamlWitness.loc_of_location loop_invariant.location in let inv = loop_invariant.value in let msgLoc: M.Location.t = CilLocation loc in diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index f5a8ae94e2..cf6b1dfc44 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -47,7 +47,7 @@ struct file_name = loc.file; file_hash = sha256_file loc.file; line = loc.line; - column = loc.column; + column = Some loc.column; function_ = Some location_function; } @@ -515,6 +515,17 @@ struct end +let loc_of_location (location: YamlWitnessType.Location.t): Cil.location = { + file = location.file_name; + line = location.line; + column = Option.value location.column ~default:1; + byte = -1; + endLine = -1; + endColumn = -1; + endByte = -1; + synthetic = false; +} + module ValidationResult = struct (* constructor order is important for the chain lattice *) @@ -553,17 +564,6 @@ struct module InvariantParser = WitnessUtil.InvariantParser module VR = ValidationResult - let loc_of_location (location: YamlWitnessType.Location.t): Cil.location = { - file = location.file_name; - line = location.line; - column = location.column; - byte = -1; - endLine = -1; - endColumn = -1; - endByte = -1; - synthetic = false; - } - let validate () = let location_locator = Locator.create () in let loop_locator = Locator.create () in diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index ff11fcbe9d..23a0343c18 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -108,7 +108,7 @@ struct file_name: string; file_hash: string; line: int; - column: int; + column: int option; function_: string option; } [@@deriving ord] @@ -118,21 +118,26 @@ struct ("file_name", `String file_name); ("file_hash", `String file_hash); ("line", `Float (float_of_int line)); - ("column", `Float (float_of_int column)); - ] @ match function_ with - | Some function_ -> [ - ("function", `String function_); - ] - | None -> - [] - ) + ] @ (match column with + | Some column -> [ + ("column", `Float (float_of_int column)); + ] + | None -> + [] + ) @ (match function_ with + | Some function_ -> [ + ("function", `String function_); + ] + | None -> + [] + )) let of_yaml y = let open GobYaml in let+ file_name = y |> find "file_name" >>= to_string and+ file_hash = y |> find "file_hash" >>= to_string and+ line = y |> find "line" >>= to_int - and+ column = y |> find "column" >>= to_int + and+ column = y |> Yaml.Util.find "column" >>= option_map to_int and+ function_ = y |> Yaml.Util.find "function" >>= option_map to_string in {file_name; file_hash; line; column; function_} end From b3dd140985c1db0e086bb42b51f5d5a6a045fc92 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 14:03:04 +0300 Subject: [PATCH 357/689] Make YAML witness location file_hash optional Removed from version 2.0 schema. --- src/witness/yamlWitness.ml | 21 ++++++++++++++------- src/witness/yamlWitnessType.ml | 16 +++++++++++----- tests/util/yamlWitnessStrip.ml | 9 +++++++-- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index cf6b1dfc44..d880663547 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -43,13 +43,20 @@ struct specification } - let location ~location:(loc: Cil.location) ~(location_function): Location.t = { - file_name = loc.file; - file_hash = sha256_file loc.file; - line = loc.line; - column = Some loc.column; - function_ = Some location_function; - } + let location ~location:(loc: Cil.location) ~(location_function): Location.t = + let file_hash = + match GobConfig.get_string "witness.yaml.format-version" with + | "0.1" -> Some (sha256_file loc.file) + | "2.0" -> None + | _ -> assert false + in + { + file_name = loc.file; + file_hash; + line = loc.line; + column = Some loc.column; + function_ = Some location_function; + } let invariant invariant: Invariant.t = { string = invariant; diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 23a0343c18..aabf551109 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -106,7 +106,7 @@ module Location = struct type t = { file_name: string; - file_hash: string; + file_hash: string option; line: int; column: int option; function_: string option; @@ -116,9 +116,15 @@ struct let to_yaml {file_name; file_hash; line; column; function_} = `O ([ ("file_name", `String file_name); - ("file_hash", `String file_hash); - ("line", `Float (float_of_int line)); - ] @ (match column with + ] @ (match file_hash with + | Some file_hash -> [ + ("file_hash", `String file_hash); + ] + | None -> + [] + ) @ [ + ("line", `Float (float_of_int line)); + ] @ (match column with | Some column -> [ ("column", `Float (float_of_int column)); ] @@ -135,7 +141,7 @@ struct let of_yaml y = let open GobYaml in let+ file_name = y |> find "file_name" >>= to_string - and+ file_hash = y |> find "file_hash" >>= to_string + and+ file_hash = y |> Yaml.Util.find "file_hash" >>= option_map to_string and+ line = y |> find "line" >>= to_int and+ column = y |> Yaml.Util.find "column" >>= option_map to_int and+ function_ = y |> Yaml.Util.find "function" >>= option_map to_string in diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 8a5046d6ff..1a463d1390 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -10,8 +10,13 @@ struct let strip_file_hashes {entry_type} = let stripped_file_hash = "$FILE_HASH" in - let location_strip_file_hash location: Location.t = - {location with file_hash = stripped_file_hash} + let location_strip_file_hash (location: Location.t): Location.t = + let file_hash = + match location.file_hash with + | Some _ -> Some stripped_file_hash (* TODO: or just map to None always? *) + | None -> None + in + {location with file_hash} in let target_strip_file_hash target: Target.t = {target with file_hash = stripped_file_hash} From 28cff0f0917ecd5d2bd38972b6f0d66369b2d873 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 14:10:45 +0300 Subject: [PATCH 358/689] Make YAML witness waypoint constraint format optional --- src/witness/yamlWitnessType.ml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 159b0eedae..4fc2029801 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -449,20 +449,25 @@ struct struct type t = { value: string; - format: string; + format: string option; } [@@deriving ord] let to_yaml {value; format} = - `O [ - ("value", `String value); - ("format", `String format); - ] + `O ([ + ("value", `String value); + ] @ (match format with + | Some format -> [ + ("format", `String format); + ] + | None -> + [] + )) let of_yaml y = let open GobYaml in let+ value = y |> find "value" >>= to_string - and+ format = y |> find "format" >>= to_string in + and+ format = y |> Yaml.Util.find "format" >>= option_map to_string in {value; format} end @@ -593,8 +598,8 @@ struct let to_yaml {waypoint_type} = `O [ ("waypoint", `O ([ - ("type", `String (WaypointType.waypoint_type waypoint_type)); - ] @ WaypointType.to_yaml' waypoint_type) + ("type", `String (WaypointType.waypoint_type waypoint_type)); + ] @ WaypointType.to_yaml' waypoint_type) ) ] From 1bdb1aec3d0de987c83a3e3ff5ab0514bc965772 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 14:58:32 +0300 Subject: [PATCH 359/689] Add primitive YAML violation_sequence refutation (issue #1301) --- src/config/options.schema.json | 3 ++- src/witness/yamlWitness.ml | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 488fc494b0..95fb1a9ff5 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2574,7 +2574,8 @@ "precondition_loop_invariant", "loop_invariant_certificate", "precondition_loop_invariant_certificate", - "invariant_set" + "invariant_set", + "violation_sequence" ] }, "default": [ diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index d880663547..36e1e2b589 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -802,6 +802,15 @@ struct None in + let validate_violation_sequence (violation_sequence: YamlWitnessType.ViolationSequence.t) = + (* TODO: update cnt-s appropriately (needs access to SV-COMP result pre-witness validation) *) + (* Nothing needs to be checked here! + If program is correct and we can prove it, we output true, which counts as refutation of violation witness. + If program is correct and we cannot prove it, we output unknown. + If program is incorrect, we output unknown. *) + None + in + match entry_type_enabled target_type, entry.entry_type with | true, LocationInvariant x -> validate_location_invariant x @@ -811,7 +820,9 @@ struct validate_precondition_loop_invariant x | true, InvariantSet x -> validate_invariant_set x - | false, (LocationInvariant _ | LoopInvariant _ | PreconditionLoopInvariant _ | InvariantSet _) -> + | true, ViolationSequence x -> + validate_violation_sequence x + | false, (LocationInvariant _ | LoopInvariant _ | PreconditionLoopInvariant _ | InvariantSet _ | ViolationSequence _) -> incr cnt_disabled; M.info_noloc ~category:Witness "disabled entry of type %s" target_type; None From c546f2df8208ac3ff22886e65f64f3eb84c8e044 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 15:00:10 +0300 Subject: [PATCH 360/689] Add svcomp-validate conf for next SV-COMP Compared to svcomp24-validate: 1. Enables abortUnless (like svcomp over svcomp24). 2. Enables YAML violation_sequence validation. --- conf/svcomp-validate.json | 142 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 conf/svcomp-validate.json diff --git a/conf/svcomp-validate.json b/conf/svcomp-validate.json new file mode 100644 index 0000000000..a234aeb0d5 --- /dev/null +++ b/conf/svcomp-validate.json @@ -0,0 +1,142 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless", + "unassume" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "malloc": { + "wrappers": [ + "kmalloc", + "__kmalloc", + "usb_alloc_urb", + "__builtin_alloca", + "kzalloc", + + "ldv_malloc", + + "kzalloc_node", + "ldv_zalloc", + "kmalloc_array", + "kcalloc", + + "ldv_xmalloc", + "ldv_xzalloc", + "ldv_calloc", + "ldv_kzalloc" + ] + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "termination", + "tmpSpecialAnalysis" + ] + }, + "widen": { + "tokens": true + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": false + }, + "yaml": { + "enabled": false, + "strict": true, + "format-version": "2.0", + "entry-types": [ + "location_invariant", + "loop_invariant", + "invariant_set", + "violation_sequence" + ], + "invariant-types": [ + "location_invariant", + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": true, + "other": true + } + }, + "pre": { + "enabled": false + } +} From fccc91efee6c2dc0ad92c3d82946e1b1e994d7d8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 14 Jun 2024 15:57:34 +0300 Subject: [PATCH 361/689] Add cram test for YAML violation witness refutation --- .../witness/violation.t/correct-hard.c | 9 +++ .../witness/violation.t/correct-hard.yml | 26 +++++++++ .../regression/witness/violation.t/correct.c | 5 ++ .../witness/violation.t/correct.yml | 26 +++++++++ .../witness/violation.t/incorrect.c | 6 ++ .../witness/violation.t/incorrect.yml | 26 +++++++++ tests/regression/witness/violation.t/run.t | 57 +++++++++++++++++++ 7 files changed, 155 insertions(+) create mode 100644 tests/regression/witness/violation.t/correct-hard.c create mode 100644 tests/regression/witness/violation.t/correct-hard.yml create mode 100644 tests/regression/witness/violation.t/correct.c create mode 100644 tests/regression/witness/violation.t/correct.yml create mode 100644 tests/regression/witness/violation.t/incorrect.c create mode 100644 tests/regression/witness/violation.t/incorrect.yml create mode 100644 tests/regression/witness/violation.t/run.t diff --git a/tests/regression/witness/violation.t/correct-hard.c b/tests/regression/witness/violation.t/correct-hard.c new file mode 100644 index 0000000000..ce2b50a0c0 --- /dev/null +++ b/tests/regression/witness/violation.t/correct-hard.c @@ -0,0 +1,9 @@ +void reach_error(){} +extern int __VERIFIER_nondet_int(); + +int main() { + int x = __VERIFIER_nondet_int(); + if (x != x) + reach_error(); + return 0; +} diff --git a/tests/regression/witness/violation.t/correct-hard.yml b/tests/regression/witness/violation.t/correct-hard.yml new file mode 100644 index 0000000000..b8af2c2193 --- /dev/null +++ b/tests/regression/witness/violation.t/correct-hard.yml @@ -0,0 +1,26 @@ +- entry_type: violation_sequence + metadata: + format_version: "2.0" + uuid: 4412af70-389a-475e-849c-e57e5b92019e + creation_time: 2024-06-14T15:35:00+03:00 + producer: + name: Simmo Saan + version: n/a + task: + input_files: + - correct-hard.c + input_file_hashes: + correct-hard.c: 5cc49c1ce5a9aef64286c2a6e57f6955c5f4f9b19b43056507ae87a802802447 + specification: G ! call(reach_error()) + data_model: ILP32 + language: C + content: + - segment: + - waypoint: + type: target + action: follow + location: + file_name: correct-hard.c + line: 7 + column: 5 + function: main diff --git a/tests/regression/witness/violation.t/correct.c b/tests/regression/witness/violation.t/correct.c new file mode 100644 index 0000000000..30f58a2f7e --- /dev/null +++ b/tests/regression/witness/violation.t/correct.c @@ -0,0 +1,5 @@ +void reach_error(){} + +int main() { + return 0; +} diff --git a/tests/regression/witness/violation.t/correct.yml b/tests/regression/witness/violation.t/correct.yml new file mode 100644 index 0000000000..1f1d4f41da --- /dev/null +++ b/tests/regression/witness/violation.t/correct.yml @@ -0,0 +1,26 @@ +- entry_type: violation_sequence + metadata: + format_version: "2.0" + uuid: 4412af70-389a-475e-849c-e57e5b92019d + creation_time: 2024-06-14T15:35:00+03:00 + producer: + name: Simmo Saan + version: n/a + task: + input_files: + - correct.c + input_file_hashes: + correct.c: 6f760cf7f33fc152738bf3514fe623cc94e52cad9ddc2f0e744595ce0de07530 + specification: G ! call(reach_error()) + data_model: ILP32 + language: C + content: + - segment: + - waypoint: + type: target + action: follow + location: + file_name: correct.c + line: 4 + column: 3 + function: main diff --git a/tests/regression/witness/violation.t/incorrect.c b/tests/regression/witness/violation.t/incorrect.c new file mode 100644 index 0000000000..ff56fa2ef4 --- /dev/null +++ b/tests/regression/witness/violation.t/incorrect.c @@ -0,0 +1,6 @@ +void reach_error(){} + +int main() { + reach_error(); + return 0; +} diff --git a/tests/regression/witness/violation.t/incorrect.yml b/tests/regression/witness/violation.t/incorrect.yml new file mode 100644 index 0000000000..dd57ce3ca1 --- /dev/null +++ b/tests/regression/witness/violation.t/incorrect.yml @@ -0,0 +1,26 @@ +- entry_type: violation_sequence + metadata: + format_version: "2.0" + uuid: 4412af70-389a-475e-849c-e57e5b92019c + creation_time: 2024-06-14T15:35:00+03:00 + producer: + name: Simmo Saan + version: n/a + task: + input_files: + - incorrect.c + input_file_hashes: + incorrect.c: 1af4fd9e76418e4b95af9950b58248127e7c2d9eb791e1c9b92da53952e0fca2 + specification: G ! call(reach_error()) + data_model: ILP32 + language: C + content: + - segment: + - waypoint: + type: target + action: follow + location: + file_name: incorrect.c + line: 4 + column: 3 + function: main diff --git a/tests/regression/witness/violation.t/run.t b/tests/regression/witness/violation.t/run.t new file mode 100644 index 0000000000..1fc408635e --- /dev/null +++ b/tests/regression/witness/violation.t/run.t @@ -0,0 +1,57 @@ +Violation witness for a correct program can be refuted by proving the program correct and returning `true`: + + $ goblint --enable ana.sv-comp.enabled --set witness.yaml.entry-types[+] violation_sequence --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" correct.c --set witness.yaml.validate correct.yml + [Info] SV-COMP specification: CHECK( init(main()), LTL(G ! call(reach_error())) ) + [Warning][Deadcode] Function 'reach_error' is uncalled: 1 LLoC (correct.c:1:1-1:20) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 2 + dead: 1 (1 in uncalled functions) + total lines: 3 + [Info][Witness] witness validation summary: + confirmed: 0 + unconfirmed: 0 + refuted: 0 + error: 0 + unchecked: 0 + unsupported: 0 + disabled: 0 + total validation entries: 0 + SV-COMP result: true + +If a correct progtam cannot be proven correct, return `unknown` for the violation witness: + + $ goblint --set ana.activated[-] expRelation --enable ana.sv-comp.functions --enable ana.sv-comp.enabled --set witness.yaml.entry-types[+] violation_sequence --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" correct-hard.c --set witness.yaml.validate correct-hard.yml + [Info] SV-COMP specification: CHECK( init(main()), LTL(G ! call(reach_error())) ) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 0 + total lines: 7 + [Info][Witness] witness validation summary: + confirmed: 0 + unconfirmed: 0 + refuted: 0 + error: 0 + unchecked: 0 + unsupported: 0 + disabled: 0 + total validation entries: 0 + SV-COMP result: unknown + +Violation witness for an incorrect program cannot be proven correct, so return `unknown`: + + $ goblint --enable ana.sv-comp.enabled --set witness.yaml.entry-types[+] violation_sequence --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" incorrect.c --set witness.yaml.validate incorrect.yml + [Info] SV-COMP specification: CHECK( init(main()), LTL(G ! call(reach_error())) ) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 4 + dead: 0 + total lines: 4 + [Info][Witness] witness validation summary: + confirmed: 0 + unconfirmed: 0 + refuted: 0 + error: 0 + unchecked: 0 + unsupported: 0 + disabled: 0 + total validation entries: 0 + SV-COMP result: unknown From 8920200c71df4a855d22ef7f330eadad64aca205 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Mon, 17 Jun 2024 13:34:41 +0200 Subject: [PATCH 362/689] next try --- src/cdomains/apron/sharedFunctions.apron.ml | 53 ++++++++++++++------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 7c69cefda4..1bcc6d7202 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -6,15 +6,8 @@ open GobApron module M = Messages -let frac_of_scalar scalar = - if Scalar.is_infty scalar <> 0 then (* infinity means unbounded *) - None - else match scalar with - | Float f -> if Stdlib.Float.is_integer f then Some (Q.of_float f) else None - | Mpqf f -> Some (Z_mlgmpidl.q_of_mpqf f) - | _ -> failwith "frac_of_scalar: unsupported" -let int_of_scalar ?round (scalar: Scalar.t) = +let int_of_scalar ?(scalewith=Z.one) ?round (scalar: Scalar.t) = if Scalar.is_infty scalar <> 0 then (* infinity means unbounded *) None else @@ -28,18 +21,19 @@ let int_of_scalar ?round (scalar: Scalar.t) = | None when Stdlib.Float.is_integer f -> Some f | None -> None in - Z.of_float f + Z.(of_float f * scalewith) | Mpqf scalar -> (* octMPQ, boxMPQ, polkaMPQ *) let n = Mpqf.get_num scalar in let d = Mpqf.get_den scalar in + let scale = Z_mlgmpidl.mpz_of_z scalewith in let+ z = if Mpzf.cmp_int d 1 = 0 then (* exact integer (denominator 1) *) - Some n + Some (Mpzf.mul scale n) else begin match round with - | Some `Floor -> Some (Mpzf.fdiv_q n d) (* floor division *) - | Some `Ceil -> Some (Mpzf.cdiv_q n d) (* ceiling division *) - | None -> None + | Some `Floor -> Some (Mpzf.mul scale (Mpzf.fdiv_q n d)) (* floor division *) + | Some `Ceil -> Some (Mpzf.mul scale (Mpzf.cdiv_q n d)) (* ceiling division *) + | None -> Some (Mpzf.divexact (Mpzf.mul scale n ) d) (* scale, preferably with common denominator *) end in Z_mlgmpidl.z_of_mpzf z @@ -246,11 +240,11 @@ module CilOfApron (V: SV) = struct exception Unsupported_Linexpr1 - let cil_exp_of_linexpr1 (linexpr1:Linexpr1.t) = + let cil_exp_of_linexpr1 ?(scalewith=Z.one) (linexpr1:Linexpr1.t) = let longlong = TInt(ILongLong,[]) in let coeff_to_const consider_flip (c:Coeff.union_5) = match c with | Scalar c -> - (match int_of_scalar c with + (match int_of_scalar ~scalewith:scalewith c with | Some i -> let ci,truncation = truncateCilint ILongLong i in if truncation = NoTruncation then @@ -286,11 +280,38 @@ struct !expr + let lcm_den linexpr1 = + let exception UnsupportedScalar + in + let frac_of_scalar scalar = + if Scalar.is_infty scalar <> 0 then (* infinity means unbounded *) + None + else match scalar with + | Float f -> if Stdlib.Float.is_integer f then Some (Q.of_float f) else None + | Mpqf f -> Some (Z_mlgmpidl.q_of_mpqf f) + | _ -> raise UnsupportedScalar + in + let extract_den (c:Coeff.union_5) _ = + match c with + | Scalar c -> BatOption.map (fun q -> Q.den q) (frac_of_scalar c) + | _ -> None + in + let lcm_denom = ref (BatOption.default Z.one (extract_den (Linexpr1.get_cst linexpr1) ())) in + let lcm_coeff (c:Coeff.union_5) v = + match (extract_den c v) with + | Some z -> lcm_denom := Z.lcm z !lcm_denom + | _ -> () + in + try + Linexpr1.iter lcm_coeff linexpr1; !lcm_denom + with UnsupportedScalar -> Z.one + let cil_exp_of_lincons1 (lincons1:Lincons1.t) = let zero = Cil.kinteger ILongLong 0 in try let linexpr1 = Lincons1.get_linexpr1 lincons1 in - let cilexp = cil_exp_of_linexpr1 linexpr1 in + let common_denominator = lcm_den linexpr1 in + let cilexp = cil_exp_of_linexpr1 ~scalewith:common_denominator linexpr1 in match Lincons1.get_typ lincons1 with | EQ -> Some (Cil.constFold false @@ BinOp(Eq, cilexp, zero, TInt(IInt,[]))) | SUPEQ -> Some (Cil.constFold false @@ BinOp(Ge, cilexp, zero, TInt(IInt,[]))) From 2fefea01a7816968035328557d060cd5f61f5407 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 20:52:18 +0000 Subject: [PATCH 363/689] Bump docker/build-push-action from 5 to 6 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 4 ++-- .github/workflows/unlocked.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 36568e6cb2..daa7f224b8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -59,7 +59,7 @@ jobs: - name: Build Docker image id: build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . load: true # load into docker instead of immediately pushing @@ -72,7 +72,7 @@ jobs: run: docker run --rm -v $(pwd):/data ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} /data/tests/regression/04-mutex/01-simple_rc.c # run image by version in case multiple tags - name: Push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index db41ad3007..f1bd399a17 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -165,7 +165,7 @@ jobs: - name: Build dev Docker image id: build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . target: dev From a7e4ff18c7a5f15d0bc03bcf9caa1b402d39b381 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 18 Jun 2024 10:57:24 +0200 Subject: [PATCH 364/689] Update src/cdomains/apron/sharedFunctions.apron.ml Co-authored-by: Simmo Saan --- src/cdomains/apron/sharedFunctions.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index f3cdf6f8ba..17fdb2175c 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -300,7 +300,7 @@ struct in let extract_den (c:Coeff.union_5) _ = match c with - | Scalar c -> BatOption.map (fun q -> Q.den q) (frac_of_scalar c) + | Scalar c -> BatOption.map Q.den (frac_of_scalar c) | _ -> None in let lcm_denom = ref (BatOption.default Z.one (extract_den (Linexpr1.get_cst linexpr1) ())) in From 7876d6b3c38f79c50d1361e62d8ab20f0d2e49fe Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 18 Jun 2024 10:58:06 +0200 Subject: [PATCH 365/689] Update src/cdomains/apron/sharedFunctions.apron.ml Co-authored-by: Simmo Saan --- src/cdomains/apron/sharedFunctions.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 17fdb2175c..656fe0b9bd 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -251,7 +251,7 @@ struct let longlong = TInt(ILongLong,[]) in let coeff_to_const consider_flip (c:Coeff.union_5) = match c with | Scalar c -> - (match int_of_scalar ~scalewith:scalewith c with + (match int_of_scalar ?scalewith c with | Some i -> let ci,truncation = truncateCilint ILongLong i in if truncation = NoTruncation then From e4cd4df9d9f3c6678596060c11efd058466d0f6d Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 18 Jun 2024 10:58:17 +0200 Subject: [PATCH 366/689] Update src/cdomains/apron/sharedFunctions.apron.ml Co-authored-by: Simmo Saan --- src/cdomains/apron/sharedFunctions.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 656fe0b9bd..022e60200d 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -247,7 +247,7 @@ module CilOfApron (V: SV) = struct exception Unsupported_Linexpr1 - let cil_exp_of_linexpr1 ?(scalewith=Z.one) (linexpr1:Linexpr1.t) = + let cil_exp_of_linexpr1 ?scalewith (linexpr1:Linexpr1.t) = let longlong = TInt(ILongLong,[]) in let coeff_to_const consider_flip (c:Coeff.union_5) = match c with | Scalar c -> From 4812b07e58b7c854e2fc4c25763101cb73800e69 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 18 Jun 2024 13:41:00 +0300 Subject: [PATCH 367/689] Avoid unused value warning on LibraryFunctions.all_library_descs --- src/util/library/libraryFunctions.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 4e678c926e..e7ff2a4d04 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1246,7 +1246,7 @@ let libraries = descs_tbl ) libraries -let all_library_descs: (string, LibraryDesc.t) Hashtbl.t = +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 From d5f67cb1d1c811a8b207e4095deebc7836d302e9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 18 Jun 2024 15:49:36 +0300 Subject: [PATCH 368/689] Fix ctx.split and ctx.spawn in non-call transfer functions Since OCaml evaluates arguments right-to-left, !r and !spawns are dereferenced before calling the transfer function, which will populate them (uselessly). By using let, evaluation order is enforced. --- src/framework/constraints.ml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index e0e36801ed..7df4167acd 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -713,11 +713,13 @@ struct let tf_assign var edge prev_node lv e getl sidel getg sideg d = let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - common_join ctx (S.assign ctx lv e) !r !spawns + let d = S.assign ctx lv e in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) + common_join ctx d !r !spawns let tf_vdecl var edge prev_node v getl sidel getg sideg d = let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - common_join ctx (S.vdecl ctx v) !r !spawns + let d = S.vdecl ctx v in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) + common_join ctx d !r !spawns let normal_return r fd ctx sideg = let spawning_return = S.return ctx r fd in @@ -732,7 +734,7 @@ struct let tf_ret var edge prev_node ret fd getl sidel getg sideg d = let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = + let d = (* Force transfer function to be evaluated before dereferencing in common_join argument. *) if (CilType.Fundec.equal fd MyCFG.dummy_func || List.mem fd.svar.vname (get_string_list "mainfun")) && get_bool "kernel" @@ -747,11 +749,13 @@ struct let c: unit -> S.C.t = snd var |> Obj.obj in side_context sideg fd (c ()); let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - common_join ctx (S.body ctx fd) !r !spawns + let d = S.body ctx fd in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) + common_join ctx d !r !spawns let tf_test var edge prev_node e tv getl sidel getg sideg d = let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - common_join ctx (S.branch ctx e tv) !r !spawns + let d = S.branch ctx e tv in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) + common_join ctx d !r !spawns let tf_normal_call ctx lv e (f:fundec) args getl sidel getg sideg = let combine (cd, fc, fd) = @@ -870,11 +874,13 @@ struct let tf_asm var edge prev_node getl sidel getg sideg d = let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - common_join ctx (S.asm ctx) !r !spawns + let d = S.asm ctx in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) + common_join ctx d !r !spawns let tf_skip var edge prev_node getl sidel getg sideg d = let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - common_join ctx (S.skip ctx) !r !spawns + let d = S.skip ctx in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) + common_join ctx d !r !spawns let tf var getl sidel getg sideg prev_node edge d = begin match edge with From 7fcb10cd0fcb4c4f68d43a7bb60fec9d7cfc64d5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 18 Jun 2024 17:20:55 +0300 Subject: [PATCH 369/689] Handle pthread_rwlock_t as opaque mutex in base analysis Avoids unsound rwlock struct content invariants in witnesses. --- src/cdomain/value/cdomains/valueDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/valueDomain.ml b/src/cdomain/value/cdomains/valueDomain.ml index de64fde807..09593fb614 100644 --- a/src/cdomain/value/cdomains/valueDomain.ml +++ b/src/cdomain/value/cdomains/valueDomain.ml @@ -120,7 +120,7 @@ struct | _ -> false let is_mutex_type (t: typ): bool = match t with - | TNamed (info, attr) -> info.tname = "pthread_mutex_t" || info.tname = "spinlock_t" || info.tname = "pthread_spinlock_t" || info.tname = "pthread_cond_t" + | TNamed (info, attr) -> info.tname = "pthread_mutex_t" || info.tname = "spinlock_t" || info.tname = "pthread_spinlock_t" || info.tname = "pthread_cond_t" || info.tname = "pthread_rwlock_t" | TInt (IInt, attr) -> hasAttribute "mutex" attr | _ -> false From 62f01a9778ccc61b3894a292a522ee397394ab5f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 18 Jun 2024 18:05:57 +0300 Subject: [PATCH 370/689] Add cram test for int witness invariants --- tests/regression/witness/int.t/int.c | 17 ++++++++++ tests/regression/witness/int.t/run.t | 47 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/regression/witness/int.t/int.c create mode 100644 tests/regression/witness/int.t/run.t diff --git a/tests/regression/witness/int.t/int.c b/tests/regression/witness/int.t/int.c new file mode 100644 index 0000000000..4ad15b09ad --- /dev/null +++ b/tests/regression/witness/int.t/int.c @@ -0,0 +1,17 @@ +#include +extern int __VERIFIER_nondet_int(); + +int main() { + int i; + i = __VERIFIER_nondet_int(); + + if (i < 100) + __goblint_check(1); + + if (50 < i && i < 100) + __goblint_check(1); + + if (i == 42 || i == 5 || i == 101) + __goblint_check(1); + return 0; +} diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t new file mode 100644 index 0000000000..28c670d475 --- /dev/null +++ b/tests/regression/witness/int.t/run.t @@ -0,0 +1,47 @@ + $ goblint --enable ana.sv-comp.functions --enable witness.yaml.enabled --set witness.yaml.entry-types '["location_invariant"]' --enable ana.int.def_exc --enable ana.int.enums --enable ana.int.interval --enable ana.int.congruence --enable ana.int.interval_set --disable witness.invariant.split-conjunction int.c + [Success][Assert] Assertion "1" will succeed (int.c:9:5-9:23) + [Success][Assert] Assertion "1" will succeed (int.c:12:5-12:23) + [Success][Assert] Assertion "1" will succeed (int.c:15:5-15:23) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 10 + dead: 0 + total lines: 10 + [Info][Witness] witness generation summary: + total generation entries: 3 + + $ yamlWitnessStrip < witness.yml + - entry_type: location_invariant + location: + file_name: int.c + file_hash: $FILE_HASH + line: 15 + column: 5 + function: main + location_invariant: + string: ((((0 <= i && i <= 127) && i != 0) && (5 <= i && i <= 101)) && ((i == + 5 || i == 42) || i == 101)) && ((i == 5 || i == 42) || i == 101) + type: assertion + format: C + - entry_type: location_invariant + location: + file_name: int.c + file_hash: $FILE_HASH + line: 12 + column: 5 + function: main + location_invariant: + string: (((0 <= i && i != 0) && (51 <= i && i <= 99)) && (0 <= i && i != 0)) && + (51 <= i && i <= 99) + type: assertion + format: C + - entry_type: location_invariant + location: + file_name: int.c + file_hash: $FILE_HASH + line: 9 + column: 5 + function: main + location_invariant: + string: i <= 99 && i <= 99 + type: assertion + format: C From ca5f0646bc18d055d36501b9db5ca72d09854818 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 11:25:32 +0300 Subject: [PATCH 371/689] Extract inclusion list invariant in IntDomain --- src/cdomain/value/cdomains/intDomain.ml | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index c525732d3b..89be71ea92 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -582,6 +582,24 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct List.exists (Z.equal l) ts end +module IntInvariant = +struct + let of_incl_list e ik ps = + match ps with + | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> + assert (List.mem Z.zero ps); + assert (List.mem Z.one ps); + Invariant.none + | [_] when get_bool "witness.invariant.exact" -> + Invariant.none + | _ :: _ :: _ + | [_] | [] -> + List.fold_left (fun a x -> + let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in + Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) (Invariant.bot ()) ps +end + module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = struct let name () = "intervals" @@ -2731,19 +2749,11 @@ module Enums : S with type int_t = Z.t = struct let ne ik x y = c_lognot ik (eq ik x y) let invariant_ikind e ik x = - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in match x with - | Inc ps when not inexact_type_bounds && ik = IBool && is_top_of ik x -> - Invariant.none | Inc ps -> - if BISet.cardinal ps > 1 || get_bool "witness.invariant.exact" then - BISet.fold (fun x a -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) ps (Invariant.bot ()) - else - Invariant.top () + IntInvariant.of_incl_list e ik (BISet.elements ps) | Exc (ns, r) -> + let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in (* Emit range invariant if tighter than ikind bounds. This can be more precise than interval, which has been widened. *) let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in From e767f90fdcce9eb4348341129915a515d2539d4e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 11:26:43 +0300 Subject: [PATCH 372/689] Simplify inclusion list invariants --- src/cdomain/value/cdomains/intDomain.ml | 12 ++++++---- .../56-witness/46-top-bool-invariant.t | 24 +------------------ tests/regression/witness/int.t/run.t | 3 +-- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 89be71ea92..b9723bdb5b 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -3797,10 +3797,14 @@ module IntDomTupleImpl = struct else Invariant.top () | None -> - let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x) - in List.fold_left (fun a i -> - Invariant.(a && i) - ) (Invariant.top ()) is + match to_incl_list x with + | Some ps -> + IntInvariant.of_incl_list e ik ps + | None -> + let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x) + in List.fold_left (fun a i -> + Invariant.(a && i) + ) (Invariant.top ()) is let arbitrary ik = QCheck.(set_print show @@ tup5 (option (I1.arbitrary ik)) (option (I2.arbitrary ik)) (option (I3.arbitrary ik)) (option (I4.arbitrary ik)) (option (I5.arbitrary ik))) diff --git a/tests/regression/56-witness/46-top-bool-invariant.t b/tests/regression/56-witness/46-top-bool-invariant.t index b04d33dda8..741b00966f 100644 --- a/tests/regression/56-witness/46-top-bool-invariant.t +++ b/tests/regression/56-witness/46-top-bool-invariant.t @@ -144,7 +144,7 @@ all: dead: 0 total lines: 2 [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 1 $ yamlWitnessStrip < witness.yml - entry_type: location_invariant @@ -158,28 +158,6 @@ all: string: x == (_Bool)0 || x == (_Bool)1 type: assertion format: C - - entry_type: location_invariant - location: - file_name: 46-top-bool-invariant.c - file_hash: $FILE_HASH - line: 5 - column: 3 - function: main - location_invariant: - string: x <= (_Bool)1 - type: assertion - format: C - - entry_type: location_invariant - location: - file_name: 46-top-bool-invariant.c - file_hash: $FILE_HASH - line: 5 - column: 3 - function: main - location_invariant: - string: (_Bool)0 <= x - type: assertion - format: C all without inexact-type-bounds: diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t index 28c670d475..6f75a2cd17 100644 --- a/tests/regression/witness/int.t/run.t +++ b/tests/regression/witness/int.t/run.t @@ -18,8 +18,7 @@ column: 5 function: main location_invariant: - string: ((((0 <= i && i <= 127) && i != 0) && (5 <= i && i <= 101)) && ((i == - 5 || i == 42) || i == 101)) && ((i == 5 || i == 42) || i == 101) + string: (i == 5 || i == 42) || i == 101 type: assertion format: C - entry_type: location_invariant From 176941d1a1582f45eec20ad5d3f9c1d648bffc7d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 11:34:09 +0300 Subject: [PATCH 373/689] Extract definite int invariant in IntDomain --- src/cdomain/value/cdomains/intDomain.ml | 29 ++++++++++--------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index b9723bdb5b..f0715c2e57 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -584,6 +584,12 @@ end module IntInvariant = struct + let of_int e ik x = + if get_bool "witness.invariant.exact" then + Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) + else + Invariant.none + let of_incl_list e ik ps = match ps with | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> @@ -936,11 +942,7 @@ struct let invariant_ikind e ik x = match x with | Some (x1, x2) when Ints_t.compare x1 x2 = 0 -> - if get_bool "witness.invariant.exact" then - let x1 = Ints_t.to_bigint x1 in - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x1, intType)) - else - Invariant.top () + IntInvariant.of_int e ik (Ints_t.to_bigint x1) | Some (x1, x2) -> let (min_ik, max_ik) = range ik in let (x1', x2') = BatTuple.Tuple2.mapn (Ints_t.to_bigint) (x1, x2) in @@ -2315,10 +2317,7 @@ struct let invariant_ikind e ik (x:t) = match x with | `Definite x -> - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.top () + IntInvariant.of_int e ik x | `Excluded (s, r) -> (* Emit range invariant if tighter than ikind bounds. This can be more precise than interval, which has been widened. *) @@ -3253,10 +3252,7 @@ struct match x with | x when is_top x -> Invariant.top () | Some (c, m) when m =: Z.zero -> - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, Cil.kintegerCilint ik c, intType)) - else - Invariant.top () + IntInvariant.of_int e ik c | Some (c, m) -> let open Cil in let (c, m) = BatTuple.Tuple2.mapn (fun a -> kintegerCilint ik a) (c, m) in @@ -3791,11 +3787,8 @@ module IntDomTupleImpl = struct let invariant_ikind e ik x = match to_int x with | Some v -> - if get_bool "witness.invariant.exact" then - (* If definite, output single equality instead of every subdomain repeating same equality *) - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik v, intType)) - else - Invariant.top () + (* If definite, output single equality instead of every subdomain repeating same equality *) + IntInvariant.of_int e ik v | None -> match to_incl_list x with | Some ps -> From 250196bfb9ee6f2cd2195cc9b46b1c275452a731 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 11:44:39 +0300 Subject: [PATCH 374/689] Extract interval invariant in IntDomain --- src/cdomain/value/cdomains/intDomain.ml | 44 ++++++++++--------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index f0715c2e57..bdd403bbce 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -604,6 +604,17 @@ struct let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) (Invariant.bot ()) ps + + let of_interval e ik (x1, x2) = + if Z.equal x1 x2 then + of_int e ik x1 + else ( + let (min_ik, max_ik) = Size.range ik in + let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in + let i1 = if inexact_type_bounds || Z.compare min_ik x1 <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) else Invariant.none in + let i2 = if inexact_type_bounds || Z.compare x2 max_ik <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) else Invariant.none in + Invariant.(i1 && i2) + ) end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = @@ -939,17 +950,10 @@ struct else if Ints_t.compare y2 x1 <= 0 then of_bool ik false else top_bool - let invariant_ikind e ik x = - match x with - | Some (x1, x2) when Ints_t.compare x1 x2 = 0 -> - IntInvariant.of_int e ik (Ints_t.to_bigint x1) + let invariant_ikind e ik = function | Some (x1, x2) -> - let (min_ik, max_ik) = range ik in - let (x1', x2') = BatTuple.Tuple2.mapn (Ints_t.to_bigint) (x1, x2) in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = if inexact_type_bounds || Ints_t.compare min_ik x1 <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1', e, intType)) else Invariant.none in - let i2 = if inexact_type_bounds || Ints_t.compare x2 max_ik <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2', intType)) else Invariant.none in - Invariant.(i1 && i2) + let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in + IntInvariant.of_interval e ik (x1', x2') | None -> Invariant.none let arbitrary ik = @@ -2322,17 +2326,11 @@ struct (* Emit range invariant if tighter than ikind bounds. This can be more precise than interval, which has been widened. *) let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let (ikmin, ikmax) = - let ikr = size ik in - (Exclusion.min_of_range ikr, Exclusion.max_of_range ikr) - in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let imin = if inexact_type_bounds || Z.compare ikmin rmin <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik rmin, e, intType)) else Invariant.none in - let imax = if inexact_type_bounds || Z.compare rmax ikmax <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik rmax, intType)) else Invariant.none in + let ri = IntInvariant.of_interval e ik (rmin, rmax) in S.fold (fun x a -> let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in Invariant.(a && i) - ) s Invariant.(imin && imax) + ) s ri | `Bot -> Invariant.none let arbitrary ik = @@ -2752,20 +2750,14 @@ module Enums : S with type int_t = Z.t = struct | Inc ps -> IntInvariant.of_incl_list e ik (BISet.elements ps) | Exc (ns, r) -> - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in (* Emit range invariant if tighter than ikind bounds. This can be more precise than interval, which has been widened. *) let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let (ikmin, ikmax) = - let ikr = size ik in - (Exclusion.min_of_range ikr, Exclusion.max_of_range ikr) - in - let imin = if inexact_type_bounds || Z.compare ikmin rmin <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik rmin, e, intType)) else Invariant.none in - let imax = if inexact_type_bounds || Z.compare rmax ikmax <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik rmax, intType)) else Invariant.none in + let ri = IntInvariant.of_interval e ik (rmin, rmax) in BISet.fold (fun x a -> let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in Invariant.(a && i) - ) ns Invariant.(imin && imax) + ) ns ri let arbitrary ik = From 9a25b4859c45671b416281784e26f8e1781ca7b2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 11:49:15 +0300 Subject: [PATCH 375/689] Extract exclusion list invariant in IntDomain --- src/cdomain/value/cdomains/intDomain.ml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index bdd403bbce..79c672f689 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -615,6 +615,12 @@ struct let i2 = if inexact_type_bounds || Z.compare x2 max_ik <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) else Invariant.none in Invariant.(i1 && i2) ) + + let of_excl_list e ik ns = + List.fold_left (fun a x -> + let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in + Invariant.(a && i) + ) (Invariant.top ()) ns end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = @@ -2327,10 +2333,8 @@ struct This can be more precise than interval, which has been widened. *) let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in let ri = IntInvariant.of_interval e ik (rmin, rmax) in - S.fold (fun x a -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) s ri + let si = IntInvariant.of_excl_list e ik (S.elements s) in + Invariant.(ri && si) | `Bot -> Invariant.none let arbitrary ik = @@ -2754,10 +2758,8 @@ module Enums : S with type int_t = Z.t = struct This can be more precise than interval, which has been widened. *) let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in let ri = IntInvariant.of_interval e ik (rmin, rmax) in - BISet.fold (fun x a -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) ns ri + let nsi = IntInvariant.of_excl_list e ik (BISet.elements ns) in + Invariant.(ri && nsi) let arbitrary ik = From d1f04bc23150d0b186d52f1ccaf170f54916bd8f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 12:35:20 +0300 Subject: [PATCH 376/689] Simplify interval and exclusion list invariants --- src/cdomain/value/cdomains/intDomain.ml | 39 ++++++++++++++++++------- tests/regression/cfg/foo.t/run.t | 24 +-------------- tests/regression/witness/int.t/run.t | 3 +- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 79c672f689..8860a8fbb5 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -605,16 +605,28 @@ struct Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) (Invariant.bot ()) ps - let of_interval e ik (x1, x2) = - if Z.equal x1 x2 then + let of_interval_opt e ik = function + | (Some x1, Some x2) when Z.equal x1 x2 -> of_int e ik x1 - else ( + | x1_opt, x2_opt -> let (min_ik, max_ik) = Size.range ik in let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = if inexact_type_bounds || Z.compare min_ik x1 <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) else Invariant.none in - let i2 = if inexact_type_bounds || Z.compare x2 max_ik <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) else Invariant.none in + let i1 = + match x1_opt, inexact_type_bounds with + | Some x1, false when Z.equal min_ik x1 -> Invariant.none + | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) + | None, _ -> Invariant.none + in + let i2 = + match x2_opt, inexact_type_bounds with + | Some x2, false when Z.equal x2 max_ik -> Invariant.none + | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) + | None, _ -> Invariant.none + in Invariant.(i1 && i2) - ) + + let of_interval e ik (x1, x2) = + of_interval_opt e ik (Some x1, Some x2) let of_excl_list e ik ns = List.fold_left (fun a x -> @@ -3778,7 +3790,7 @@ module IntDomTupleImpl = struct | Some v when not (GobConfig.get_bool "dbg.full-output") -> BatPrintf.fprintf f "\n\n%s\n\n\n" (Z.to_string v) | _ -> BatPrintf.fprintf f "\n\n%s\n\n\n" (show x) - let invariant_ikind e ik x = + let invariant_ikind e ik ((_, _, _, x_cong, x_intset) as x) = match to_int x with | Some v -> (* If definite, output single equality instead of every subdomain repeating same equality *) @@ -3788,10 +3800,15 @@ module IntDomTupleImpl = struct | Some ps -> IntInvariant.of_incl_list e ik ps | None -> - let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x) - in List.fold_left (fun a i -> - Invariant.(a && i) - ) (Invariant.top ()) is + let min = minimal x in + let max = maximal x in + let ns = Option.map fst (to_excl_list x) |? [] in + Invariant.( + IntInvariant.of_interval_opt e ik (min, max) && + IntInvariant.of_excl_list e ik ns && + Option.map_default (I4.invariant_ikind e ik) Invariant.none x_cong && + Option.map_default (I5.invariant_ikind e ik) Invariant.none x_intset + ) let arbitrary ik = QCheck.(set_print show @@ tup5 (option (I1.arbitrary ik)) (option (I2.arbitrary ik)) (option (I3.arbitrary ik)) (option (I4.arbitrary ik)) (option (I5.arbitrary ik))) diff --git a/tests/regression/cfg/foo.t/run.t b/tests/regression/cfg/foo.t/run.t index 02f6c1e5e0..705fb8d497 100644 --- a/tests/regression/cfg/foo.t/run.t +++ b/tests/regression/cfg/foo.t/run.t @@ -67,7 +67,7 @@ total lines: 6 [Warning][Deadcode][CWE-571] condition 'a > 0' (possibly inserted by CIL) is always true (foo.c:3:10-3:20) [Info][Witness] witness generation summary: - total generation entries: 15 + total generation entries: 13 $ yamlWitnessStrip < witness.yml - entry_type: loop_invariant @@ -125,17 +125,6 @@ string: 1 <= a type: assertion format: C - - entry_type: location_invariant - location: - file_name: foo.c - file_hash: $FILE_HASH - line: 7 - column: 3 - function: main - location_invariant: - string: 0 <= a - type: assertion - format: C - entry_type: location_invariant location: file_name: foo.c @@ -224,14 +213,3 @@ string: 1 <= a type: assertion format: C - - entry_type: location_invariant - location: - file_name: foo.c - file_hash: $FILE_HASH - line: 4 - column: 5 - function: main - location_invariant: - string: 0 <= a - type: assertion - format: C diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t index 6f75a2cd17..33316791e7 100644 --- a/tests/regression/witness/int.t/run.t +++ b/tests/regression/witness/int.t/run.t @@ -29,8 +29,7 @@ column: 5 function: main location_invariant: - string: (((0 <= i && i != 0) && (51 <= i && i <= 99)) && (0 <= i && i != 0)) && - (51 <= i && i <= 99) + string: (51 <= i && i <= 99) && ((i != 0 && i != 0) && (51 <= i && i <= 99)) type: assertion format: C - entry_type: location_invariant From 39f6c2d8d0d1c4f059263bba840fec4cb5aead34 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 12:41:09 +0300 Subject: [PATCH 377/689] Deduplicate inclusion list elements in IntDomTuple --- src/cdomain/value/cdomains/intDomain.ml | 2 +- tests/regression/witness/int.t/run.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 8860a8fbb5..c2eb2f3aa5 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -3536,7 +3536,7 @@ module IntDomTupleImpl = struct let merge ps = let (vs, rs) = List.split ps in let (mins, maxs) = List.split rs in - (List.concat vs, (List.min mins, List.max maxs)) + (List.concat vs |> List.sort_uniq Z.compare, (List.min mins, List.max maxs)) in mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.to_excl_list } x |> flat merge diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t index 33316791e7..2bf5bd31c3 100644 --- a/tests/regression/witness/int.t/run.t +++ b/tests/regression/witness/int.t/run.t @@ -29,7 +29,7 @@ column: 5 function: main location_invariant: - string: (51 <= i && i <= 99) && ((i != 0 && i != 0) && (51 <= i && i <= 99)) + string: (51 <= i && i <= 99) && (i != 0 && (51 <= i && i <= 99)) type: assertion format: C - entry_type: location_invariant From 2408ab6ae413a4bfcefa149c5a76d086382e3f86 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 12:44:40 +0300 Subject: [PATCH 378/689] Filter out-of-invariant exclusion list elements in IntDomTuple invariant --- src/cdomain/value/cdomains/intDomain.ml | 2 ++ tests/regression/cfg/foo.t/run.t | 35 +------------------------ tests/regression/witness/int.t/run.t | 2 +- 3 files changed, 4 insertions(+), 35 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index c2eb2f3aa5..a472a5017e 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -3803,6 +3803,8 @@ module IntDomTupleImpl = struct let min = minimal x in let max = maximal x in let ns = Option.map fst (to_excl_list x) |? [] in + let ns = Option.map_default (fun min -> List.filter (Z.leq min) ns) ns min in + let ns = Option.map_default (fun max -> List.filter (Z.geq max) ns) ns max in Invariant.( IntInvariant.of_interval_opt e ik (min, max) && IntInvariant.of_excl_list e ik ns && diff --git a/tests/regression/cfg/foo.t/run.t b/tests/regression/cfg/foo.t/run.t index 705fb8d497..cd890b7a19 100644 --- a/tests/regression/cfg/foo.t/run.t +++ b/tests/regression/cfg/foo.t/run.t @@ -67,7 +67,7 @@ total lines: 6 [Warning][Deadcode][CWE-571] condition 'a > 0' (possibly inserted by CIL) is always true (foo.c:3:10-3:20) [Info][Witness] witness generation summary: - total generation entries: 13 + total generation entries: 10 $ yamlWitnessStrip < witness.yml - entry_type: loop_invariant @@ -103,17 +103,6 @@ string: b == 0 type: assertion format: C - - entry_type: location_invariant - location: - file_name: foo.c - file_hash: $FILE_HASH - line: 7 - column: 3 - function: main - location_invariant: - string: a != 0 - type: assertion - format: C - entry_type: location_invariant location: file_name: foo.c @@ -147,17 +136,6 @@ string: b != 0 type: assertion format: C - - entry_type: location_invariant - location: - file_name: foo.c - file_hash: $FILE_HASH - line: 5 - column: 5 - function: main - location_invariant: - string: a != 1 - type: assertion - format: C - entry_type: location_invariant location: file_name: foo.c @@ -191,17 +169,6 @@ string: b != 0 type: assertion format: C - - entry_type: location_invariant - location: - file_name: foo.c - file_hash: $FILE_HASH - line: 4 - column: 5 - function: main - location_invariant: - string: a != 0 - type: assertion - format: C - entry_type: location_invariant location: file_name: foo.c diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t index 2bf5bd31c3..bc8ad5ac0a 100644 --- a/tests/regression/witness/int.t/run.t +++ b/tests/regression/witness/int.t/run.t @@ -29,7 +29,7 @@ column: 5 function: main location_invariant: - string: (51 <= i && i <= 99) && (i != 0 && (51 <= i && i <= 99)) + string: (51 <= i && i <= 99) && (51 <= i && i <= 99) type: assertion format: C - entry_type: location_invariant From 0a27c74d21a66a34abd5ecb6bbfe052d064fa261 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 12:57:06 +0300 Subject: [PATCH 379/689] Document nicer IntDomTuple invariant --- src/cdomain/value/cdomains/intDomain.ml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index a472a5017e..797c0f46c1 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -3793,23 +3793,26 @@ module IntDomTupleImpl = struct let invariant_ikind e ik ((_, _, _, x_cong, x_intset) as x) = match to_int x with | Some v -> - (* If definite, output single equality instead of every subdomain repeating same equality *) + (* If definite, output single equality instead of every subdomain repeating same equality (or something less precise). *) IntInvariant.of_int e ik v | None -> match to_incl_list x with | Some ps -> + (* If inclusion set, output disjunction of equalities because it subsumes interval(s), exclusion set and congruence. *) IntInvariant.of_incl_list e ik ps | None -> + (* Get interval bounds from all domains (intervals and exclusion set ranges). *) let min = minimal x in let max = maximal x in - let ns = Option.map fst (to_excl_list x) |? [] in + let ns = Option.map fst (to_excl_list x) |? [] in (* Ignore exclusion set bit range, known via interval bounds already. *) + (* "Refine" out-of-bounds exclusions for simpler output. *) let ns = Option.map_default (fun min -> List.filter (Z.leq min) ns) ns min in let ns = Option.map_default (fun max -> List.filter (Z.geq max) ns) ns max in Invariant.( - IntInvariant.of_interval_opt e ik (min, max) && + IntInvariant.of_interval_opt e ik (min, max) && (* Output best interval bounds once instead of multiple subdomains repeating them (or less precise ones). *) IntInvariant.of_excl_list e ik ns && - Option.map_default (I4.invariant_ikind e ik) Invariant.none x_cong && - Option.map_default (I5.invariant_ikind e ik) Invariant.none x_intset + Option.map_default (I4.invariant_ikind e ik) Invariant.none x_cong && (* Output congruence as is. *) + Option.map_default (I5.invariant_ikind e ik) Invariant.none x_intset (* Output interval sets as is. *) ) let arbitrary ik = QCheck.(set_print show @@ tup5 (option (I1.arbitrary ik)) (option (I2.arbitrary ik)) (option (I3.arbitrary ik)) (option (I4.arbitrary ik)) (option (I5.arbitrary ik))) From 02ef2f96d96e15bf94231dfdc5ddebe7b6d3606b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 19 Jun 2024 12:59:08 +0300 Subject: [PATCH 380/689] Disable interval set in witness int invariant cram test --- tests/regression/witness/int.t/run.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t index bc8ad5ac0a..6b4784ce32 100644 --- a/tests/regression/witness/int.t/run.t +++ b/tests/regression/witness/int.t/run.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --enable witness.yaml.enabled --set witness.yaml.entry-types '["location_invariant"]' --enable ana.int.def_exc --enable ana.int.enums --enable ana.int.interval --enable ana.int.congruence --enable ana.int.interval_set --disable witness.invariant.split-conjunction int.c + $ goblint --enable ana.sv-comp.functions --enable witness.yaml.enabled --set witness.yaml.entry-types '["location_invariant"]' --enable ana.int.def_exc --enable ana.int.enums --enable ana.int.interval --enable ana.int.congruence --disable ana.int.interval_set --disable witness.invariant.split-conjunction int.c [Success][Assert] Assertion "1" will succeed (int.c:9:5-9:23) [Success][Assert] Assertion "1" will succeed (int.c:12:5-12:23) [Success][Assert] Assertion "1" will succeed (int.c:15:5-15:23) @@ -29,7 +29,7 @@ column: 5 function: main location_invariant: - string: (51 <= i && i <= 99) && (51 <= i && i <= 99) + string: 51 <= i && i <= 99 type: assertion format: C - entry_type: location_invariant @@ -40,6 +40,6 @@ column: 5 function: main location_invariant: - string: i <= 99 && i <= 99 + string: i <= 99 type: assertion format: C From c9ea4408e20c8968912c7773677b696c6f050222 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 19 Jun 2024 15:49:17 +0300 Subject: [PATCH 381/689] Binops on offsets should not generate overflow warnings in SV-COMP --- src/cdomain/value/cdomains/offset.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/offset.ml b/src/cdomain/value/cdomains/offset.ml index fa64f71daa..e8cba0afc5 100644 --- a/src/cdomain/value/cdomains/offset.ml +++ b/src/cdomain/value/cdomains/offset.ml @@ -213,7 +213,7 @@ struct 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 - Idx.add bits_offset remaining_offset + GobRef.wrap AnalysisState.executing_speculative_computations true @@ fun () -> Idx.add bits_offset remaining_offset | `Index (x, o) -> let (item_typ, item_size_in_bits) = match Option.map unrollType typ with From 545206f68a9dee4999860ec4ce6232f214d65516 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 19 Jun 2024 16:07:19 +0300 Subject: [PATCH 382/689] Add some info about overflows on pointer arithmetics to assumptions --- docs/user-guide/assumptions.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/user-guide/assumptions.md b/docs/user-guide/assumptions.md index f77e3b5097..16386987de 100644 --- a/docs/user-guide/assumptions.md +++ b/docs/user-guide/assumptions.md @@ -17,3 +17,12 @@ _NB! This list is likely incomplete._ See [PR #1414](https://github.com/goblint/analyzer/pull/1414). +2. Goblint's does not give any guarantees about overflows not happening during pointer arithmetics. + + Although the analysis can detect and warn about overflows that might happen during operations with pointer offsets, + the analysis does not warn about overflows from operations with the possible addresses (as integers) of the pointers themselves. + + This affects the `no-overflows` analysis from `ana.int.interval` analysis. + + See further discussion from [PR #1511](https://github.com/goblint/analyzer/pull/1511). + From af781ed684c538cfa98ef0d35a9d258fec62e495 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 12:56:40 +0300 Subject: [PATCH 383/689] Enable ana.float.evaluate_math_functions in svcomp24 and svcomp confs This is needed for sv-benchmarks Juliet no-overflow tasks involving sqrt. We used this at SV-COMP 2024, before the option existed. --- conf/svcomp.json | 3 ++- conf/svcomp24-validate.json | 3 ++- conf/svcomp24.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/conf/svcomp.json b/conf/svcomp.json index 467d294bdd..d2bea96040 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -10,7 +10,8 @@ "interval": true }, "float": { - "interval": true + "interval": true, + "evaluate_math_functions": true }, "activated": [ "base", diff --git a/conf/svcomp24-validate.json b/conf/svcomp24-validate.json index 7832ffa6af..d83b1767a4 100644 --- a/conf/svcomp24-validate.json +++ b/conf/svcomp24-validate.json @@ -10,7 +10,8 @@ "interval": true }, "float": { - "interval": true + "interval": true, + "evaluate_math_functions": true }, "activated": [ "base", diff --git a/conf/svcomp24.json b/conf/svcomp24.json index 7e30554ceb..1c60f84920 100644 --- a/conf/svcomp24.json +++ b/conf/svcomp24.json @@ -10,7 +10,8 @@ "interval": true }, "float": { - "interval": true + "interval": true, + "evaluate_math_functions": true }, "activated": [ "base", From 3ff00aea295c6e7386323efc88f38d1a046cbdbc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:00:36 +0300 Subject: [PATCH 384/689] Add tests for imaxabs --- .../39-signed-overflows/11-imaxabs.c | 24 +++++++++++++++++++ .../39-signed-overflows/12-imaxabs-sqrt.c | 12 ++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/regression/39-signed-overflows/11-imaxabs.c create mode 100644 tests/regression/39-signed-overflows/12-imaxabs-sqrt.c diff --git a/tests/regression/39-signed-overflows/11-imaxabs.c b/tests/regression/39-signed-overflows/11-imaxabs.c new file mode 100644 index 0000000000..dce200a146 --- /dev/null +++ b/tests/regression/39-signed-overflows/11-imaxabs.c @@ -0,0 +1,24 @@ +//PARAM: --enable ana.int.interval --set ana.activated[+] tmpSpecial +#include +#include +#include +int main() { + int64_t data; + if (data > (-0x7fffffffffffffff - 1)) + { + if (imaxabs(data) < 100) + { + __goblint_check(data < 100); // TODO + __goblint_check(-100 < data); // TODO + int64_t result = data * data; // TODO NOWARN + } + + if(imaxabs(data) <= 100) + { + __goblint_check(data <= 100); // TODO + __goblint_check(-100 <= data); // TODO + int64_t result = data * data; // TODO NOWARN + } + } + return 8; +} diff --git a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c new file mode 100644 index 0000000000..b121645b27 --- /dev/null +++ b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c @@ -0,0 +1,12 @@ +//PARAM: --enable ana.int.interval --enable ana.float.interval --enable ana.float.evaluate_math_functions --set ana.activated[+] tmpSpecial +#include +#include +#include +int main() { + int64_t data; + if (data > (-0x7fffffffffffffff - 1) && imaxabs((intmax_t)data) <= sqrtl(0x7fffffffffffffffLL)) + { + int64_t result = data * data; // TODO NOWARN + } + return 8; +} From 2653e2ea22dd9d012a10e008f3189e1061d2c344 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:02:26 +0300 Subject: [PATCH 385/689] Add hacky imaxabs support --- src/util/library/libraryFunctions.ml | 2 +- tests/regression/39-signed-overflows/11-imaxabs.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index e7ff2a4d04..df90339c65 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -139,7 +139,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("abs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (IInt, j)) }); ("labs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); ("llabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILongLong, j)) }); - ("imaxabs", unknown [drop "j" []]); + ("imaxabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); (* TODO: look up intmax_t ikind from CIL file *) ("localtime_r", unknown [drop "timep" [r]; drop "result" [w]]); ("strpbrk", unknown [drop "s" [r]; drop "accept" [r]]); ("_setjmp", special [__ "env" [w]] @@ fun env -> Setjmp { env }); (* only has one underscore *) diff --git a/tests/regression/39-signed-overflows/11-imaxabs.c b/tests/regression/39-signed-overflows/11-imaxabs.c index dce200a146..47bd26569f 100644 --- a/tests/regression/39-signed-overflows/11-imaxabs.c +++ b/tests/regression/39-signed-overflows/11-imaxabs.c @@ -8,16 +8,16 @@ int main() { { if (imaxabs(data) < 100) { - __goblint_check(data < 100); // TODO - __goblint_check(-100 < data); // TODO - int64_t result = data * data; // TODO NOWARN + __goblint_check(data < 100); + __goblint_check(-100 < data); + int64_t result = data * data; // NOWARN } if(imaxabs(data) <= 100) { - __goblint_check(data <= 100); // TODO - __goblint_check(-100 <= data); // TODO - int64_t result = data * data; // TODO NOWARN + __goblint_check(data <= 100); + __goblint_check(-100 <= data); + int64_t result = data * data; // NOWARN } } return 8; From f9765da81d64a99f77c385835c6c0a5c3db419da Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:05:26 +0300 Subject: [PATCH 386/689] Add hacky imaxabs sqrt refine support --- src/analyses/baseInvariant.ml | 3 ++- tests/regression/39-signed-overflows/12-imaxabs-sqrt.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analyses/baseInvariant.ml b/src/analyses/baseInvariant.ml index 51a27e19f8..d5b65a95f4 100644 --- a/src/analyses/baseInvariant.ml +++ b/src/analyses/baseInvariant.ml @@ -785,7 +785,8 @@ struct | TFloat (fk, _), FLongDouble | TFloat (FDouble as fk, _), FDouble | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st - | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) + | TInt (ik, _), _ -> inv_exp (Int (FD.to_int ik c)) e st (* TODO: is this cast refinement correct? *) + | t, fk -> fallback (fun () -> Pretty.dprintf "CastE: incompatible types %a and %a" CilType.Typ.pretty t CilType.Fkind.pretty fk) st) | CastE ((TInt (ik, _)) as t, e), Int c | CastE ((TEnum ({ekind = ik; _ }, _)) as t, e), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) (match eval e st with diff --git a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c index b121645b27..46512aed21 100644 --- a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c +++ b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c @@ -6,7 +6,7 @@ int main() { int64_t data; if (data > (-0x7fffffffffffffff - 1) && imaxabs((intmax_t)data) <= sqrtl(0x7fffffffffffffffLL)) { - int64_t result = data * data; // TODO NOWARN + int64_t result = data * data; // NOWARN } return 8; } From a1f0b35703e34da0eda8f3f27ea260a58fd2c85d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:15:01 +0300 Subject: [PATCH 387/689] Find intmax_t for imaxabs from program --- src/util/library/libraryFunctions.ml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index df90339c65..689eb17126 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -6,6 +6,16 @@ open GobConfig module M = Messages +let intmax_t = lazy ( + let res = ref None in + GoblintCil.iterGlobals !Cilfacade.current_file (function + | GType ({tname = "intmax_t"; ttype; _}, _) -> + res := Some ttype; + | _ -> () + ); + !res +) + (** C standard library functions. These are specified by the C standard. *) let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ @@ -139,7 +149,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("abs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (IInt, j)) }); ("labs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); ("llabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILongLong, j)) }); - ("imaxabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); (* TODO: look up intmax_t ikind from CIL file *) + ("imaxabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (Cilfacade.get_ikind (Option.get (Lazy.force intmax_t)), j)) }); ("localtime_r", unknown [drop "timep" [r]; drop "result" [w]]); ("strpbrk", unknown [drop "s" [r]; drop "accept" [r]]); ("_setjmp", special [__ "env" [w]] @@ fun env -> Setjmp { env }); (* only has one underscore *) From 06086c646285037bcb242dc70705fbaa690e8ebd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 17:55:07 +0300 Subject: [PATCH 388/689] Refactor YAML witness validation result passing --- src/framework/control.ml | 14 +++++++++----- src/witness/witness.ml | 25 ++++++++----------------- src/witness/yamlWitness.ml | 16 +++++++++++++++- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index 05fad90caf..bb1d7bab58 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -789,15 +789,19 @@ struct ); (* Before SV-COMP, so result can depend on YAML witness validation. *) - if get_string "witness.yaml.validate" <> "" then ( - let module YWitness = YamlWitness.Validator (R) in - YWitness.validate () - ); + let yaml_validate_result = + if get_string "witness.yaml.validate" <> "" then ( + let module YWitness = YamlWitness.Validator (R) in + Some (YWitness.validate ()) + ) + else + None + in if get_bool "ana.sv-comp.enabled" then ( (* SV-COMP and witness generation *) let module WResult = Witness.Result (R) in - WResult.write entrystates + WResult.write yaml_validate_result entrystates ); if get_bool "witness.yaml.enabled" then ( diff --git a/src/witness/witness.ml b/src/witness/witness.ml index fb88c2ce7b..651e7a76d5 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -690,25 +690,16 @@ struct Timing.wrap "graphml witness" (write_file witness_path (module Task)) (module TaskResult) ) - let write entrystates = + let write yaml_validate_result entrystates = match !AnalysisState.verified with | Some false -> print_svcomp_result "ERROR (verify)" | _ -> - if get_string "witness.yaml.validate" <> "" then ( - match get_bool "witness.yaml.strict" with - | true when !YamlWitness.cnt_error > 0 -> - print_svcomp_result "ERROR (witness error)" - | true when !YamlWitness.cnt_unsupported > 0 -> - print_svcomp_result "ERROR (witness unsupported)" - | true when !YamlWitness.cnt_disabled > 0 -> - print_svcomp_result "ERROR (witness disabled)" - | _ when !YamlWitness.cnt_refuted > 0 -> - print_svcomp_result (Result.to_string (False None)) - | _ when !YamlWitness.cnt_unconfirmed > 0 -> - print_svcomp_result (Result.to_string Unknown) - | _ -> - write entrystates - ) - else + match yaml_validate_result with + | Some (Error msg) -> + print_svcomp_result ("ERROR (" ^ msg ^ ")") + | Some (Ok (Svcomp.Result.False _ | Unknown as result)) -> + print_svcomp_result (Result.to_string result) + | Some (Ok True) + | None -> write entrystates end diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 42254f30de..71bb75afef 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -840,5 +840,19 @@ struct let certificate_path = GobConfig.get_string "witness.yaml.certificate" in if certificate_path <> "" then - yaml_entries_to_file (List.rev yaml_entries') (Fpath.v certificate_path) + yaml_entries_to_file (List.rev yaml_entries') (Fpath.v certificate_path); + + match GobConfig.get_bool "witness.yaml.strict" with + | true when !cnt_error > 0 -> + Error "witness error" + | true when !cnt_unsupported > 0 -> + Error "witness unsupported" + | true when !cnt_disabled > 0 -> + Error "witness disabled" + | _ when !cnt_refuted > 0 -> + Ok (Svcomp.Result.False None) + | _ when !cnt_unconfirmed > 0 -> + Ok Unknown + | _ -> + Ok True end From a74840942fabc3231eb41eb62ce073a35b667971 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 21 Jun 2024 13:20:34 +0300 Subject: [PATCH 389/689] Upgrade locked opam dependencies --- goblint.opam.locked | 91 ++++++++++++++++++++++++--------------------- gobview | 2 +- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/goblint.opam.locked b/goblint.opam.locked index d532457ced..410d363ac8 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -21,89 +21,94 @@ homepage: "https://goblint.in.tum.de" doc: "https://goblint.readthedocs.io/en/latest/" bug-reports: "https://github.com/goblint/analyzer/issues" depends: [ - "angstrom" {= "0.15.0"} - "apron" {= "v0.9.14~beta.2"} + "angstrom" {= "0.16.0"} + "apron" {= "v0.9.14"} "arg-complete" {= "0.1.0"} "astring" {= "0.8.5"} "base-bigarray" {= "base"} "base-bytes" {= "base"} "base-threads" {= "base"} "base-unix" {= "base"} - "batteries" {= "3.6.0"} + "batteries" {= "3.8.0"} "benchmark" {= "1.6" & with-test} "bigarray-compat" {= "1.1.0"} - "bigstringaf" {= "0.9.0"} + "bigstringaf" {= "0.9.1"} "bos" {= "0.2.1"} - "camlidl" {= "1.11"} + "camlidl" {= "1.12"} "camlp-streams" {= "5.0.1"} "catapult" {= "0.2"} "catapult-file" {= "0.2"} - "cmdliner" {= "1.1.1" & with-doc} - "conf-autoconf" {= "0.1"} + "cmdliner" {= "1.3.0" & with-doc} + "conf-autoconf" {= "0.2"} + "conf-findutils" {= "1"} "conf-gcc" {= "1.0"} "conf-gmp" {= "4"} - "conf-mpfr" {= "3"} + "conf-gmp-paths" {= "1"} + "conf-mpfr-paths" {= "1"} "conf-perl" {= "2"} - "conf-pkg-config" {= "2"} "conf-ruby" {= "1.0.0" & with-test} - "conf-which" {= "1"} "cppo" {= "1.6.9"} "cpu" {= "2.0.0"} - "csexp" {= "1.5.1"} - "ctypes" {= "0.20.1"} - "dune" {= "3.7.1"} - "dune-build-info" {= "3.7.1"} - "dune-configurator" {= "3.7.1"} - "dune-private-libs" {= "3.7.1"} - "dune-site" {= "3.7.1"} - "dyn" {= "3.7.1"} + "crunch" {= "3.3.1" & with-doc} + "csexp" {= "1.5.2"} + "cstruct" {= "6.2.0"} + "ctypes" {= "0.22.0"} + "dune" {= "3.16.0"} + "dune-build-info" {= "3.16.0"} + "dune-configurator" {= "3.16.0"} + "dune-private-libs" {= "3.16.0"} + "dune-site" {= "3.16.0"} + "dyn" {= "3.16.0"} + "ez-conf-lib" {= "2"} "fileutils" {= "0.6.4"} "fmt" {= "0.9.0"} "fpath" {= "0.7.3"} "goblint-cil" {= "2.0.3"} + "hex" {= "1.5.0"} "integers" {= "0.7.0"} - "json-data-encoding" {= "0.12.1"} - "jsonrpc" {= "1.15.0~5.0preview1"} + "json-data-encoding" {= "1.0.1"} + "jsonrpc" {= "1.17.0"} "logs" {= "0.7.0"} - "mlgmpidl" {= "1.2.15"} - "num" {= "1.4"} + "mlgmpidl" {= "1.3.0"} + "num" {= "1.5"} "ocaml" {= "4.14.0"} "ocaml-compiler-libs" {= "v0.12.4"} "ocaml-config" {= "2"} "ocaml-option-flambda" {= "1"} "ocaml-syntax-shims" {= "1.0.0"} "ocaml-variants" {= "4.14.0+options"} - "ocamlbuild" {= "0.14.2"} - "ocamlfind" {= "1.9.5"} - "odoc" {= "2.2.0" & with-doc} - "odoc-parser" {= "2.0.0" & with-doc} - "ordering" {= "3.7.1"} - "ounit2" {= "2.2.6" & with-test} - "pp" {= "1.1.2"} + "ocamlbuild" {= "0.14.3"} + "ocamlfind" {= "1.9.6"} + "odoc" {= "2.4.2" & with-doc} + "odoc-parser" {= "2.4.2" & with-doc} + "ordering" {= "3.16.0"} + "ounit2" {= "2.2.7" & with-test} + "pp" {= "1.2.0"} "ppx_derivers" {= "1.2.1"} "ppx_deriving" {= "6.0.2"} "ppx_deriving_hash" {= "0.1.2"} - "ppx_deriving_yojson" {= "3.7.0"} + "ppx_deriving_yojson" {= "3.8.0"} "ppxlib" {= "0.32.1"} - "qcheck-core" {= "0.20"} - "qcheck-ounit" {= "0.20" & with-test} - "re" {= "1.10.4" & with-doc} - "result" {= "1.5"} + "ptime" {= "1.1.0" & with-doc} + "qcheck-core" {= "0.21.3"} + "qcheck-ounit" {= "0.21.3" & with-test} + "re" {= "1.11.0" & with-doc} + "result" {= "1.5" & with-doc} "rresult" {= "0.7.0"} "seq" {= "base"} - "sexplib0" {= "v0.15.1"} - "sha" {= "1.15.2"} + "sexplib0" {= "v0.16.0"} + "sha" {= "1.15.4"} "stdlib-shims" {= "0.3.0"} - "stdune" {= "3.7.1"} + "stdune" {= "3.16.0"} "stringext" {= "1.6.0"} - "topkg" {= "1.0.6"} - "tyxml" {= "4.5.0" & with-doc} - "uri" {= "4.2.0"} + "topkg" {= "1.0.7"} + "tyxml" {= "4.6.0" & with-doc} + "uri" {= "4.4.0"} "uuidm" {= "0.9.8"} "uutf" {= "1.0.3" & with-doc} - "yaml" {= "3.1.0"} - "yojson" {= "2.0.2"} - "zarith" {= "1.12"} + "yaml" {= "3.2.0"} + "yojson" {= "2.2.1"} + "zarith" {= "1.13"} ] build: [ ["dune" "subst"] {dev} diff --git a/gobview b/gobview index 195c61cbae..287bf59be9 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 195c61cbae86b8ffb8af4a21f2acd689665c1c0e +Subproject commit 287bf59be9e25ceea704384c65e0d91565bb749d From 702af102571ec98d660b5ec898d62a73dd4d616c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 21 Jun 2024 14:50:45 +0300 Subject: [PATCH 390/689] Use Sys.opaque_identity in build-info to prevent excessive no-changes rebuild in release profile --- src/build-info/dune | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/build-info/dune b/src/build-info/dune index 5a64b399a4..e1a45ef8fc 100644 --- a/src/build-info/dune +++ b/src/build-info/dune @@ -15,7 +15,7 @@ (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\"'"))))) + (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 = Sys.opaque_identity \"%s\"'"))))) (rule (target configProfile.ml) @@ -31,7 +31,7 @@ (target configDatetime.ml) (mode (promote (until-clean) (only configDatetime.ml))) ; replace existing file in source tree, even if releasing (only overrides) (deps (universe)) ; do not cache, always regenerate - (action (pipe-stdout (bash "date +\"%Y-%m-%dT%H:%M:%S\" || echo \"n/a\"") (with-stdout-to %{target} (bash "xargs printf '(* Automatically regenerated, changes do not persist! *)\nlet datetime = \"%s\"'"))))) + (action (pipe-stdout (bash "date +\"%Y-%m-%dT%H:%M:%S\" || echo \"n/a\"") (with-stdout-to %{target} (bash "xargs printf '(* Automatically regenerated, changes do not persist! *)\nlet datetime = Sys.opaque_identity \"%s\"'"))))) (env (_ From 01d275829fa8c532cbf44ab3a439f04bd3886e19 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 21 Jun 2024 15:19:14 +0300 Subject: [PATCH 391/689] Use String.starts_with and ends_with from Stdlib Since OCaml 4.13. --- src/analyses/mutexEventsAnalysis.ml | 5 ++--- src/autoTune.ml | 2 +- src/build-info/dune | 1 - src/build-info/goblint_build_info.ml | 2 +- src/cdomain/value/domains/invariantCil.ml | 4 ++-- src/cdomains/apron/affineEqualityDomain.apron.ml | 5 ++--- src/common/util/cilfacade.ml | 2 +- src/domains/access.ml | 9 ++++----- src/incremental/compareAST.ml | 2 +- src/incremental/makefileUtil.ml | 2 +- src/witness/svcomp.ml | 5 ++--- 11 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/analyses/mutexEventsAnalysis.ml b/src/analyses/mutexEventsAnalysis.ml index c5339e68cf..5ea0afc809 100644 --- a/src/analyses/mutexEventsAnalysis.ml +++ b/src/analyses/mutexEventsAnalysis.ml @@ -5,7 +5,6 @@ module M = Messages module Addr = ValueDomain.Addr module LF = LibraryFunctions -open Batteries open GoblintCil open Analyses open GobConfig @@ -52,12 +51,12 @@ struct let return ctx exp fundec : D.t = (* deprecated but still valid SV-COMP convention for atomic block *) - if get_bool "ana.sv-comp.functions" && String.starts_with fundec.svar.vname "__VERIFIER_atomic_" then + if get_bool "ana.sv-comp.functions" && String.starts_with fundec.svar.vname ~prefix:"__VERIFIER_atomic_" then ctx.emit (Events.Unlock (LockDomain.Addr.of_var LF.verifier_atomic_var)) let body ctx f : D.t = (* deprecated but still valid SV-COMP convention for atomic block *) - if get_bool "ana.sv-comp.functions" && String.starts_with f.svar.vname "__VERIFIER_atomic_" then + if get_bool "ana.sv-comp.functions" && String.starts_with f.svar.vname ~prefix:"__VERIFIER_atomic_" then ctx.emit (Events.Lock (LockDomain.Addr.of_var LF.verifier_atomic_var, true)) let special (ctx: (unit, _, _, _) ctx) lv f arglist : D.t = diff --git a/src/autoTune.ml b/src/autoTune.ml index 434b4fb0b2..3871e421c7 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -104,7 +104,7 @@ let rec setCongruenceRecursive fd depth neigbourFunction = | exception Not_found -> () (* Happens for __goblint_bounded *) ) (FunctionSet.filter (*for extern and builtin functions there is no function definition in CIL*) - (fun x -> not (isExtern x.vstorage || BatString.starts_with x.vname "__builtin")) + (fun x -> not (isExtern x.vstorage || String.starts_with x.vname ~prefix:"__builtin")) (neigbourFunction fd.svar) ) ; diff --git a/src/build-info/dune b/src/build-info/dune index e1a45ef8fc..1dd74c192c 100644 --- a/src/build-info/dune +++ b/src/build-info/dune @@ -8,7 +8,6 @@ (library (name goblint_build_info) (public_name goblint.build-info) - (libraries batteries.unthreaded) (virtual_modules dune_build_info)) (rule diff --git a/src/build-info/goblint_build_info.ml b/src/build-info/goblint_build_info.ml index 14e30a1b36..d2600c94ad 100644 --- a/src/build-info/goblint_build_info.ml +++ b/src/build-info/goblint_build_info.ml @@ -18,7 +18,7 @@ let release_commit = "%%VCS_COMMIT_ID%%" (** Goblint version. *) let version = let commit = ConfigVersion.version in - if BatString.starts_with release_version "%" then + if String.starts_with release_version ~prefix:"%" then commit else ( let commit = diff --git a/src/cdomain/value/domains/invariantCil.ml b/src/cdomain/value/domains/invariantCil.ml index 813ec25818..f41d48ab61 100644 --- a/src/cdomain/value/domains/invariantCil.ml +++ b/src/cdomain/value/domains/invariantCil.ml @@ -88,7 +88,7 @@ class exp_contains_anon_type_visitor = object inherit nopCilVisitor method! vtype (t: typ) = match t with - | TComp ({cname; _}, _) when BatString.starts_with_stdlib ~prefix:"__anon" cname -> + | TComp ({cname; _}, _) when String.starts_with ~prefix:"__anon" cname -> raise Stdlib.Exit | _ -> DoChildren @@ -102,7 +102,7 @@ let exp_contains_anon_type = (* TODO: synchronize magic constant with BaseDomain *) -let var_is_heap {vname; _} = BatString.starts_with vname "(alloc@" +let var_is_heap {vname; _} = String.starts_with vname ~prefix:"(alloc@" let reset_lazy () = ResettableLazy.reset exclude_vars_regexp diff --git a/src/cdomains/apron/affineEqualityDomain.apron.ml b/src/cdomains/apron/affineEqualityDomain.apron.ml index 7e60cce74b..ab9c1994fb 100644 --- a/src/cdomains/apron/affineEqualityDomain.apron.ml +++ b/src/cdomains/apron/affineEqualityDomain.apron.ml @@ -6,7 +6,6 @@ Matrices are modeled as proposed by Karr: Each variable is assigned to a column and each row represents a linear affine relationship that must hold at the corresponding program point. The apron environment is hereby used to organize the order of columns and variables. *) -open Batteries open GoblintCil open Pretty module M = Messages @@ -193,7 +192,7 @@ struct in let res = (String.concat "" @@ Array.to_list @@ Array.map dim_to_str vars) ^ (const_to_str arr.(Array.length arr - 1)) ^ "=0" in - if String.starts_with res "+" then + if String.starts_with res ~prefix:"+" then Str.string_after res 1 else res @@ -370,7 +369,7 @@ struct let remove_rels_with_var x var env inplace = timing_wrap "remove_rels_with_var" (remove_rels_with_var x var env) inplace let forget_vars t vars = - if is_bot t || is_top_env t || List.is_empty vars then + if is_bot t || is_top_env t || vars = [] then t else let m = Option.get t.d in diff --git a/src/common/util/cilfacade.ml b/src/common/util/cilfacade.ml index 99430ee8b6..62ce993455 100644 --- a/src/common/util/cilfacade.ml +++ b/src/common/util/cilfacade.ml @@ -734,7 +734,7 @@ let add_function_declarations (file: Cil.file): unit = let functions, non_functions = List.partition (fun g -> match g with GFun _ -> true | _ -> false) globals in let upto_last_type, non_types = GobList.until_last_with (fun g -> match g with GType _ -> true | _ -> false) non_functions in let declaration_from_GFun f = match f with - | GFun (f, _) when BatString.starts_with_stdlib ~prefix:"__builtin" f.svar.vname -> + | GFun (f, _) when String.starts_with ~prefix:"__builtin" f.svar.vname -> (* Builtin functions should not occur in asserts generated, so there is no need to add declarations for them.*) None | GFun (f, _) -> diff --git a/src/domains/access.ml b/src/domains/access.ml index c35fb3a16d..f7ce68a18b 100644 --- a/src/domains/access.ml +++ b/src/domains/access.ml @@ -1,6 +1,5 @@ (** Memory accesses and their manipulation. *) -open Batteries open GoblintCil open Pretty open GobConfig @@ -12,7 +11,7 @@ module M = Messages let is_ignorable_comp_name = function | "__pthread_mutex_s" | "__pthread_rwlock_arch_t" | "__jmp_buf_tag" | "_pthread_cleanup_buffer" | "__pthread_cleanup_frame" | "__cancel_jmp_buf_tag" | "_IO_FILE" -> true - | cname when String.starts_with_stdlib ~prefix:"__anon" cname -> + | cname when String.starts_with ~prefix:"__anon" cname -> begin match Cilfacade.split_anoncomp_name cname with | (true, Some ("__once_flag" | "__pthread_unwind_buf_t" | "__cancel_jmp_buf"), _) -> true (* anonstruct *) | (false, Some ("pthread_mutexattr_t" | "pthread_condattr_t" | "pthread_barrierattr_t"), _) -> true (* anonunion *) @@ -385,7 +384,7 @@ and distribute_access_exp f = function and distribute_access_type f = function | TArray (et, len, _) -> - Option.may (distribute_access_exp f) len; + Option.iter (distribute_access_exp f) len; distribute_access_type f et | TVoid _ @@ -434,7 +433,7 @@ struct include SetDomain.Make (A) let max_conf accs = - accs |> elements |> List.map (fun {A.conf; _} -> conf) |> (List.max ~cmp:Int.compare) + accs |> elements |> List.map (fun {A.conf; _} -> conf) |> (BatList.max ~cmp:Int.compare) end @@ -583,7 +582,7 @@ let incr_summary ~safe ~vulnerable ~unsafe grouped_accs = |> List.filter_map race_conf |> (function | [] -> None - | confs -> Some (List.max confs) + | confs -> Some (BatList.max confs) ) in match safety with diff --git a/src/incremental/compareAST.ml b/src/incremental/compareAST.ml index f3de153658..ecd69f1f96 100644 --- a/src/incremental/compareAST.ml +++ b/src/incremental/compareAST.ml @@ -73,7 +73,7 @@ let forward_list_equal ?(propF = (&&>>)) f l1 l2 ~(rename_mapping: rename_mappin let compare_name (a: string) (b: string) = let anon_struct = "__anonstruct_" in let anon_union = "__anonunion_" in - if a = b then true else BatString.(starts_with a anon_struct && starts_with b anon_struct || starts_with a anon_union && starts_with b anon_union) + if a = b then true else String.(starts_with a ~prefix:anon_struct && starts_with b ~prefix:anon_struct || starts_with a ~prefix:anon_union && starts_with b ~prefix:anon_union) let rec eq_constant ~(rename_mapping: rename_mapping) ~(acc: (typ * typ) list) (a: constant) (b: constant) : bool * rename_mapping = match a, b with diff --git a/src/incremental/makefileUtil.ml b/src/incremental/makefileUtil.ml index 9a17122f5e..33cd8f64c9 100644 --- a/src/incremental/makefileUtil.ml +++ b/src/incremental/makefileUtil.ml @@ -39,7 +39,7 @@ let find_file_by_suffix (dir: Fpath.t) (file_name_suffix: string) = | (h::t) -> let f = Fpath.to_string h in if Sys.file_exists f && Sys.is_directory f then (Queue.add h dirs; search dir t) - else if Batteries.String.ends_with (Fpath.filename h) file_name_suffix then h else search dir t + else if String.ends_with (Fpath.filename h) ~suffix:file_name_suffix then h else search dir t | [] -> if Queue.is_empty dirs then failwith ("find_file_by_suffix found no files with suffix "^file_name_suffix^" in "^ Fpath.to_string dir) else let d = Queue.take dirs in search d (list_files d) diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index bb887e6cb1..c17b5e78f8 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -1,7 +1,6 @@ (** SV-COMP tasks and results. *) open GoblintCil -open Batteries module Specification = SvcompSpec @@ -27,9 +26,9 @@ let is_error_function f = (* TODO: unused, but should be used? *) let is_special_function f = let loc = f.vdecl in - 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_svcomp = String.ends_with loc.file ~suffix:"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 when String.starts_with fname ~prefix:"__VERIFIER" -> true | fname -> is_error_function f in is_svcomp && is_verifier From ecda3f734f020703b0535e578513abfd9b2d53a4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 25 Jun 2024 11:24:45 +0300 Subject: [PATCH 392/689] Move comment in MutexTypeAnalysis --- src/analyses/mutexTypeAnalysis.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexTypeAnalysis.ml b/src/analyses/mutexTypeAnalysis.ml index e8edddd41e..4a993bbd7d 100644 --- a/src/analyses/mutexTypeAnalysis.ml +++ b/src/analyses/mutexTypeAnalysis.ml @@ -12,17 +12,17 @@ struct let name () = "pthreadMutexType" - (* Removing indexes here avoids complicated lookups and allows to have the LVals as vars here, at the price that different types of mutexes in arrays are not dinstinguished *) - module O = Offset.Unit - module V = struct + (* Removing indexes here avoids complicated lookups and allows to have the LVals as vars here, at the price that different types of mutexes in arrays are not dinstinguished *) include Mval.Unit let is_write_only _ = false end module G = MAttr + module O = Offset.Unit + (* transfer functions *) let assign ctx (lval:lval) (rval:exp) : D.t = match lval with From bc3fac895299e7b96ad8ac216d446bc6751a831c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 25 Jun 2024 11:51:07 +0300 Subject: [PATCH 393/689] Add witness missing verdict to YAML witness validation Better than "EXCEPTION (Failure)" as verdict. --- src/goblint.ml | 5 +++++ src/witness/svcomp.ml | 5 +++++ src/witness/witness.ml | 2 +- src/witness/yamlWitness.ml | 4 +++- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/goblint.ml b/src/goblint.ml index a687badb8e..52b9bbdfc0 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -83,6 +83,11 @@ let main () = Logs.error "%s" (MessageUtil.colorize ~fd:Unix.stderr ("{RED}Analysis was aborted because it reached the set timeout of " ^ get_string "dbg.timeout" ^ " or was signalled SIGPROF!")); Goblint_timing.teardown_tef (); exit 124 + | Svcomp.Error msg -> + do_stats (); + Witness.print_svcomp_result ("ERROR (" ^ msg ^ ")"); + Goblint_timing.teardown_tef (); + exit 1 (* We do this since the evaluation order of top-level bindings is not defined, but we want `main` to run after all the other side-effects (e.g. registering analyses/solvers) have happened. *) let () = at_exit main diff --git a/src/witness/svcomp.ml b/src/witness/svcomp.ml index bb887e6cb1..59a8f01b40 100644 --- a/src/witness/svcomp.ml +++ b/src/witness/svcomp.ml @@ -60,6 +60,11 @@ struct | Unknown -> "unknown" end +exception Error of string + +let errorwith s = raise (Error s) + + module type TaskResult = sig module Arg: MyARG.S diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 651e7a76d5..7b0213b601 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -695,7 +695,7 @@ struct | Some false -> print_svcomp_result "ERROR (verify)" | _ -> match yaml_validate_result with - | Some (Error msg) -> + | Some (Stdlib.Error msg) -> print_svcomp_result ("ERROR (" ^ msg ^ ")") | Some (Ok (Svcomp.Result.False _ | Unknown as result)) -> print_svcomp_result (Result.to_string result) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 71bb75afef..bb91e195ef 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -581,7 +581,9 @@ struct let yaml = match Yaml_unix.of_file (Fpath.v (GobConfig.get_string "witness.yaml.validate")) with | Ok yaml -> yaml - | Error (`Msg m) -> failwith ("Yaml_unix.of_file: " ^ m) + | Error (`Msg m) -> + Logs.error "Yaml_unix.of_file: %s" m; + Svcomp.errorwith "witness missing" in let yaml_entries = yaml |> GobYaml.list |> BatResult.get_ok in From 9fd0fd5bd3dcb7b22d200e4f655535789d846d51 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 25 Jun 2024 11:59:00 +0300 Subject: [PATCH 394/689] Add witness missing verdict to YAML witness unassume Better than "EXCEPTION (Failure)" as verdict. --- src/analyses/unassumeAnalysis.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 265e9c6925..85b33edc79 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -85,7 +85,9 @@ struct let yaml = match Yaml_unix.of_file (Fpath.v (GobConfig.get_string "witness.yaml.unassume")) with | Ok yaml -> yaml - | Error (`Msg m) -> failwith ("Yaml_unix.of_file: " ^ m) + | Error (`Msg m) -> + Logs.error "Yaml_unix.of_file: %s" m; + Svcomp.errorwith "witness missing" in let yaml_entries = yaml |> GobYaml.list |> BatResult.get_ok in From 85ab1fdc9edddf65a8f1a6c8bae74c1a417859f0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 25 Jun 2024 12:09:46 +0300 Subject: [PATCH 395/689] Check YAML witness existence before analysis --- src/framework/control.ml | 1 + src/witness/yamlWitness.ml | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/src/framework/control.ml b/src/framework/control.ml index bb1d7bab58..5e92282210 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -357,6 +357,7 @@ struct (* real beginning of the [analyze] function *) if get_bool "ana.sv-comp.enabled" then Witness.init (module FileCfg); (* TODO: move this out of analyze_loop *) + YamlWitness.init (); AnalysisState.global_initialization := true; GobConfig.earlyglobs := get_bool "exp.earlyglobs"; diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index bb91e195ef..7134211d32 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -514,6 +514,15 @@ struct Timing.wrap "yaml witness" write () end +let init () = + match GobConfig.get_string "witness.yaml.validate" with + | "" -> () + | path -> + (* Check witness existence before doing the analysis. *) + if not (Sys.file_exists path) then ( + Logs.error "witness.yaml.validate: %s not found" path; + Svcomp.errorwith "witness missing" + ) module ValidationResult = struct From 05397c58b551d94dfb3532ed9952ab0d50edfc51 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 25 Jun 2024 15:22:44 +0300 Subject: [PATCH 396/689] Add Karoliine to authors --- .zenodo.json | 5 +++++ CITATION.cff | 4 ++++ dune-project | 2 +- goblint.opam | 1 + goblint.opam.locked | 1 + 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.zenodo.json b/.zenodo.json index 22705c2d9c..1e71573948 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -23,6 +23,11 @@ "affiliation": "Technische Universität München", "orcid": "0009-0009-9644-7475" }, + { + "name": "Holter, Karoliine", + "affiliation": "University of Tartu", + "orcid": "0009-0008-3725-4131" + }, { "name": "Vogler, Ralf", "affiliation": "Technische Universität München" diff --git a/CITATION.cff b/CITATION.cff index 25d46cf762..7a93859c54 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -21,6 +21,10 @@ authors: # same authors as in .zenodo.json and dune-project family-names: Tilscher affiliation: "Technische Universität München" orcid: "https://orcid.org/0009-0009-9644-7475" + - given-names: Karoliine + family-names: Holter + affiliation: "University of Tartu" + orcid: "https://orcid.org/0009-0008-3725-4131" - given-names: Ralf family-names: Vogler affiliation: "Technische Universität München" diff --git a/dune-project b/dune-project index 878abd3b4f..b85a82b93f 100644 --- a/dune-project +++ b/dune-project @@ -15,7 +15,7 @@ (source (github goblint/analyzer)) (homepage "https://goblint.in.tum.de") (documentation "https://goblint.readthedocs.io/en/latest/") -(authors "Simmo Saan" "Michael Schwarz" "Julian Erhard" "Sarah Tilscher" "Ralf Vogler" "Kalmer Apinis" "Vesal Vojdani" ) ; same authors as in .zenodo.json and CITATION.cff +(authors "Simmo Saan" "Michael Schwarz" "Julian Erhard" "Sarah Tilscher" "Karoliine Holter" "Ralf Vogler" "Kalmer Apinis" "Vesal Vojdani" ) ; same authors as in .zenodo.json and CITATION.cff (maintainers "Simmo Saan " "Michael Schwarz " "Karoliine Holter") (license MIT) diff --git a/goblint.opam b/goblint.opam index 692625c965..03e11d456a 100644 --- a/goblint.opam +++ b/goblint.opam @@ -11,6 +11,7 @@ authors: [ "Michael Schwarz" "Julian Erhard" "Sarah Tilscher" + "Karoliine Holter" "Ralf Vogler" "Kalmer Apinis" "Vesal Vojdani" diff --git a/goblint.opam.locked b/goblint.opam.locked index f8de683948..0cf9a2ff75 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -12,6 +12,7 @@ authors: [ "Michael Schwarz" "Julian Erhard" "Sarah Tilscher" + "Karoliine Holter" "Ralf Vogler" "Kalmer Apinis" "Vesal Vojdani" From 1e705fa4925863dd9a52a7b9e5070c9f7b97fe0a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 25 Jun 2024 21:56:56 +0300 Subject: [PATCH 397/689] Rewrite pointer arithmethic not overflowing assumption --- docs/user-guide/assumptions.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/user-guide/assumptions.md b/docs/user-guide/assumptions.md index 16386987de..33284ccc00 100644 --- a/docs/user-guide/assumptions.md +++ b/docs/user-guide/assumptions.md @@ -17,12 +17,22 @@ _NB! This list is likely incomplete._ See [PR #1414](https://github.com/goblint/analyzer/pull/1414). -2. Goblint's does not give any guarantees about overflows not happening during pointer arithmetics. +2. Pointer arithmetic does not overflow. - Although the analysis can detect and warn about overflows that might happen during operations with pointer offsets, - the analysis does not warn about overflows from operations with the possible addresses (as integers) of the pointers themselves. + [C11's N1570][n1570] at 6.5.6.8 states that - This affects the `no-overflows` analysis from `ana.int.interval` analysis. + > When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. + > [...] + > the evaluation shall not produce an overflow; otherwise, the behavior is undefined. - See further discussion from [PR #1511](https://github.com/goblint/analyzer/pull/1511). + after a long list of defined behaviors. + Goblint does not report overflow and out-of-bounds pointer arithmetic (when the pointer _is not dereferenced_). + This affects the overflow analysis (SV-COMP no-overflow property) in the `base` analysis. + + This _does not_ affect the `memOutOfBounds` analysis (SV-COMP valid-memsafety property), which is for undefined behavior from _dereferencing_ such out-of-bounds pointers. + + See [PR #1511](https://github.com/goblint/analyzer/pull/1511). + + +[n1570]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf From a1bfc416569028f2f03c43d5df9840e2ac9aa3e6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 26 Jun 2024 11:45:25 +0300 Subject: [PATCH 398/689] Upgrade locked OCaml to 4.14.2 --- .github/workflows/coverage.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/locked.yml | 6 +++--- .github/workflows/unlocked.yml | 8 ++++---- goblint.opam.locked | 4 ++-- gobview | 2 +- make.sh | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d4fc872620..1e1991e2ab 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,7 +18,7 @@ jobs: os: - ubuntu-latest ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used runs-on: ${{ matrix.os }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 242acef3de..bae49437dd 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -18,7 +18,7 @@ jobs: os: - ubuntu-latest ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used runs-on: ${{ matrix.os }} diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 18935725ca..a7f8787305 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -20,7 +20,7 @@ jobs: - ubuntu-latest - macos-13 ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used runs-on: ${{ matrix.os }} @@ -73,7 +73,7 @@ jobs: os: - ubuntu-latest ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used runs-on: ${{ matrix.os }} @@ -116,7 +116,7 @@ jobs: os: - ubuntu-latest ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used node-version: - 14 diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index db41ad3007..af32008400 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -21,7 +21,7 @@ jobs: - 5.2.x - 5.1.x - 5.0.x - - ocaml-variants.4.14.0+options,ocaml-option-flambda + - ocaml-variants.4.14.2+options,ocaml-option-flambda - 4.14.x apron: - false @@ -92,7 +92,7 @@ jobs: - ubuntu-latest - macos-13 ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file, downgrade deps step + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file, downgrade deps step name: lower-bounds (${{ matrix.os }}, ${{ matrix.ocaml-compiler }}, downgrade) @@ -133,7 +133,7 @@ jobs: - name: Downgrade dependencies # must specify ocaml-base-compiler again to prevent it from being downgraded # prevent num downgrade to avoid dune/jbuilder error: https://github.com/ocaml/dune/issues/5280 - run: opam install $(opam exec -- opam-0install --prefer-oldest goblint ocaml-variants.4.14.0+options ocaml-option-flambda num.1.5) + run: opam install $(opam exec -- opam-0install --prefer-oldest goblint ocaml-variants.4.14.2+options ocaml-option-flambda num.1.5) - name: Build run: ./make.sh nat @@ -190,7 +190,7 @@ jobs: - ubuntu-latest - macos-13 ocaml-compiler: - - ocaml-variants.4.14.0+options,ocaml-option-flambda # matches opam lock file + - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file runs-on: ${{ matrix.os }} diff --git a/goblint.opam.locked b/goblint.opam.locked index 410d363ac8..26f8bb53e7 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -71,12 +71,12 @@ depends: [ "logs" {= "0.7.0"} "mlgmpidl" {= "1.3.0"} "num" {= "1.5"} - "ocaml" {= "4.14.0"} + "ocaml" {= "4.14.2"} "ocaml-compiler-libs" {= "v0.12.4"} "ocaml-config" {= "2"} "ocaml-option-flambda" {= "1"} "ocaml-syntax-shims" {= "1.0.0"} - "ocaml-variants" {= "4.14.0+options"} + "ocaml-variants" {= "4.14.2+options"} "ocamlbuild" {= "0.14.3"} "ocamlfind" {= "1.9.6"} "odoc" {= "2.4.2" & with-doc} diff --git a/gobview b/gobview index 287bf59be9..4069f32f82 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 287bf59be9e25ceea704384c65e0d91565bb749d +Subproject commit 4069f32f82efdefb43c970fb77ca29671a4b6972 diff --git a/make.sh b/make.sh index 5b55e51beb..0f76759065 100755 --- a/make.sh +++ b/make.sh @@ -8,7 +8,7 @@ opam_setup() { set -x opam init -y -a --bare $SANDBOXING # sandboxing is disabled in travis and docker opam update - opam switch -y create . --deps-only --packages=ocaml-variants.4.14.0+options,ocaml-option-flambda --locked + opam switch -y create . --deps-only --packages=ocaml-variants.4.14.2+options,ocaml-option-flambda --locked } rule() { From 56ed7b5589da639d5ec9028c8558cb75810dada1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 26 Jun 2024 17:05:20 +0300 Subject: [PATCH 399/689] Add option ana.base.invariant.int.simplify --- src/cdomain/value/cdomains/intDomain.ml | 26 ++++++++++++++++++++----- src/config/options.schema.json | 14 +++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 797c0f46c1..2d40e6a161 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -3791,11 +3791,15 @@ module IntDomTupleImpl = struct | _ -> BatPrintf.fprintf f "\n\n%s\n\n\n" (show x) let invariant_ikind e ik ((_, _, _, x_cong, x_intset) as x) = - match to_int x with - | Some v -> - (* If definite, output single equality instead of every subdomain repeating same equality (or something less precise). *) - IntInvariant.of_int e ik v - | None -> + let simplify_int fallback = + match to_int x with + | Some v -> + (* If definite, output single equality instead of every subdomain repeating same equality (or something less precise). *) + IntInvariant.of_int e ik v + | None -> + fallback () + in + let simplify_all () = match to_incl_list x with | Some ps -> (* If inclusion set, output disjunction of equalities because it subsumes interval(s), exclusion set and congruence. *) @@ -3814,6 +3818,18 @@ module IntDomTupleImpl = struct Option.map_default (I4.invariant_ikind e ik) Invariant.none x_cong && (* Output congruence as is. *) Option.map_default (I5.invariant_ikind e ik) Invariant.none x_intset (* Output interval sets as is. *) ) + in + let simplify_none () = + let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x) in + List.fold_left (fun a i -> + Invariant.(a && i) + ) (Invariant.top ()) is + in + match GobConfig.get_string "ana.base.invariant.int.simplify" with + | "none" -> simplify_none () + | "int" -> simplify_int simplify_none + | "all" -> simplify_int simplify_all + | _ -> assert false let arbitrary ik = QCheck.(set_print show @@ tup5 (option (I1.arbitrary ik)) (option (I2.arbitrary ik)) (option (I3.arbitrary ik)) (option (I4.arbitrary ik)) (option (I5.arbitrary ik))) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index acf85abed9..27cc0c7d93 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -807,6 +807,20 @@ "type": "string", "enum": ["once", "fixpoint"], "default": "once" + }, + "int": { + "title": "ana.base.invariant.int", + "type": "object", + "properties": { + "simplify": { + "title": "ana.base.invariant.int.simplify", + "description": "How much to simplify int domain invariants. Value \"int\" only simplifies definite integers. Without int domain refinement \"all\" might not be maximally precise.", + "type": "string", + "enum": ["none", "int", "all"], + "default": "all" + } + }, + "additionalProperties": false } }, "additionalProperties": false From 14e5523ce2b49eed48ec72837d9a41eff4b0f3e3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 27 Jun 2024 11:40:07 +0300 Subject: [PATCH 400/689] Remove small margin for Apron domain show --- src/cdomains/apron/apronDomain.apron.ml | 2 +- src/common/util/gobFormat.ml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/apronDomain.apron.ml b/src/cdomains/apron/apronDomain.apron.ml index d0ef268ca6..26e954f1b2 100644 --- a/src/cdomains/apron/apronDomain.apron.ml +++ b/src/cdomains/apron/apronDomain.apron.ml @@ -442,7 +442,7 @@ struct let invariant _ = [] let show (x:t) = - Format.asprintf "%a (env: %a)" A.print x (Environment.print: Format.formatter -> Environment.t -> unit) (A.env x) + Format.asprintf "%t%a (env: %a)" GobFormat.pp_set_infinite_geometry A.print x (Environment.print: Format.formatter -> Environment.t -> unit) (A.env x) let pretty () (x:t) = text (show x) let equal x y = diff --git a/src/common/util/gobFormat.ml b/src/common/util/gobFormat.ml index 3cda0a4758..1b4d28a26c 100644 --- a/src/common/util/gobFormat.ml +++ b/src/common/util/gobFormat.ml @@ -19,3 +19,7 @@ let pp_set_ansi_color_tags ppf = Format.pp_set_mark_tags ppf true let pp_print_nothing (ppf: Format.formatter) () = () + +let pp_infinity = 1000000001 (* Exact value not exposed before OCaml 5.2, but use the smallest value permitted by documentation. *) + +let pp_set_infinite_geometry = Format.pp_set_geometry ~max_indent:(pp_infinity - 2) ~margin:(pp_infinity - 1) From d2527b7f757e486cadfd551c712796cc6ee4c1b2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 27 Jun 2024 11:49:10 +0300 Subject: [PATCH 401/689] Add Printable.SimpleFormat --- src/common/domains/printable.ml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/common/domains/printable.ml b/src/common/domains/printable.ml index 1a642c932a..b6b1dc5c3a 100644 --- a/src/common/domains/printable.ml +++ b/src/common/domains/printable.ml @@ -88,6 +88,20 @@ struct let to_yojson x = `String (show x) end +module type Formatable = +sig + type t + val pp: Format.formatter -> t -> unit +end + +module SimpleFormat (P: Formatable) = +struct + let show x = Format.asprintf "%t%a" GobFormat.pp_set_infinite_geometry P.pp x + let pretty () x = text (show x) + let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) + let to_yojson x = `String (show x) +end + module type Name = sig val name: string end module UnitConf (N: Name) = From 6269d1e2942b8567601a30d35657beadeaabecaa Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 27 Jun 2024 12:02:59 +0300 Subject: [PATCH 402/689] Add some Printables to GobApron --- .../apron/affineEqualityDomain.apron.ml | 3 +- src/cdomains/apron/apronDomain.apron.ml | 18 +++--- src/cdomains/apron/gobApron.apron.ml | 56 ++++++++++++++++++- .../apron/linearTwoVarEqualityDomain.apron.ml | 6 +- src/cdomains/apron/sharedFunctions.apron.ml | 2 +- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/cdomains/apron/affineEqualityDomain.apron.ml b/src/cdomains/apron/affineEqualityDomain.apron.ml index 7e60cce74b..6bef6c329e 100644 --- a/src/cdomains/apron/affineEqualityDomain.apron.ml +++ b/src/cdomains/apron/affineEqualityDomain.apron.ml @@ -206,8 +206,7 @@ struct Format.asprintf "%s" ("[|"^ (String.concat "; " constraint_list) ^"|]") let pretty () (x:t) = text (show x) - let printXml f x = BatPrintf.fprintf f "\n\n\nmatrix\n\n\n%s\n\nenv\n\n\n%s\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) (XmlUtil.escape (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (x.env))) - + let printXml f x = BatPrintf.fprintf f "\n\n\nmatrix\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) Environment.printXml x.env let eval_interval ask = Bounds.bound_texpr let name () = "affeq" diff --git a/src/cdomains/apron/apronDomain.apron.ml b/src/cdomains/apron/apronDomain.apron.ml index 26e954f1b2..826eec0715 100644 --- a/src/cdomains/apron/apronDomain.apron.ml +++ b/src/cdomains/apron/apronDomain.apron.ml @@ -283,7 +283,7 @@ struct let assign_exp_with ask nd v e no_ov = match Convert.texpr1_of_cil_exp ask nd (A.env nd) e no_ov with | texpr1 -> - if M.tracing then M.trace "apron" "assign_exp converted: %s" (Format.asprintf "%a" Texpr1.print texpr1); + if M.tracing then M.trace "apron" "assign_exp converted: %a" Texpr1.pretty texpr1; A.assign_texpr_with Man.mgr nd v texpr1 None | exception Convert.Unsupported_CilExp _ -> if M.tracing then M.trace "apron" "assign_exp unsupported"; @@ -442,7 +442,7 @@ struct let invariant _ = [] let show (x:t) = - Format.asprintf "%t%a (env: %a)" GobFormat.pp_set_infinite_geometry A.print x (Environment.print: Format.formatter -> Environment.t -> unit) (A.env x) + Format.asprintf "%t%a (env: %a)" GobFormat.pp_set_infinite_geometry A.print x Environment.pp (A.env x) let pretty () (x:t) = text (show x) let equal x y = @@ -454,7 +454,7 @@ struct let compare (x:t) y: int = (* there is no A.compare, but polymorphic compare should delegate to Abstract0 and Environment compare's implemented in Apron's C *) Stdlib.compare x y - let printXml f x = BatPrintf.fprintf f "\n\n\nconstraints\n\n\n%s\n\nenv\n\n\n%s\n\n\n" (XmlUtil.escape (Format.asprintf "%a" A.print x)) (XmlUtil.escape (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (A.env x))) + let printXml f x = BatPrintf.fprintf f "\n\n\nconstraints\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (Format.asprintf "%a" A.print x)) Environment.printXml (A.env x) let to_yojson (x: t) = let constraints = @@ -463,11 +463,9 @@ struct |> Lincons1Set.elements |> List.map (fun lincons1 -> `String (Lincons1.show lincons1)) in - let env = `String (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (A.env x)) - in `Assoc [ ("constraints", `List constraints); - ("env", env); + ("env", Environment.to_yojson (A.env x)); ] let unify x y = @@ -533,9 +531,9 @@ struct | _ -> begin match Convert.tcons1_of_cil_exp ask d (A.env d) e negate no_ov with | tcons1 -> - if M.tracing then M.trace "apron" "assert_constraint %a %s" d_exp e (Format.asprintf "%a" Tcons1.print tcons1); + if M.tracing then M.trace "apron" "assert_constraint %a %a" d_exp e Tcons1.pretty tcons1; if M.tracing then M.trace "apron" "assert_constraint st: %a" D.pretty d; - if M.tracing then M.trace "apron" "assert_constraint tcons1: %s" (Format.asprintf "%a" Tcons1.print tcons1); + if M.tracing then M.trace "apron" "assert_constraint tcons1: %a" Tcons1.pretty tcons1; let r = meet_tcons ask d tcons1 e in if M.tracing then M.trace "apron" "assert_constraint r: %a" D.pretty r; r @@ -598,7 +596,7 @@ struct let x_cons = A.to_lincons_array Man.mgr x_j in let y_cons = A.to_lincons_array Man.mgr y_j in let try_add_con j con1 = - if M.tracing then M.tracei "apron" "try_add_con %s" (Format.asprintf "%a" (Lincons1.print: Format.formatter -> Lincons1.t -> unit) con1); + if M.tracing then M.tracei "apron" "try_add_con %a" Lincons1.pretty con1; let t = meet_lincons j con1 in let t_x = A.change_environment Man.mgr t x_env false in let t_y = A.change_environment Man.mgr t y_env false in @@ -637,7 +635,7 @@ struct in let env_exists_mem_con1 env con1 = let r = env_exists_mem_con1 env con1 in - if M.tracing then M.trace "apron" "env_exists_mem_con1 %s %s -> %B" (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) env) (Lincons1.show con1) r; + if M.tracing then M.trace "apron" "env_exists_mem_con1 %a %a -> %B" Environment.pretty env Lincons1.pretty con1 r; r in (* Heuristically reorder constraints to pass 36/12 with singlethreaded->multithreaded mode switching. *) diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index e202a88c60..f2322c1473 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -18,7 +18,14 @@ module Lincons1 = struct include Lincons1 - let show = Format.asprintf "%a" print + let pp = print + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) + let compare x y = String.compare (show x) (show y) (* HACK *) let num_vars x = @@ -43,12 +50,59 @@ struct |> of_enum end +module Texpr1 = +struct + include Texpr1 + + let pp = print + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) + + module Expr = + struct + type t = expr + + let pp = print_expr + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) + end +end + +module Tcons1 = +struct + include Tcons1 + + let pp = print + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) +end + (** A few code elements for environment changes from functions as remove_vars etc. have been moved to sharedFunctions as they are needed in a similar way inside affineEqualityDomain. A module that includes various methods used by variable handling operations such as add_vars, remove_vars etc. in apronDomain and affineEqualityDomain. *) module Environment = struct include Environment + let pp: Format.formatter -> Environment.t -> unit = Environment.print + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) + let ivars_only env = let ivs, fvs = Environment.vars env in assert (Array.length fvs = 0); (* shouldn't ever contain floats *) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 5558bc2c96..fa71e3d1a5 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -11,7 +11,7 @@ open Batteries open GoblintCil open Pretty module M = Messages -open Apron +open GobApron open VectorMatrix module Mpqf = SharedFunctions.Mpqf @@ -331,7 +331,7 @@ struct let simplified_monomials_from_texp (t: t) texp = let res = simplified_monomials_from_texp t texp in - if M.tracing then M.tracel "from_texp" "%s %s -> %s" (EConj.show @@ snd @@ BatOption.get t.d) (Format.asprintf "%a" Texpr1.print_expr texp) + if M.tracing then M.tracel "from_texp" "%s %a -> %s" (EConj.show @@ snd @@ BatOption.get t.d) Texpr1.Expr.pretty texp (BatOption.map_default (fun (l,(o,d)) -> List.fold_right (fun (a,x,b) acc -> Printf.sprintf "%s*var_%d/%s + %s" (Z.to_string a) x (Z.to_string b) acc) l ((Z.to_string o)^"/"^(Z.to_string d))) "" res); res @@ -424,7 +424,7 @@ struct EConj.show_formatted (show_var varM.env) (snd arr) ^ (to_subscript @@ fst arr) let pretty () (x:t) = text (show x) - let printXml f x = BatPrintf.fprintf f "\n\n\nequalities\n\n\n%s\n\nenv\n\n\n%s\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) (XmlUtil.escape (Format.asprintf "%a" (Environment.print: Format.formatter -> Environment.t -> unit) (x.env))) + let printXml f x = BatPrintf.fprintf f "\n\n\nequalities\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) Environment.printXml x.env let eval_interval ask = Bounds.bound_texpr let meet_with_one_conj t i (var, o, divi) = diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 8c94c996b0..9627b4762a 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -196,7 +196,7 @@ struct in let exp = Cil.constFold false exp in let res = conv exp in - if M.tracing then M.trace "relation" "texpr1_expr_of_cil_exp: %a -> %s (%b)" d_plainexp exp (Format.asprintf "%a" Texpr1.print_expr res) (Lazy.force no_ov); + if M.tracing then M.trace "relation" "texpr1_expr_of_cil_exp: %a -> %a (%b)" d_plainexp exp Texpr1.Expr.pretty res (Lazy.force no_ov); res let texpr1_of_cil_exp ask d env e no_ov = From e37b7d756ee7f0fcd4a8f56ded7f01adf89d090f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 27 Jun 2024 12:06:04 +0300 Subject: [PATCH 403/689] Remove pointless `Format.asprintf "%s"` --- src/cdomains/apron/affineEqualityDomain.apron.ml | 4 ++-- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cdomains/apron/affineEqualityDomain.apron.ml b/src/cdomains/apron/affineEqualityDomain.apron.ml index 6bef6c329e..8bb99f2264 100644 --- a/src/cdomains/apron/affineEqualityDomain.apron.ml +++ b/src/cdomains/apron/affineEqualityDomain.apron.ml @@ -203,10 +203,10 @@ struct | Some m when Matrix.is_empty m -> "⊤" | Some m -> let constraint_list = List.init (Matrix.num_rows m) (fun i -> vec_to_constraint (conv_to_ints @@ Matrix.get_row m i) t.env) in - Format.asprintf "%s" ("[|"^ (String.concat "; " constraint_list) ^"|]") + "[|"^ (String.concat "; " constraint_list) ^"|]" let pretty () (x:t) = text (show x) - let printXml f x = BatPrintf.fprintf f "\n\n\nmatrix\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) Environment.printXml x.env + let printXml f x = BatPrintf.fprintf f "\n\n\nmatrix\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (show x)) Environment.printXml x.env let eval_interval ask = Bounds.bound_texpr let name () = "affeq" diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index fa71e3d1a5..bd6b81402a 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -424,7 +424,7 @@ struct EConj.show_formatted (show_var varM.env) (snd arr) ^ (to_subscript @@ fst arr) let pretty () (x:t) = text (show x) - let printXml f x = BatPrintf.fprintf f "\n\n\nequalities\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (Format.asprintf "%s" (show x) )) Environment.printXml x.env + let printXml f x = BatPrintf.fprintf f "\n\n\nequalities\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (show x)) Environment.printXml x.env let eval_interval ask = Bounds.bound_texpr let meet_with_one_conj t i (var, o, divi) = From 5ea925eab57750f77acad4081dc6d46d6016814d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 27 Jun 2024 12:28:09 +0300 Subject: [PATCH 404/689] Extract GobFormat.asprintf --- src/cdomains/apron/apronDomain.apron.ml | 4 ++-- src/common/domains/printable.ml | 2 +- src/common/util/gobFormat.ml | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cdomains/apron/apronDomain.apron.ml b/src/cdomains/apron/apronDomain.apron.ml index 826eec0715..777db5a297 100644 --- a/src/cdomains/apron/apronDomain.apron.ml +++ b/src/cdomains/apron/apronDomain.apron.ml @@ -442,7 +442,7 @@ struct let invariant _ = [] let show (x:t) = - Format.asprintf "%t%a (env: %a)" GobFormat.pp_set_infinite_geometry A.print x Environment.pp (A.env x) + GobFormat.asprintf "%a (env: %a)" A.print x Environment.pp (A.env x) let pretty () (x:t) = text (show x) let equal x y = @@ -454,7 +454,7 @@ struct let compare (x:t) y: int = (* there is no A.compare, but polymorphic compare should delegate to Abstract0 and Environment compare's implemented in Apron's C *) Stdlib.compare x y - let printXml f x = BatPrintf.fprintf f "\n\n\nconstraints\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (Format.asprintf "%a" A.print x)) Environment.printXml (A.env x) + let printXml f x = BatPrintf.fprintf f "\n\n\nconstraints\n\n\n%s\n\nenv\n\n\n%a\n\n\n" (XmlUtil.escape (GobFormat.asprint A.print x)) Environment.printXml (A.env x) let to_yojson (x: t) = let constraints = diff --git a/src/common/domains/printable.ml b/src/common/domains/printable.ml index b6b1dc5c3a..ee0eda0766 100644 --- a/src/common/domains/printable.ml +++ b/src/common/domains/printable.ml @@ -96,7 +96,7 @@ end module SimpleFormat (P: Formatable) = struct - let show x = Format.asprintf "%t%a" GobFormat.pp_set_infinite_geometry P.pp x + let show x = GobFormat.asprint P.pp x let pretty () x = text (show x) let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) let to_yojson x = `String (show x) diff --git a/src/common/util/gobFormat.ml b/src/common/util/gobFormat.ml index 1b4d28a26c..8f26ff0087 100644 --- a/src/common/util/gobFormat.ml +++ b/src/common/util/gobFormat.ml @@ -23,3 +23,8 @@ let pp_print_nothing (ppf: Format.formatter) () = () let pp_infinity = 1000000001 (* Exact value not exposed before OCaml 5.2, but use the smallest value permitted by documentation. *) let pp_set_infinite_geometry = Format.pp_set_geometry ~max_indent:(pp_infinity - 2) ~margin:(pp_infinity - 1) + +let asprintf (fmt: ('a, Format.formatter, unit, string) format4): 'a = + Format.asprintf ("%t" ^^ fmt) pp_set_infinite_geometry + +let asprint pp x = asprintf "%a" pp x (* eta-expanded to bypass value restriction *) From c2db27d9de0bda2d9de7c91d89a7c03496421446 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 27 Jun 2024 12:36:49 +0300 Subject: [PATCH 405/689] Remove some trailing whitespace --- .../apron/linearTwoVarEqualityDomain.apron.ml | 24 +++++++++---------- src/cdomains/apron/sharedFunctions.apron.ml | 2 +- src/common/domains/printable.ml | 10 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index 5558bc2c96..3a9e2d3e11 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -158,7 +158,7 @@ module EqualitiesConjunction = struct let (newref,offs,divi) = (get_rhs d head) in let (coeff,y) = BatOption.get newref in let (y,yrhs) = inverse head (coeff,y,offs,divi) in (* reassemble yrhs out of components *) - let shifted_cluster = (List.fold (fun map i -> + let shifted_cluster = (List.fold (fun map i -> let irhs = (get_rhs d i) in (* old entry is i = irhs *) Rhs.subst yrhs y irhs |> (* new entry for i is irhs [yrhs/y] *) set_rhs map i @@ -222,7 +222,7 @@ module EqualitiesConjunction = struct | Some (coeff,j), ((Some (coeff1,h1), o1, divi1) as oldi)-> (match get_rhs ts j with (* ts[x_j]=o2/d2 ========> ... *) - | (None , o2, divi2) -> + | (None , o2, divi2) -> let newxi = Rhs.subst (None,o2,divi2) j (Some (coeff,j),offs,divi) in let newxh1 = snd @@ inverse i (coeff1,h1,o1,divi1) in let newxh1 = Rhs.subst newxi i newxh1 in @@ -251,7 +251,7 @@ module EqualitiesConjunction = struct else (* var_i = var_i, i.e. it may occur on the rhs of other equalities *) (* so now, we transform with the inverse of the transformer: *) let inv = snd (inverse i (coeff,j,offs,divi)) in - IntMap.fold (fun k v acc -> + IntMap.fold (fun k v acc -> match v with | (Some (c,x),o,d) when x=i-> set_rhs acc k (Rhs.subst inv i v) | _ -> acc @@ -281,7 +281,7 @@ struct let multiply a b = (* if one of them is a constant, then multiply. Otherwise, the expression is not linear *) match a, b with - | [(None,coeff, divi)], c + | [(None,coeff, divi)], c | c, [(None,coeff, divi)] -> multiply_with_Q coeff divi c | _ -> raise NotLinearExpr in @@ -314,7 +314,7 @@ struct | x -> Some(x) (** convert and simplify (wrt. reference variables) a texpr into a tuple of a list of monomials (coeff,varidx,divi) and a (constant/divi) *) - let simplified_monomials_from_texp (t: t) texp = + let simplified_monomials_from_texp (t: t) texp = BatOption.bind (monomials_from_texp t texp) (fun monomiallist -> let d = Option.get t.d in @@ -323,7 +323,7 @@ struct | None -> let gcdee = Z.gcd adiv divi in exprcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi) | Some (coeff,idx) -> let (somevar,someoffs,somedivi)=Rhs.subst (EConj.get_rhs d idx) idx (v,offs,divi) in (* normalize! *) let newcache = Option.map_default (fun (coef,ter) -> IMap.add ter Q.((IMap.find_default zero ter exprcache) + make coef somedivi) exprcache) exprcache somevar in - let gcdee = Z.gcd adiv divi in + let gcdee = Z.gcd adiv divi in (newcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi)) in let (expr,constant) = List.fold_left accumulate_constants (IMap.empty,(Z.zero,Z.one)) monomiallist in (* abstract simplification of the guard wrt. reference variables *) @@ -339,7 +339,7 @@ struct BatOption.bind (simplified_monomials_from_texp t texp ) (fun (sum_of_terms, (constant,divisor)) -> (match sum_of_terms with - | [] -> Some (None, constant,divisor) + | [] -> Some (None, constant,divisor) | [(coeff,var,divi)] -> Some (Rhs.canonicalize (Some (Z.mul divisor coeff,var), Z.mul constant divi,Z.mul divisor divi)) |_ -> None)) @@ -447,7 +447,7 @@ struct let t1 = change_d t1 sup_env ~add:true ~del:false in let t2 = change_d t2 sup_env ~add:true ~del:false in match t1.d, t2.d with - | Some d1', Some d2' -> + | Some d1', Some d2' -> EConj.IntMap.fold (fun lhs rhs map -> meet_with_one_conj map lhs rhs) (snd d2') t1 (* even on sparse d2, this will chose the relevant conjs to meet with*) | _ -> {d = None; env = sup_env} @@ -489,7 +489,7 @@ struct - lhs itself - criteria A and B that characterize equivalence class, depending on the reference variable and the affine expression parameters wrt. each EConj - rhs1 - - rhs2 + - rhs2 however, we have to account for the sparseity of EConj maps by manually patching holes with default values *) let joinfunction lhs rhs1 rhs2 = ( @@ -516,15 +516,15 @@ struct let varentry ci offi ch offh xh = let (coeff,off,d) = Q.(ci,(offi*ch)-(ci*offh),ch) in (* compute new rhs in Q *) let (coeff,off,d) = Z.(coeff.num*d.den*off.den,off.num*d.den*coeff.den,d. num*coeff.den*off.den) in (* convert that back into Z *) - Rhs.canonicalize (Some(coeff,xh),off,d) + Rhs.canonicalize (Some(coeff,xh),off,d) in (* ci1 = a*ch1+b /\ ci2 = a*ch2+b *) (* ===> a = (ci1-ci2)/(ch1-ch2) b = ci2-a*ch2 *) - let constentry ci1 ci2 ch1 ch2 xh = + let constentry ci1 ci2 ch1 ch2 xh = let a = Q.((ci1-ci2) / (ch1-ch2)) in let b = Q.(ci2 - a*ch2) in Rhs.canonicalize (Some (Z.(a.num*b.den),xh),Z.(b.num*a.den) ,Z.(a.den*b.den) ) in - let iterate map l = + let iterate map l = match l with | (_, _, _, rhs , rhs' ) :: t when Rhs.equal rhs rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(monom,oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 8c94c996b0..8167667293 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -136,7 +136,7 @@ struct let expr = (** simplify asks for a constant value of some subexpression e, similar to a constant fold. In particular but not exclusively this query is answered by the 2 var equalities domain itself. This normalizes arbitrary expressions to a point where they - might be able to be represented by means of 2 var equalities + might be able to be represented by means of 2 var equalities This simplification happens during a time, when there are temporary variables a#in and a#out part of the expression, but are not represented in the ctx, thus queries may result in top for these variables. Wrapping this in speculative diff --git a/src/common/domains/printable.ml b/src/common/domains/printable.ml index 1a642c932a..199113a5d8 100644 --- a/src/common/domains/printable.ml +++ b/src/common/domains/printable.ml @@ -588,7 +588,7 @@ module Prod4 (Base1: S) (Base2: S) (Base3: S) (Base4: S) = struct let arbitrary () = QCheck.quad (Base1.arbitrary ()) (Base2.arbitrary ()) (Base3.arbitrary ()) (Base4.arbitrary ()) end -module PQueue (Base: S) = +module PQueue (Base: S) = struct type t = Base.t BatDeque.dq include Std @@ -604,22 +604,22 @@ struct let rec loop n q = match BatDeque.front q with | None -> () - | Some (x, xs) -> (BatPrintf.fprintf f "%d\n%a\n" n Base.printXml x; + | Some (x, xs) -> (BatPrintf.fprintf f "%d\n%a\n" n Base.printXml x; loop (n+1) (xs)) in BatPrintf.fprintf f "\n\n"; - loop 0 xs; + loop 0 xs; BatPrintf.fprintf f "\n\n" let to_yojson q = `List (BatDeque.to_list @@ BatDeque.map (Base.to_yojson) q) let hash q = BatDeque.fold_left (fun acc x -> (acc + 71) * (Base.hash x)) 11 q let equal q1 q2 = BatDeque.eq ~eq:Base.equal q1 q2 - let compare q1 q2 = + let compare q1 q2 = match BatDeque.front q1, BatDeque.front q2 with | None, None -> 0 | None, Some(_, _) -> -1 | Some(_, _), None -> 1 - | Some(a1, q1'), Some(a2, q2') -> + | Some(a1, q1'), Some(a2, q2') -> let c = Base.compare a1 a2 in if c <> 0 then c else compare q1' q2' From 47b9f44d67539fed3fc534a22ea999d47d656417 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 28 Jun 2024 12:09:47 +0300 Subject: [PATCH 406/689] Add package description (closes #1528) --- dune-project | 5 +++++ goblint.opam | 5 +++++ goblint.opam.locked | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/dune-project b/dune-project index b85a82b93f..f07ccf4236 100644 --- a/dune-project +++ b/dune-project @@ -22,6 +22,11 @@ (package (name goblint) (synopsis "Static analysis framework for C") + (description "\ +Goblint is a sound static analysis framework for C programs using abstract interpretation. +It specializes in thread-modular verification of multi-threaded programs, especially regarding data races. +Goblint includes analyses for assertions, overflows, deadlocks, etc and can be extended with new analyses. +") (depends (ocaml (>= 4.14)) (goblint-cil (>= 2.0.3)) ; TODO no way to define as pin-depends? Used goblint.opam.template to add it for now. https://github.com/ocaml/dune/issues/3231. Alternatively, removing this line and adding cil as a git submodule and `(vendored_dirs cil)` as ./dune also works. This way, no more need to reinstall the pinned cil opam package on changes. However, then cil is cleaned and has to be rebuild together with goblint. diff --git a/goblint.opam b/goblint.opam index 03e11d456a..eec74439a0 100644 --- a/goblint.opam +++ b/goblint.opam @@ -1,6 +1,11 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" synopsis: "Static analysis framework for C" +description: """ +Goblint is a sound static analysis framework for C programs using abstract interpretation. +It specializes in thread-modular verification of multi-threaded programs, especially regarding data races. +Goblint includes analyses for assertions, overflows, deadlocks, etc and can be extended with new analyses. +""" maintainer: [ "Simmo Saan " "Michael Schwarz " diff --git a/goblint.opam.locked b/goblint.opam.locked index 0cf9a2ff75..90bfba68f0 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -143,3 +143,7 @@ pin-depends: [ ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} +description: """\ +Goblint is a sound static analysis framework for C programs using abstract interpretation. +It specializes in thread-modular verification of multi-threaded programs, especially regarding data races. +Goblint includes analyses for assertions, overflows, deadlocks, etc and can be extended with new analyses.""" From c078eaa015ef54bf70b4d0598dea46ef1675c70e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 28 Jun 2024 12:19:19 +0300 Subject: [PATCH 407/689] Add package tags --- dune-project | 8 ++++++++ goblint.opam | 9 +++++++++ goblint.opam.locked | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/dune-project b/dune-project index f07ccf4236..8d9d53623b 100644 --- a/dune-project +++ b/dune-project @@ -27,6 +27,14 @@ Goblint is a sound static analysis framework for C programs using abstract inter It specializes in thread-modular verification of multi-threaded programs, especially regarding data races. Goblint includes analyses for assertions, overflows, deadlocks, etc and can be extended with new analyses. ") + (tags ( + "program analysis" + "program verification" + "static analysis" + "abstract interpretation" + "C" + "data race analysis" + "concurrency")) (depends (ocaml (>= 4.14)) (goblint-cil (>= 2.0.3)) ; TODO no way to define as pin-depends? Used goblint.opam.template to add it for now. https://github.com/ocaml/dune/issues/3231. Alternatively, removing this line and adding cil as a git submodule and `(vendored_dirs cil)` as ./dune also works. This way, no more need to reinstall the pinned cil opam package on changes. However, then cil is cleaned and has to be rebuild together with goblint. diff --git a/goblint.opam b/goblint.opam index eec74439a0..e198bf6f3c 100644 --- a/goblint.opam +++ b/goblint.opam @@ -22,6 +22,15 @@ authors: [ "Vesal Vojdani" ] license: "MIT" +tags: [ + "program analysis" + "program verification" + "static analysis" + "abstract interpretation" + "C" + "data race analysis" + "concurrency" +] homepage: "https://goblint.in.tum.de" doc: "https://goblint.readthedocs.io/en/latest/" bug-reports: "https://github.com/goblint/analyzer/issues" diff --git a/goblint.opam.locked b/goblint.opam.locked index 90bfba68f0..b1d8030c1c 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -147,3 +147,12 @@ description: """\ Goblint is a sound static analysis framework for C programs using abstract interpretation. It specializes in thread-modular verification of multi-threaded programs, especially regarding data races. Goblint includes analyses for assertions, overflows, deadlocks, etc and can be extended with new analyses.""" +tags: [ + "program analysis" + "program verification" + "static analysis" + "abstract interpretation" + "C" + "data race analysis" + "concurrency" +] From 4fe33dcf25c095acd6e2a561ffa779e7d9b87a93 Mon Sep 17 00:00:00 2001 From: "Dr. Michael Petter" Date: Fri, 28 Jun 2024 11:22:34 +0200 Subject: [PATCH 408/689] make sure that exact division is possible --- src/cdomains/apron/sharedFunctions.apron.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 022e60200d..e46f8b2f4b 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -33,7 +33,9 @@ let int_of_scalar ?(scalewith=Z.one) ?round (scalar: Scalar.t) = begin match round with | Some `Floor -> Some (Mpzf.mul scale (Mpzf.fdiv_q n d)) (* floor division *) | Some `Ceil -> Some (Mpzf.mul scale (Mpzf.cdiv_q n d)) (* ceiling division *) - | None -> Some (Mpzf.divexact (Mpzf.mul scale n ) d) (* scale, preferably with common denominator *) + | None -> if Mpz.divisible_p (Mpzf.mul scale n ) d then + Some (Mpzf.divexact (Mpzf.mul scale n ) d) (* scale, preferably with common denominator *) + else None end in Z_mlgmpidl.z_of_mpzf z From 8ddbc43a728260596995cf9ecfb9cbbb6049171f Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 28 Jun 2024 15:44:24 +0300 Subject: [PATCH 409/689] Update results table in relationalAnalysis only if exp.relation.prec-dump is set --- src/analyses/apron/relationAnalysis.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index a42d78d71a..ad99e26b58 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -756,7 +756,7 @@ struct let sync ctx reason = (* After the solver is finished, store the results (for later comparison) *) - if !AnalysisState.postsolving then begin + if !AnalysisState.postsolving && GobConfig.get_string "exp.relation.prec-dump" <> "" then begin let keep_local = GobConfig.get_bool "ana.relation.invariant.local" in let keep_global = GobConfig.get_bool "ana.relation.invariant.global" in From 4d5a4085c67090a173ffdeb56d20b3cd0a1f5143 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 2 Jul 2024 11:06:30 +0200 Subject: [PATCH 410/689] removed unused parameter --- src/cdomains/apron/sharedFunctions.apron.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index e46f8b2f4b..9652942136 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -300,14 +300,14 @@ struct | Mpqf f -> Some (Z_mlgmpidl.q_of_mpqf f) | _ -> raise UnsupportedScalar in - let extract_den (c:Coeff.union_5) _ = + let extract_den (c:Coeff.union_5) = match c with | Scalar c -> BatOption.map Q.den (frac_of_scalar c) | _ -> None in - let lcm_denom = ref (BatOption.default Z.one (extract_den (Linexpr1.get_cst linexpr1) ())) in - let lcm_coeff (c:Coeff.union_5) v = - match (extract_den c v) with + let lcm_denom = ref (BatOption.default Z.one (extract_den (Linexpr1.get_cst linexpr1))) in + let lcm_coeff (c:Coeff.union_5) _ = + match (extract_den c) with | Some z -> lcm_denom := Z.lcm z !lcm_denom | _ -> () in From 05dfb9fcc0dfb75659767fc6d210db08023eb514 Mon Sep 17 00:00:00 2001 From: Michael Petter Date: Tue, 2 Jul 2024 13:55:47 +0200 Subject: [PATCH 411/689] pulled out product --- src/cdomains/apron/sharedFunctions.apron.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 9652942136..668b6af5d4 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -33,8 +33,8 @@ let int_of_scalar ?(scalewith=Z.one) ?round (scalar: Scalar.t) = begin match round with | Some `Floor -> Some (Mpzf.mul scale (Mpzf.fdiv_q n d)) (* floor division *) | Some `Ceil -> Some (Mpzf.mul scale (Mpzf.cdiv_q n d)) (* ceiling division *) - | None -> if Mpz.divisible_p (Mpzf.mul scale n ) d then - Some (Mpzf.divexact (Mpzf.mul scale n ) d) (* scale, preferably with common denominator *) + | None -> let product = Mpzf.mul scale n in if Mpz.divisible_p product d then + Some (Mpzf.divexact product d) (* scale, preferably with common denominator *) else None end in From dd2932f56bbabc1da077206e7cbae19f69d301d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:16:10 +0000 Subject: [PATCH 412/689] Bump ocaml/setup-ocaml from 2 to 3 Bumps [ocaml/setup-ocaml](https://github.com/ocaml/setup-ocaml) from 2 to 3. - [Release notes](https://github.com/ocaml/setup-ocaml/releases) - [Changelog](https://github.com/ocaml/setup-ocaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/ocaml/setup-ocaml/compare/v2...v3) --- updated-dependencies: - dependency-name: ocaml/setup-ocaml dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/coverage.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/indentation.yml | 2 +- .github/workflows/locked.yml | 6 +++--- .github/workflows/unlocked.yml | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d4fc872620..245c7eb23b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -35,7 +35,7 @@ jobs: # otherwise setup-ocaml pins non-locked dependencies # https://github.com/ocaml/setup-ocaml/issues/166 OPAMLOCKED: locked - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 242acef3de..253c7514b4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -35,7 +35,7 @@ jobs: # otherwise setup-ocaml pins non-locked dependencies # https://github.com/ocaml/setup-ocaml/issues/166 OPAMLOCKED: locked - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} diff --git a/.github/workflows/indentation.yml b/.github/workflows/indentation.yml index e22e674301..96ef5ee56a 100644 --- a/.github/workflows/indentation.yml +++ b/.github/workflows/indentation.yml @@ -25,7 +25,7 @@ jobs: fetch-depth: 0 - name: Set up OCaml ${{ matrix.ocaml-compiler }} - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 18935725ca..5f795fcf67 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -37,7 +37,7 @@ jobs: # otherwise setup-ocaml pins non-locked dependencies # https://github.com/ocaml/setup-ocaml/issues/166 OPAMLOCKED: locked - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) @@ -87,7 +87,7 @@ jobs: # otherwise setup-ocaml pins non-locked dependencies # https://github.com/ocaml/setup-ocaml/issues/166 OPAMLOCKED: locked - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) @@ -132,7 +132,7 @@ jobs: # otherwise setup-ocaml pins non-locked dependencies # https://github.com/ocaml/setup-ocaml/issues/166 OPAMLOCKED: locked - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index f1bd399a17..935bcfab25 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -45,7 +45,7 @@ jobs: uses: actions/checkout@v4 - name: Set up OCaml ${{ matrix.ocaml-compiler }} - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) @@ -106,7 +106,7 @@ jobs: uses: actions/checkout@v4 - name: Set up OCaml ${{ matrix.ocaml-compiler }} - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) @@ -199,7 +199,7 @@ jobs: uses: actions/checkout@v4 - name: Set up OCaml ${{ matrix.ocaml-compiler }} - uses: ocaml/setup-ocaml@v2 + uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) From d1663cfc3e073dda53f9f7d328af68cd4b727729 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 3 Jul 2024 11:39:55 +0300 Subject: [PATCH 413/689] Remove opam-depext-flags from ocaml/setup-ocaml@v3 It has been removed now and didn't work anyway. --- .github/workflows/coverage.yml | 1 - .github/workflows/locked.yml | 2 -- .github/workflows/unlocked.yml | 3 --- 3 files changed, 6 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 245c7eb23b..47feb77d0b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -38,7 +38,6 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) - name: Install graph-easy # TODO: remove if depext --with-test works if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 5f795fcf67..dbcb46635a 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -40,7 +40,6 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) - name: Install graph-easy # TODO: remove if depext --with-test works if: ${{ matrix.os == 'ubuntu-latest' }} @@ -90,7 +89,6 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) - name: Install graph-easy # TODO: remove if depext --with-test works if: ${{ matrix.os == 'ubuntu-latest' }} diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 935bcfab25..60a9003c16 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -48,7 +48,6 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) - name: Install graph-easy # TODO: remove if depext --with-test works if: ${{ matrix.os == 'ubuntu-latest' }} @@ -109,7 +108,6 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) - name: Install graph-easy # TODO: remove if depext --with-test works if: ${{ matrix.os == 'ubuntu-latest' }} @@ -202,7 +200,6 @@ jobs: uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} - opam-depext-flags: --with-test # doesn't work (https://github.com/ocaml/opam/issues/5836) - name: Install graph-easy # TODO: remove if depext --with-test works if: ${{ matrix.os == 'ubuntu-latest' }} From 502cf9f7b7ad704025270a6b8a6df1570927783a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Jul 2024 11:45:38 +0300 Subject: [PATCH 414/689] Use setup-ocaml@v2 for lower-bounds CI opam-0install is incompatible with opam 2.2 --- .github/workflows/unlocked.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 60a9003c16..e4be79e630 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -105,7 +105,7 @@ jobs: uses: actions/checkout@v4 - name: Set up OCaml ${{ matrix.ocaml-compiler }} - uses: ocaml/setup-ocaml@v3 + uses: ocaml/setup-ocaml@v2 with: ocaml-compiler: ${{ matrix.ocaml-compiler }} From 71a1657124fd4f9fb12e954f199189f8ef6e5244 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 5 Jul 2024 13:09:03 +0300 Subject: [PATCH 415/689] Remove apron v0.9.15 pin --- goblint.opam | 1 - goblint.opam.locked | 4 ---- goblint.opam.template | 1 - 3 files changed, 6 deletions(-) diff --git a/goblint.opam b/goblint.opam index ec6a1f8fcb..0cc5eab3a2 100644 --- a/goblint.opam +++ b/goblint.opam @@ -84,7 +84,6 @@ pin-depends: [ [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] # 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" ] - [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#b3172bd51e4bb0135716a300cab424a56970d96f" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index 8b184e189d..532b8e1aff 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -140,9 +140,5 @@ pin-depends: [ "ppx_deriving.5.2.1" "git+https://github.com/ocaml-ppx/ppx_deriving.git#0a89b619f94cbbfc3b0fb3255ab4fe5bc77d32d6" ] - [ - "apron.v0.9.15" - "git+https://github.com/antoinemine/apron.git#b3172bd51e4bb0135716a300cab424a56970d96f" - ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.template b/goblint.opam.template index 27be21015f..2d5ef10bc9 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -6,7 +6,6 @@ pin-depends: [ [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] # 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" ] - [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#b3172bd51e4bb0135716a300cab424a56970d96f" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} From a23b728a4023b9c8582c852b7f6d31ceb4f8b328 Mon Sep 17 00:00:00 2001 From: Fabian Stemmler Date: Thu, 11 Jul 2024 11:29:39 +0200 Subject: [PATCH 416/689] propagate bottom through narrowing operator of lifters --- src/domain/lattice.ml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/domain/lattice.ml b/src/domain/lattice.ml index 99322c09d8..d45ddcbfc2 100644 --- a/src/domain/lattice.ml +++ b/src/domain/lattice.ml @@ -277,6 +277,8 @@ struct let narrow x y = match (x,y) with | (`Lifted x, `Lifted y) -> `Lifted (Base.narrow x y) + | (_, `Bot) -> `Bot + | (`Top, y) -> y | _ -> x end @@ -337,6 +339,8 @@ struct | (`Lifted x, `Lifted y) -> (try `Lifted (Base.narrow x y) with Uncomparable -> `Bot) + | (_, `Bot) -> `Bot + | (`Top, y) -> y | _ -> x end @@ -408,6 +412,8 @@ struct match (x,y) with | (`Lifted1 x, `Lifted1 y) -> `Lifted1 (Base1.narrow x y) | (`Lifted2 x, `Lifted2 y) -> `Lifted2 (Base2.narrow x y) + | (_, `Bot) -> `Bot + | (`Top, y) -> y | _ -> x end @@ -539,6 +545,7 @@ struct let narrow x y = match (x,y) with | (`Lifted x, `Lifted y) -> `Lifted (Base.narrow x y) + | (_, `Bot) -> `Bot | _ -> x end @@ -580,6 +587,7 @@ struct let narrow x y = match (x,y) with | (`Lifted x, `Lifted y) -> `Lifted (Base.narrow x y) + | (`Top, y) -> y | _ -> x let pretty_diff () (x,y) = From 11ed4180e3064e4d43fb01751df553e233235a77 Mon Sep 17 00:00:00 2001 From: Jonas August Date: Thu, 29 Jun 2023 08:29:30 +0200 Subject: [PATCH 417/689] Fix depreciated option --- tests/regression/46-apron2/26-autotune.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/46-apron2/26-autotune.c b/tests/regression/46-apron2/26-autotune.c index 96c5c85278..ec8f55fe19 100644 --- a/tests/regression/46-apron2/26-autotune.c +++ b/tests/regression/46-apron2/26-autotune.c @@ -1,4 +1,4 @@ -//SKIP PARAM: --enable ana.int.interval --sets sem.int.signed_overflow assume_none --set ana.activated[+] apron --enable ana.autotune.enabled +//SKIP PARAM: --enable ana.int.interval --set sem.int.signed_overflow assume_none --set ana.activated[+] apron --enable ana.autotune.enabled // Check that autotuner disables context for apron as well for recursive calls #include From 0077e1d78857f238aae4fb87a0d7b0ef5aba5b9c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 15:09:51 +0300 Subject: [PATCH 418/689] Replace --sets with --set in tests --- scripts/creduce/privPrecCompare.sh | 2 +- scripts/privPrecCompare.sh | 2 +- tests/regression/01-cpa/71-widen-sides.c | 2 +- tests/regression/46-apron2/03-other-assume.c | 2 +- tests/regression/46-apron2/04-other-assume-inprec.c | 2 +- tests/regression/46-apron2/30-autotune-stub.c | 2 +- tests/regression/58-base-mm-tid/01-tid-toy1.c | 2 +- tests/regression/58-base-mm-tid/22-other-assume.c | 2 +- tests/regression/58-base-mm-tid/23-other-assume-inprec.c | 2 +- tests/regression/66-interval-set-one/51-widen-sides.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/creduce/privPrecCompare.sh b/scripts/creduce/privPrecCompare.sh index fdc5f9219d..2165112924 100755 --- a/scripts/creduce/privPrecCompare.sh +++ b/scripts/creduce/privPrecCompare.sh @@ -22,7 +22,7 @@ for PRIV in "${PRIVS[@]}"; do PRIVDUMP="$OUTDIR/$PRIV" LOG="$OUTDIR/$PRIV.log" rm -f $PRIVDUMP - $GOBLINTDIR/goblint --sets exp.privatization $PRIV --sets exp.priv-prec-dump $PRIVDUMP $OPTS -v --enable warn.debug &> $LOG + $GOBLINTDIR/goblint --set exp.privatization $PRIV --set exp.priv-prec-dump $PRIVDUMP $OPTS -v --enable warn.debug &> $LOG grep -F "Function definition missing" $LOG && exit 1 done diff --git a/scripts/privPrecCompare.sh b/scripts/privPrecCompare.sh index c5b9f2c01e..2b09fb80b5 100755 --- a/scripts/privPrecCompare.sh +++ b/scripts/privPrecCompare.sh @@ -10,7 +10,7 @@ mkdir -p $OUTDIR for PRIV in "${PRIVS[@]}"; do echo $PRIV PRIVDUMP="$OUTDIR/$PRIV" - ./goblint --sets exp.privatization $PRIV --sets exp.priv-prec-dump $PRIVDUMP "$@" + ./goblint --set exp.privatization $PRIV --set exp.priv-prec-dump $PRIVDUMP "$@" done PRIVDUMPS=("${PRIVS[*]/#/$OUTDIR/}") # why [*] here? diff --git a/tests/regression/01-cpa/71-widen-sides.c b/tests/regression/01-cpa/71-widen-sides.c index 522f6fae44..a93124c6e5 100644 --- a/tests/regression/01-cpa/71-widen-sides.c +++ b/tests/regression/01-cpa/71-widen-sides.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.ctx_insens "['base', 'mallocWrapper']" --enable ana.int.interval --sets solvers.td3.side_widen sides-local +// PARAM: --set ana.ctx_insens "['base', 'mallocWrapper']" --enable ana.int.interval --set solvers.td3.side_widen sides-local #include int further(int n) { diff --git a/tests/regression/46-apron2/03-other-assume.c b/tests/regression/46-apron2/03-other-assume.c index 635911a197..c136d1bde3 100644 --- a/tests/regression/46-apron2/03-other-assume.c +++ b/tests/regression/46-apron2/03-other-assume.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --sets ana.relation.privatization mutex-meet-tid +// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --set ana.relation.privatization mutex-meet-tid #include #include diff --git a/tests/regression/46-apron2/04-other-assume-inprec.c b/tests/regression/46-apron2/04-other-assume-inprec.c index 09b8d150a8..ccf8ecefa1 100644 --- a/tests/regression/46-apron2/04-other-assume-inprec.c +++ b/tests/regression/46-apron2/04-other-assume-inprec.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --sets ana.relation.privatization mutex-meet-tid +// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins --set ana.relation.privatization mutex-meet-tid #include #include diff --git a/tests/regression/46-apron2/30-autotune-stub.c b/tests/regression/46-apron2/30-autotune-stub.c index e1b7603c3b..02c80e7d21 100644 --- a/tests/regression/46-apron2/30-autotune-stub.c +++ b/tests/regression/46-apron2/30-autotune-stub.c @@ -1,4 +1,4 @@ -//SKIP PARAM: --enable ana.int.interval --sets sem.int.signed_overflow assume_none --set ana.activated[+] apron --enable ana.autotune.enabled +//SKIP PARAM: --enable ana.int.interval --set sem.int.signed_overflow assume_none --set ana.activated[+] apron --enable ana.autotune.enabled // Check that autotuner respect goblint_stub attributes as hints to not track variables. #include diff --git a/tests/regression/58-base-mm-tid/01-tid-toy1.c b/tests/regression/58-base-mm-tid/01-tid-toy1.c index bc3cd18efa..49e96881d1 100644 --- a/tests/regression/58-base-mm-tid/01-tid-toy1.c +++ b/tests/regression/58-base-mm-tid/01-tid-toy1.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.path_sens[+] threadflag --sets ana.base.privatization mutex-meet-tid +// PARAM: --set ana.path_sens[+] threadflag --set ana.base.privatization mutex-meet-tid // Inspired by 36/71 #include #include diff --git a/tests/regression/58-base-mm-tid/22-other-assume.c b/tests/regression/58-base-mm-tid/22-other-assume.c index 4f5c73b038..301195ac1f 100644 --- a/tests/regression/58-base-mm-tid/22-other-assume.c +++ b/tests/regression/58-base-mm-tid/22-other-assume.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.path_sens[+] threadflag --sets ana.base.privatization mutex-meet-tid +// PARAM: --set ana.path_sens[+] threadflag --set ana.base.privatization mutex-meet-tid // Copy of 46/03 for base #include #include diff --git a/tests/regression/58-base-mm-tid/23-other-assume-inprec.c b/tests/regression/58-base-mm-tid/23-other-assume-inprec.c index 37e59d3edf..a4bac04c59 100644 --- a/tests/regression/58-base-mm-tid/23-other-assume-inprec.c +++ b/tests/regression/58-base-mm-tid/23-other-assume-inprec.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.path_sens[+] threadflag --sets ana.base.privatization mutex-meet-tid --set ana.activated[+] threadJoins +// PARAM: --set ana.path_sens[+] threadflag --set ana.base.privatization mutex-meet-tid --set ana.activated[+] threadJoins // Copy of 46/04 for base #include #include diff --git a/tests/regression/66-interval-set-one/51-widen-sides.c b/tests/regression/66-interval-set-one/51-widen-sides.c index b086baf026..53fe749704 100644 --- a/tests/regression/66-interval-set-one/51-widen-sides.c +++ b/tests/regression/66-interval-set-one/51-widen-sides.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.ctx_insens "['base', 'mallocWrapper']" --enable ana.int.interval_set --sets solvers.td3.side_widen sides-local +// PARAM: --set ana.ctx_insens "['base', 'mallocWrapper']" --enable ana.int.interval_set --set solvers.td3.side_widen sides-local #include int further(int n) { From 67c18668154d79ce5cdd71c887788c8cfa09aab0 Mon Sep 17 00:00:00 2001 From: stilscher <66023521+stilscher@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:26:31 +0100 Subject: [PATCH 419/689] change may fail to fail annotation --- tests/regression/36-apron/86-branched-thread-creation.c | 2 +- tests/regression/58-base-mm-tid/15-branched-thread-creation.c | 2 +- .../67-interval-sets-two/16-branched-thread-creation.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regression/36-apron/86-branched-thread-creation.c b/tests/regression/36-apron/86-branched-thread-creation.c index cac0a881a6..91a5411e8f 100644 --- a/tests/regression/36-apron/86-branched-thread-creation.c +++ b/tests/regression/36-apron/86-branched-thread-creation.c @@ -40,7 +40,7 @@ int main(void) { if(!mt) { pthread_mutex_lock(&mutex); - __goblint_check(g==h); //MAYFAIL + __goblint_check(g==h); //FAIL pthread_mutex_unlock(&mutex); } diff --git a/tests/regression/58-base-mm-tid/15-branched-thread-creation.c b/tests/regression/58-base-mm-tid/15-branched-thread-creation.c index 3292182adc..c7bb43519f 100644 --- a/tests/regression/58-base-mm-tid/15-branched-thread-creation.c +++ b/tests/regression/58-base-mm-tid/15-branched-thread-creation.c @@ -41,7 +41,7 @@ int main(void) { if(!mt) { pthread_mutex_lock(&mutex); - __goblint_check(g==h); //MAYFAIL + __goblint_check(g==h); //FAIL pthread_mutex_unlock(&mutex); } diff --git a/tests/regression/67-interval-sets-two/16-branched-thread-creation.c b/tests/regression/67-interval-sets-two/16-branched-thread-creation.c index c309ec8ffd..d97f800621 100644 --- a/tests/regression/67-interval-sets-two/16-branched-thread-creation.c +++ b/tests/regression/67-interval-sets-two/16-branched-thread-creation.c @@ -41,7 +41,7 @@ int main(void) { if(!mt) { pthread_mutex_lock(&mutex); - __goblint_check(g==h); //MAYFAIL + __goblint_check(g==h); //FAIL pthread_mutex_unlock(&mutex); } From f1c6e2c6d4acf94a2137433d34364c8c639c9aec Mon Sep 17 00:00:00 2001 From: J2000A Date: Fri, 5 May 2023 14:41:52 +0200 Subject: [PATCH 420/689] Adjust evalAssert to offer __goblint_check(exp) with the option trans.goblint-check --- src/config/options.schema.json | 6 ++++++ src/transform/evalAssert.ml | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index d259a6f418..2e2a9212ef 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1561,6 +1561,12 @@ "description": "Output filename for transformations that output a transformed file.", "type":"string", "default": "transformed.c" + }, + "goblint-check" : { + "title": "trans.goblint-check", + "description": "Write __Goblint_Check(exp) in the file instead of __VERIFIER_assert(exp).", + "type": "boolean", + "default": false } }, "additionalProperties": false diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index eab06222ef..82b92b9040 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -26,8 +26,11 @@ module EvalAssert = struct (* should asserts be surrounded by __VERIFIER_atomic_{begin,end}? *) let surroundByAtomic = true + (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp)*) + let goblintCheck = GobConfig.get_bool "trans.goblint-check" + (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) - let ass = makeVarinfo true "__VERIFIER_assert" (TVoid []) + let ass = if goblintCheck then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) let atomicBegin = makeVarinfo true "__VERIFIER_atomic_begin" (TVoid []) let atomicEnd = makeVarinfo true "__VERIFIER_atomic_end" (TVoid []) @@ -60,7 +63,7 @@ module EvalAssert = struct | `Lifted e -> let es = WitnessUtil.InvariantExp.process_exp e in let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv ass); ("exp", Fe e)]) es in - if surroundByAtomic then + if surroundByAtomic && not goblintCheck then let abegin = (cInstr ("%v:__VERIFIER_atomic_begin();") loc [("__VERIFIER_atomic_begin", Fv atomicBegin)]) in let aend = (cInstr ("%v:__VERIFIER_atomic_end();") loc [("__VERIFIER_atomic_end", Fv atomicEnd)]) in abegin :: (asserts @ [aend]) From 8db9e1d320de69baf396bab7b56f55149f577a69 Mon Sep 17 00:00:00 2001 From: Jonas August Date: Wed, 10 May 2023 19:24:34 +0200 Subject: [PATCH 421/689] Adopt evalAssert.ml so the option is checked correctly at runtime --- src/transform/evalAssert.ml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index 82b92b9040..fb9cf84d86 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -26,11 +26,6 @@ module EvalAssert = struct (* should asserts be surrounded by __VERIFIER_atomic_{begin,end}? *) let surroundByAtomic = true - (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp)*) - let goblintCheck = GobConfig.get_bool "trans.goblint-check" - - (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) - let ass = if goblintCheck then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) let atomicBegin = makeVarinfo true "__VERIFIER_atomic_begin" (TVoid []) let atomicEnd = makeVarinfo true "__VERIFIER_atomic_end" (TVoid []) @@ -41,6 +36,8 @@ module EvalAssert = struct (* TODO: handle witness.invariant.loop-head *) val emit_after_lock = GobConfig.get_bool "witness.invariant.after-lock" val emit_other = GobConfig.get_bool "witness.invariant.other" + (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp) *) + val goblintCheck = GobConfig.get_bool "trans.goblint-check" method! vstmt s = let is_lock exp args = @@ -53,6 +50,10 @@ module EvalAssert = struct | _ -> false in + (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) + (* Moved in method because Options can not be checked in the module *) + let ass = if goblintCheck then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) in + let make_assert ~node loc lval = let lvals = match lval with | None -> Lval.Set.top () From 21d804a0a1ea9337075be413d30ec02cdfd5e274 Mon Sep 17 00:00:00 2001 From: Jonas August Date: Tue, 16 May 2023 18:00:31 +0200 Subject: [PATCH 422/689] Fix Goblint Option Retrieving by adding Unit to constant --- src/transform/evalAssert.ml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index fb9cf84d86..7fc70531db 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -26,6 +26,11 @@ module EvalAssert = struct (* should asserts be surrounded by __VERIFIER_atomic_{begin,end}? *) let surroundByAtomic = true + (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp) *) + let goblintCheck () = GobConfig.get_bool "trans.goblint-check" + + (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) + let ass () = if goblintCheck then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) in let atomicBegin = makeVarinfo true "__VERIFIER_atomic_begin" (TVoid []) let atomicEnd = makeVarinfo true "__VERIFIER_atomic_end" (TVoid []) @@ -36,8 +41,6 @@ module EvalAssert = struct (* TODO: handle witness.invariant.loop-head *) val emit_after_lock = GobConfig.get_bool "witness.invariant.after-lock" val emit_other = GobConfig.get_bool "witness.invariant.other" - (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp) *) - val goblintCheck = GobConfig.get_bool "trans.goblint-check" method! vstmt s = let is_lock exp args = @@ -50,10 +53,6 @@ module EvalAssert = struct | _ -> false in - (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) - (* Moved in method because Options can not be checked in the module *) - let ass = if goblintCheck then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) in - let make_assert ~node loc lval = let lvals = match lval with | None -> Lval.Set.top () From 69a33364e018a4aaea787b8aa4bda58441bd5b41 Mon Sep 17 00:00:00 2001 From: Jonas August Date: Tue, 23 May 2023 20:48:36 +0200 Subject: [PATCH 423/689] Bugfix --- src/transform/evalAssert.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index 7fc70531db..56f3d5eb5f 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -30,7 +30,7 @@ module EvalAssert = struct let goblintCheck () = GobConfig.get_bool "trans.goblint-check" (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) - let ass () = if goblintCheck then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) in + let ass () = if goblintCheck () then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) let atomicBegin = makeVarinfo true "__VERIFIER_atomic_begin" (TVoid []) let atomicEnd = makeVarinfo true "__VERIFIER_atomic_end" (TVoid []) @@ -62,8 +62,8 @@ module EvalAssert = struct match (ask ~node loc).f (Queries.Invariant context) with | `Lifted e -> let es = WitnessUtil.InvariantExp.process_exp e in - let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv ass); ("exp", Fe e)]) es in - if surroundByAtomic && not goblintCheck then + let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv (ass ())); ("exp", Fe e)]) es in + if surroundByAtomic && not (goblintCheck ()) then let abegin = (cInstr ("%v:__VERIFIER_atomic_begin();") loc [("__VERIFIER_atomic_begin", Fv atomicBegin)]) in let aend = (cInstr ("%v:__VERIFIER_atomic_end();") loc [("__VERIFIER_atomic_end", Fv atomicEnd)]) in abegin :: (asserts @ [aend]) From 3e3c1ebda3871a079fbbe65c4b84828fdbbfc914 Mon Sep 17 00:00:00 2001 From: stilscher <66023521+stilscher@users.noreply.github.com> Date: Fri, 8 Dec 2023 14:37:44 +0100 Subject: [PATCH 424/689] rename option --- src/config/options.schema.json | 18 +++++++++++++----- src/transform/evalAssert.ml | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 2e2a9212ef..d808f121c3 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1562,11 +1562,19 @@ "type":"string", "default": "transformed.c" }, - "goblint-check" : { - "title": "trans.goblint-check", - "description": "Write __Goblint_Check(exp) in the file instead of __VERIFIER_assert(exp).", - "type": "boolean", - "default": false + "assert" : { + "title": "trans.assert", + "type": "object", + "properties": { + "goblint-check": { + "title": "trans.assert.goblint-check", + "description": + "Write __goblint_check(exp) in the file instead of __VERIFIER_assert(exp).", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index 56f3d5eb5f..94fdfb8602 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -27,7 +27,7 @@ module EvalAssert = struct let surroundByAtomic = true (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp) *) - let goblintCheck () = GobConfig.get_bool "trans.goblint-check" + let goblintCheck () = GobConfig.get_bool "trans.assert.goblint-check" (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) let ass () = if goblintCheck () then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) From cae69f7006fa7c2f481e48d8613bc4f62a40b466 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 15:46:32 +0300 Subject: [PATCH 425/689] Refactor trans.assert options --- src/config/options.schema.json | 16 +++++++++++----- src/transform/evalAssert.ml | 20 +++++++++----------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index d808f121c3..0cb1b6ee67 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1566,12 +1566,18 @@ "title": "trans.assert", "type": "object", "properties": { - "goblint-check": { - "title": "trans.assert.goblint-check", - "description": - "Write __goblint_check(exp) in the file instead of __VERIFIER_assert(exp).", + "function": { + "title": "trans.assert.function", + "description": "Function to use for assertions in output.", + "type": "string", + "enum": ["assert", "__goblint_check", "__VERIFIER_assert"], + "default": "__VERIFIER_assert" + }, + "wrap-atomic": { + "title": "trans.assert.wrap-atomic", + "description": "Wrap assertions in __VERIFIER_atomic_begin and __VERIFIER_atomic_end.", "type": "boolean", - "default": false + "default": true } }, "additionalProperties": false diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index 94fdfb8602..0fee26355b 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -22,15 +22,8 @@ open Formatcil will be removed and they will fail on the next iteration *) -module EvalAssert = struct - (* should asserts be surrounded by __VERIFIER_atomic_{begin,end}? *) - let surroundByAtomic = true - - (* variable for generating __goblint_check(exp) instead of __VERIFIER_assert(exp) *) - let goblintCheck () = GobConfig.get_bool "trans.assert.goblint-check" - - (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) - let ass () = if goblintCheck () then makeVarinfo true "__goblint_check" (TVoid []) else makeVarinfo true "__VERIFIER_assert" (TVoid []) +module EvalAssert = +struct let atomicBegin = makeVarinfo true "__VERIFIER_atomic_begin" (TVoid []) let atomicEnd = makeVarinfo true "__VERIFIER_atomic_end" (TVoid []) @@ -42,6 +35,11 @@ module EvalAssert = struct val emit_after_lock = GobConfig.get_bool "witness.invariant.after-lock" val emit_other = GobConfig.get_bool "witness.invariant.other" + (* Cannot use Cilfacade.name_fundecs as assert() is external and has no fundec *) + val assert_function = makeVarinfo true (GobConfig.get_string "trans.assert.function") (TVoid []) + (* should asserts be surrounded by __VERIFIER_atomic_{begin,end}? *) + val surroundByAtomic = GobConfig.get_bool "trans.assert.wrap-atomic" + method! vstmt s = let is_lock exp args = match exp with @@ -62,8 +60,8 @@ module EvalAssert = struct match (ask ~node loc).f (Queries.Invariant context) with | `Lifted e -> let es = WitnessUtil.InvariantExp.process_exp e in - let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv (ass ())); ("exp", Fe e)]) es in - if surroundByAtomic && not (goblintCheck ()) then + let asserts = List.map (fun e -> cInstr ("%v:assert (%e:exp);") loc [("assert", Fv assert_function); ("exp", Fe e)]) es in + if surroundByAtomic then let abegin = (cInstr ("%v:__VERIFIER_atomic_begin();") loc [("__VERIFIER_atomic_begin", Fv atomicBegin)]) in let aend = (cInstr ("%v:__VERIFIER_atomic_end();") loc [("__VERIFIER_atomic_end", Fv atomicEnd)]) in abegin :: (asserts @ [aend]) From 8971af4da76b730fb3fe0eea624cd2a551561d44 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 17:59:53 +0300 Subject: [PATCH 426/689] Add NOCHECK annotation to suppress missing automatic check warning --- scripts/update_suite.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index ab68cd0f0d..0e90bbf828 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -246,7 +246,7 @@ def compare_warnings check.call warnings[idx] != "race" when "nodeadlock" check.call warnings[idx] != "deadlock" - when "nocrash", "fixpoint", "notimeout", "cram" + when "nocrash", "fixpoint", "notimeout", "cram", "nocheck" check.call true end end @@ -334,6 +334,8 @@ def parse_tests (lines) tests[-42] = "notimeout" elsif obj =~ /CRAM/ then tests[-42] = "cram" + elsif obj =~ /NOCHECK/ then + tests[-42] = "nocheck" end next if obj =~ /^\s*\/\// || obj =~ /^\s*\/\*([^*]|\*+[^*\/])*\*\/$/ todo << i if obj =~ /TODO|SKIP/ From 5946abce0cb80d1d8f245da34c471f3f38d87b23 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 18:40:00 +0300 Subject: [PATCH 427/689] Add NOCHECK and another annotations --- tests/regression/00-sanity/37-long-double.c | 1 + .../52-thread-unsafe-libfuns-single-thread.c | 1 + tests/regression/01-cpa/51-marshal.c | 1 + tests/regression/02-base/57-meet-def-exc.c | 1 + .../regression/03-practical/03-pthread_ptrs.c | 16 +- .../03-practical/22-nested-infinite-loops.c | 1 + .../03-practical/35-base-mutex-macos.c | 2 +- .../10-synch/07-thread_self_create.c | 2 +- .../10-synch/27-tid-array-malloc-2.c | 5 +- .../13-privatized/62-global-threadid.c | 2 +- .../65-threadreturn-cpa-remove.c | 2 +- .../20-slr_term/01-no-int-context.c | 2 +- tests/regression/20-slr_term/02-global-inc.c | 2 +- tests/regression/20-slr_term/03-3ctxs.c | 2 +- tests/regression/20-slr_term/05-selfloop.c | 1 + .../22-partitioned_arrays/08-unsupported.c | 1 + .../12-was_problematic_2.c | 1 + .../13-was_problematic_3.c | 1 + .../22-partitioned_arrays/16-refine-meet.c | 1 + .../22-partitioned_arrays/19-fixpoint.c | 1 + .../22-partitioned_arrays/20-more-fixpoint.c | 1 + .../08-unsupported.c | 1 + .../12-was_problematic_2.c | 1 + .../24-octagon/03-previously_problematic_a.c | 2 +- .../24-octagon/04-previously_problematic_b.c | 2 +- .../24-octagon/05-previously_problematic_c.c | 2 +- .../24-octagon/06-previously_problematic_d.c | 2 +- .../24-octagon/07-previously_problematic_e.c | 2 +- .../24-octagon/08-previously_problematic_f.c | 2 +- .../24-octagon/09-previously_problematic_g.c | 2 +- .../24-octagon/10-previously_problematic_h.c | 2 +- .../24-octagon/11-previously_problematic_i.c | 2 +- .../24-octagon/12-previously_problematic_j.c | 1 + tests/regression/25-vla/03-calls.c | 1 + .../02-bot-during-condition.c | 1 + .../27-inv_invariants/07-more-bot.c | 1 + tests/regression/28-race_reach/95-deref-fun.c | 2 +- .../regression/28-race_reach/96-deref-fun2.c | 2 +- .../29-svcomp/25-writing-into-char-array.c | 1 + tests/regression/29-svcomp/26-ikinds_if.c | 1 + tests/regression/29-svcomp/29-witness.c | 1 + tests/regression/29-svcomp/32-no-ov.c | 2 +- tests/regression/33-constants/01-const.c | 1 + tests/regression/33-constants/02-simple.c | 2 +- .../33-constants/03-empty-not-dead-branch.c | 2 +- .../33-constants/04-empty-not-dead.c | 2 +- .../regression/33-constants/05-fun_ptranal.c | 1 + .../34-localwn_restart/05-nested.w.counter.c | 1 + .../65-multi-lock-producer-consumer.c | 1 + .../38-int-refinements/05-invalid-widen.c | 1 + tests/regression/41-stdlib/03-noqsort.c | 1 + tests/regression/41-stdlib/03-noqsort.t | 2 +- tests/regression/43-struct-domain/12-aget.c | 2 +- .../43-struct-domain/25-aget-keyed.c | 2 +- tests/regression/44-trier_analyzer/00-A0.c | 1 + tests/regression/44-trier_analyzer/01-A1.c | 1 + tests/regression/44-trier_analyzer/02-abc.c | 1 + tests/regression/44-trier_analyzer/03-break.c | 1 + tests/regression/44-trier_analyzer/13-ifif.c | 1 + tests/regression/44-trier_analyzer/15-P1.c | 1 + tests/regression/44-trier_analyzer/16-P2.c | 1 + tests/regression/44-trier_analyzer/17-P3.c | 1 + tests/regression/44-trier_analyzer/23-rec0.c | 1 + tests/regression/44-trier_analyzer/33-recA.c | 1 + .../46-apron2/28-sv-comp-unroll-term.c | 2 +- .../34-iset_previously_problematic_c.c | 1 + .../36-iset_previosuly_problematic_g.c | 1 + .../37-iset_previosuly_problematic_f.c | 1 + .../39-iset_previosuly_problematic_d.c | 1 + .../45-iset_previosuly_problematic_i.c | 1 + .../47-iset_previously_problematic_a.c | 1 + .../49-iset_previously_problematic_b.c | 1 + .../51-iset_previosuly_problematic_e.c | 1 + .../53-iset_previously_problematic_h.c | 1 + tests/regression/46-apron2/58-issue-1249.c | 2 +- tests/regression/46-apron2/59-issue-1319.c | 4 +- tests/regression/46-apron2/60-issue-1338.c | 1 + .../46-apron2/82-fixpoint-not-reached.c | 2 +- .../19-mukherjee_fig_3_11.c | 2 +- tests/regression/55-loop-unrolling/08-bad.c | 1 + tests/regression/55-loop-unrolling/08-bad.t | 4 +- .../11-unrolled-loop-invariant.c | 1 + .../11-unrolled-loop-invariant.t | 206 +++++++++--------- .../56-witness/46-top-bool-invariant.c | 2 +- .../56-witness/47-top-int-invariant.c | 2 +- .../56-witness/52-witness-lifter-ps2.c | 1 + .../56-witness/53-witness-lifter-ps3.c | 1 + .../61-evalAssert/01-union_evalAssert.c | 2 +- tests/regression/63-affeq/14-norm_inv.c | 1 + tests/regression/63-affeq/17-verify.c | 2 +- .../00-was_problematic_2.c | 1 + .../03-was_problematic_3.c | 1 + .../66-interval-set-one/14-no-int-context.c | 2 +- .../regression/66-interval-set-one/39-calls.c | 1 + .../regression/66-interval-set-one/93-enum.c | 1 + .../03-def_exc-interval-inconsistent.c | 1 + .../67-interval-sets-two/04-unsupported.c | 1 + .../67-interval-sets-two/14-trylock_rc_slr.c | 1 + .../67-interval-sets-two/15-interval-bot.c | 2 +- .../67-interval-sets-two/24-arithmetic-bot.c | 1 + .../67-interval-sets-two/31-ptrdiff.c | 1 + .../67-interval-sets-two/44-comparision-bot.c | 1 + .../56-interval-set-dead-code.c | 1 + .../58-interval-set-dead-code-with-fun-call.c | 1 + .../71-doublelocking/15-rec-dyn-nested.c | 2 +- .../15-juliet-uaf-global-var.c | 1 + 106 files changed, 219 insertions(+), 153 deletions(-) diff --git a/tests/regression/00-sanity/37-long-double.c b/tests/regression/00-sanity/37-long-double.c index 01c9b8bb9b..b4eb5e29c8 100644 --- a/tests/regression/00-sanity/37-long-double.c +++ b/tests/regression/00-sanity/37-long-double.c @@ -1,3 +1,4 @@ +// CRAM int main() { long double l = 0.0L; return (int)l; diff --git a/tests/regression/00-sanity/52-thread-unsafe-libfuns-single-thread.c b/tests/regression/00-sanity/52-thread-unsafe-libfuns-single-thread.c index 94c0f3efeb..aa1bc24aa4 100644 --- a/tests/regression/00-sanity/52-thread-unsafe-libfuns-single-thread.c +++ b/tests/regression/00-sanity/52-thread-unsafe-libfuns-single-thread.c @@ -1,4 +1,5 @@ // PARAM: --enable allglobs --set ana.activated[+] threadJoins +// CRAM #include #include diff --git a/tests/regression/01-cpa/51-marshal.c b/tests/regression/01-cpa/51-marshal.c index bf4e8faebf..c718159e33 100644 --- a/tests/regression/01-cpa/51-marshal.c +++ b/tests/regression/01-cpa/51-marshal.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval +// NOCHECK void callee(int j) { j++; } diff --git a/tests/regression/02-base/57-meet-def-exc.c b/tests/regression/02-base/57-meet-def-exc.c index d66b1120d6..cf24431f8c 100644 --- a/tests/regression/02-base/57-meet-def-exc.c +++ b/tests/regression/02-base/57-meet-def-exc.c @@ -1,3 +1,4 @@ +// NOCHECK void main(void) { int x; int i = 41; diff --git a/tests/regression/03-practical/03-pthread_ptrs.c b/tests/regression/03-practical/03-pthread_ptrs.c index c619c994b2..0694698af8 100644 --- a/tests/regression/03-practical/03-pthread_ptrs.c +++ b/tests/regression/03-practical/03-pthread_ptrs.c @@ -1,5 +1,5 @@ #include - +// NOCHECK static pthread_t sid1 ; static pthread_t sid2 ; static pthread_t sid3 ; @@ -15,22 +15,22 @@ void *fn2(void) { extern void *fn3(void * a); -int main() { +int main() { /* normal call to fn1 */ pthread_create(&sid1, NULL, fn1, NULL); - - /* ignore parameter (cast parameter to void) call */ + + /* ignore parameter (cast parameter to void) call */ pthread_create(&sid2, NULL, (void *(*)(void * )) (& fn2), NULL); - + /* we create a unknown thread -- that can't be good */ pthread_create(&sid3, NULL, &fn3, NULL); pthread_join(sid3, NULL); - + pthread_join(sid2, NULL); - + pthread_join(sid1, NULL); - + return 0; } diff --git a/tests/regression/03-practical/22-nested-infinite-loops.c b/tests/regression/03-practical/22-nested-infinite-loops.c index f3e1fed23b..658bcbacb0 100644 --- a/tests/regression/03-practical/22-nested-infinite-loops.c +++ b/tests/regression/03-practical/22-nested-infinite-loops.c @@ -1,4 +1,5 @@ // https://github.com/goblint/analyzer/issues/231#issuecomment-868369123 +// NOCHECK: should check CFG? int main(void) { int x = 0; while(1) { diff --git a/tests/regression/03-practical/35-base-mutex-macos.c b/tests/regression/03-practical/35-base-mutex-macos.c index 4f4dc417fc..a83022e91b 100644 --- a/tests/regression/03-practical/35-base-mutex-macos.c +++ b/tests/regression/03-practical/35-base-mutex-macos.c @@ -1,5 +1,5 @@ // Intentionally no #include , because we want to imitate/debug MacOS construction on anything. - +// CRAM #define __PTHREAD_MUTEX_SIZE__ 56 struct _opaque_pthread_mutex_t { diff --git a/tests/regression/10-synch/07-thread_self_create.c b/tests/regression/10-synch/07-thread_self_create.c index 473a26a25b..18c5f3ee83 100644 --- a/tests/regression/10-synch/07-thread_self_create.c +++ b/tests/regression/10-synch/07-thread_self_create.c @@ -1,5 +1,5 @@ // PARAM: --set ana.activated[+] thread -// Checks termination of thread analysis with a thread who is its own single parent. +// NOTIMEOUT: Checks termination of thread analysis with a thread who is its own single parent. #include void *t_fun(void *arg) { diff --git a/tests/regression/10-synch/27-tid-array-malloc-2.c b/tests/regression/10-synch/27-tid-array-malloc-2.c index 462901459a..d1b41843a7 100644 --- a/tests/regression/10-synch/27-tid-array-malloc-2.c +++ b/tests/regression/10-synch/27-tid-array-malloc-2.c @@ -1,4 +1,5 @@ -// PARAM: --set ana.activated[+] thread +// PARAM: --set ana.activated[+] thread +// NOCRASH #include #include @@ -19,7 +20,7 @@ int main() pthread_create(&t[tid], 0, thread, 0); tid++; pthread_create(&t[tid], 0, thread, 0); - + tid=0; pthread_join(t[tid], 0); tid++; diff --git a/tests/regression/13-privatized/62-global-threadid.c b/tests/regression/13-privatized/62-global-threadid.c index 38d21700ea..b5f3c831bb 100644 --- a/tests/regression/13-privatized/62-global-threadid.c +++ b/tests/regression/13-privatized/62-global-threadid.c @@ -1,5 +1,5 @@ #include - +// NOCHECK pthread_t id; extern void magic(); diff --git a/tests/regression/13-privatized/65-threadreturn-cpa-remove.c b/tests/regression/13-privatized/65-threadreturn-cpa-remove.c index 3bbe85b3ea..58d8c9ea2f 100644 --- a/tests/regression/13-privatized/65-threadreturn-cpa-remove.c +++ b/tests/regression/13-privatized/65-threadreturn-cpa-remove.c @@ -1,5 +1,5 @@ #include - +// NOCHECK int d; pthread_t g; enum { b } c() {} diff --git a/tests/regression/20-slr_term/01-no-int-context.c b/tests/regression/20-slr_term/01-no-int-context.c index d057098559..ce8d3cb833 100644 --- a/tests/regression/20-slr_term/01-no-int-context.c +++ b/tests/regression/20-slr_term/01-no-int-context.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.int.interval --set solver slr3t --disable ana.base.context.int - +// NOCHECK int f (int i) { // -2 return i+1; } // -3 void g(int j) { // -4 diff --git a/tests/regression/20-slr_term/02-global-inc.c b/tests/regression/20-slr_term/02-global-inc.c index cfb2432999..fc2f9100df 100644 --- a/tests/regression/20-slr_term/02-global-inc.c +++ b/tests/regression/20-slr_term/02-global-inc.c @@ -1,4 +1,4 @@ - +// NOCHECK int g = 0; int f = 0; diff --git a/tests/regression/20-slr_term/03-3ctxs.c b/tests/regression/20-slr_term/03-3ctxs.c index d0236960ea..b622549419 100644 --- a/tests/regression/20-slr_term/03-3ctxs.c +++ b/tests/regression/20-slr_term/03-3ctxs.c @@ -1,4 +1,4 @@ - +// NOCHECK int f(int j){ return j+1; } diff --git a/tests/regression/20-slr_term/05-selfloop.c b/tests/regression/20-slr_term/05-selfloop.c index 94286393a6..638d11cb1b 100644 --- a/tests/regression/20-slr_term/05-selfloop.c +++ b/tests/regression/20-slr_term/05-selfloop.c @@ -1,3 +1,4 @@ +// NOCHECK void f() { } void g() { } void h() { } diff --git a/tests/regression/22-partitioned_arrays/08-unsupported.c b/tests/regression/22-partitioned_arrays/08-unsupported.c index 51e897d840..73f5871d9c 100644 --- a/tests/regression/22-partitioned_arrays/08-unsupported.c +++ b/tests/regression/22-partitioned_arrays/08-unsupported.c @@ -1,6 +1,7 @@ // PARAM: --enable ana.int.interval --disable exp.fast_global_inits --set ana.base.arrays.domain partitioned // This is just to test that the analysis does not cause problems for features that are not explicitly dealt with +// NOCHECK: what problems? int main(void) { callok(); } diff --git a/tests/regression/22-partitioned_arrays/12-was_problematic_2.c b/tests/regression/22-partitioned_arrays/12-was_problematic_2.c index fd57549008..2ff396feb4 100644 --- a/tests/regression/22-partitioned_arrays/12-was_problematic_2.c +++ b/tests/regression/22-partitioned_arrays/12-was_problematic_2.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned +// NOCHECK int main(void) { int arr[260]; diff --git a/tests/regression/22-partitioned_arrays/13-was_problematic_3.c b/tests/regression/22-partitioned_arrays/13-was_problematic_3.c index ff7e839753..1822af4f0a 100644 --- a/tests/regression/22-partitioned_arrays/13-was_problematic_3.c +++ b/tests/regression/22-partitioned_arrays/13-was_problematic_3.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned +// NOCHECK struct some_struct { int dir[7]; diff --git a/tests/regression/22-partitioned_arrays/16-refine-meet.c b/tests/regression/22-partitioned_arrays/16-refine-meet.c index 05a73a70ba..7f238ab858 100644 --- a/tests/regression/22-partitioned_arrays/16-refine-meet.c +++ b/tests/regression/22-partitioned_arrays/16-refine-meet.c @@ -1,4 +1,5 @@ // PARAM: --set ana.base.arrays.domain partitioned +// NOCHECK int garr[7]; int main(int argc, char **argv) diff --git a/tests/regression/22-partitioned_arrays/19-fixpoint.c b/tests/regression/22-partitioned_arrays/19-fixpoint.c index 1ac55216dd..30d7821db5 100644 --- a/tests/regression/22-partitioned_arrays/19-fixpoint.c +++ b/tests/regression/22-partitioned_arrays/19-fixpoint.c @@ -1,4 +1,5 @@ // PARAM: --set ana.base.arrays.domain partitioned +// FIXPOINT #include int stored_elements[20]; diff --git a/tests/regression/22-partitioned_arrays/20-more-fixpoint.c b/tests/regression/22-partitioned_arrays/20-more-fixpoint.c index 8181cf85dd..ab87e1944a 100644 --- a/tests/regression/22-partitioned_arrays/20-more-fixpoint.c +++ b/tests/regression/22-partitioned_arrays/20-more-fixpoint.c @@ -1,4 +1,5 @@ // PARAM: --set ana.base.arrays.domain partitioned +// FIXPOINT #include #include #include diff --git a/tests/regression/23-partitioned_arrays_last/08-unsupported.c b/tests/regression/23-partitioned_arrays_last/08-unsupported.c index 0b0a1baca9..cff075d786 100644 --- a/tests/regression/23-partitioned_arrays_last/08-unsupported.c +++ b/tests/regression/23-partitioned_arrays_last/08-unsupported.c @@ -1,6 +1,7 @@ // PARAM: --enable ana.int.interval --disable exp.fast_global_inits --set ana.base.arrays.domain partitioned --set ana.base.partition-arrays.keep-expr "last" // This is just to test that the analysis does not cause problems for features that are not explicitly dealt with +// NOCHECK: what problems? int main(void) { vla(); callok(); diff --git a/tests/regression/23-partitioned_arrays_last/12-was_problematic_2.c b/tests/regression/23-partitioned_arrays_last/12-was_problematic_2.c index 9523510472..d5593ffe8b 100644 --- a/tests/regression/23-partitioned_arrays_last/12-was_problematic_2.c +++ b/tests/regression/23-partitioned_arrays_last/12-was_problematic_2.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.base.partition-arrays.keep-expr "last" +// NOCHECK int main(void) { int arr[260]; diff --git a/tests/regression/24-octagon/03-previously_problematic_a.c b/tests/regression/24-octagon/03-previously_problematic_a.c index 986e2821fd..a266358408 100644 --- a/tests/regression/24-octagon/03-previously_problematic_a.c +++ b/tests/regression/24-octagon/03-previously_problematic_a.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/04-previously_problematic_b.c b/tests/regression/24-octagon/04-previously_problematic_b.c index 62649e925d..e9a239f66b 100644 --- a/tests/regression/24-octagon/04-previously_problematic_b.c +++ b/tests/regression/24-octagon/04-previously_problematic_b.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included typedef int wchar_t; typedef unsigned long size_t; diff --git a/tests/regression/24-octagon/05-previously_problematic_c.c b/tests/regression/24-octagon/05-previously_problematic_c.c index c260646c23..8d08c343ad 100644 --- a/tests/regression/24-octagon/05-previously_problematic_c.c +++ b/tests/regression/24-octagon/05-previously_problematic_c.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/06-previously_problematic_d.c b/tests/regression/24-octagon/06-previously_problematic_d.c index 733b07d015..cca02f523b 100644 --- a/tests/regression/24-octagon/06-previously_problematic_d.c +++ b/tests/regression/24-octagon/06-previously_problematic_d.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/07-previously_problematic_e.c b/tests/regression/24-octagon/07-previously_problematic_e.c index cb9b12cafe..0dee19eb94 100644 --- a/tests/regression/24-octagon/07-previously_problematic_e.c +++ b/tests/regression/24-octagon/07-previously_problematic_e.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/08-previously_problematic_f.c b/tests/regression/24-octagon/08-previously_problematic_f.c index 431b8a6c57..93c4d3195f 100644 --- a/tests/regression/24-octagon/08-previously_problematic_f.c +++ b/tests/regression/24-octagon/08-previously_problematic_f.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/09-previously_problematic_g.c b/tests/regression/24-octagon/09-previously_problematic_g.c index c48184d4dd..910a28703d 100644 --- a/tests/regression/24-octagon/09-previously_problematic_g.c +++ b/tests/regression/24-octagon/09-previously_problematic_g.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/10-previously_problematic_h.c b/tests/regression/24-octagon/10-previously_problematic_h.c index 969ae965df..ff29145789 100644 --- a/tests/regression/24-octagon/10-previously_problematic_h.c +++ b/tests/regression/24-octagon/10-previously_problematic_h.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included int main(int argc, char const *argv[]) { diff --git a/tests/regression/24-octagon/11-previously_problematic_i.c b/tests/regression/24-octagon/11-previously_problematic_i.c index f1956919d8..517b8e58d2 100644 --- a/tests/regression/24-octagon/11-previously_problematic_i.c +++ b/tests/regression/24-octagon/11-previously_problematic_i.c @@ -1,5 +1,5 @@ // SKIP PARAM: --enable ana.int.interval --set ana.base.arrays.domain partitioned --set ana.activated[+] apron -// These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might +// FIXPOINT: These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included char buf2[67]; diff --git a/tests/regression/24-octagon/12-previously_problematic_j.c b/tests/regression/24-octagon/12-previously_problematic_j.c index 208a89d50f..a289e70de3 100644 --- a/tests/regression/24-octagon/12-previously_problematic_j.c +++ b/tests/regression/24-octagon/12-previously_problematic_j.c @@ -1,4 +1,5 @@ // SKIP PARAM: --set ana.activated[+] apron +// NOCHECK void main(void) { int i = 0; int j = i; diff --git a/tests/regression/25-vla/03-calls.c b/tests/regression/25-vla/03-calls.c index 133e89f704..fbe38af248 100644 --- a/tests/regression/25-vla/03-calls.c +++ b/tests/regression/25-vla/03-calls.c @@ -1,5 +1,6 @@ // PARAM: --enable ana.int.interval --disable ana.int.def_exc --set ana.base.arrays.domain partitioned // Variable-sized arrays +// NOCHECK void foo(int n, int a[n]); void foo2(int n, int a[30][n]); void foo3(int n, int a[n][30]); diff --git a/tests/regression/27-inv_invariants/02-bot-during-condition.c b/tests/regression/27-inv_invariants/02-bot-during-condition.c index a94c65bb81..88c5ff2ada 100644 --- a/tests/regression/27-inv_invariants/02-bot-during-condition.c +++ b/tests/regression/27-inv_invariants/02-bot-during-condition.c @@ -1,3 +1,4 @@ +// NOCHECK int main () { int tmp; diff --git a/tests/regression/27-inv_invariants/07-more-bot.c b/tests/regression/27-inv_invariants/07-more-bot.c index e4b677b599..8e5819158e 100644 --- a/tests/regression/27-inv_invariants/07-more-bot.c +++ b/tests/regression/27-inv_invariants/07-more-bot.c @@ -1,5 +1,6 @@ // PARAM: --enable ana.int.interval // Adapted from sv-comp array-programs/partial_mod_count_1.c +// NOCHECK int N = 1000; int main(){ int i; diff --git a/tests/regression/28-race_reach/95-deref-fun.c b/tests/regression/28-race_reach/95-deref-fun.c index 04cf1a8723..f1431d9221 100644 --- a/tests/regression/28-race_reach/95-deref-fun.c +++ b/tests/regression/28-race_reach/95-deref-fun.c @@ -1,6 +1,6 @@ // PARAM: --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" #include - +// NOCRASH void foo(int (*callback)()) { } diff --git a/tests/regression/28-race_reach/96-deref-fun2.c b/tests/regression/28-race_reach/96-deref-fun2.c index 9e76c8604d..cb3aee7535 100644 --- a/tests/regression/28-race_reach/96-deref-fun2.c +++ b/tests/regression/28-race_reach/96-deref-fun2.c @@ -1,6 +1,6 @@ // PARAM: --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" #include - +// NOCRASH #define SVCOMP 1 #include diff --git a/tests/regression/29-svcomp/25-writing-into-char-array.c b/tests/regression/29-svcomp/25-writing-into-char-array.c index 8894007d23..ce8fea40f4 100644 --- a/tests/regression/29-svcomp/25-writing-into-char-array.c +++ b/tests/regression/29-svcomp/25-writing-into-char-array.c @@ -1,3 +1,4 @@ +// NOCHECK #include struct __anonstruct_mbox_t_232 { int one; diff --git a/tests/regression/29-svcomp/26-ikinds_if.c b/tests/regression/29-svcomp/26-ikinds_if.c index b902659f47..a8f726353f 100644 --- a/tests/regression/29-svcomp/26-ikinds_if.c +++ b/tests/regression/29-svcomp/26-ikinds_if.c @@ -1,4 +1,5 @@ //PARAM: --enable ana.int.interval +// NOCHECK #include static long sound_ioctl(unsigned int cmd , unsigned long arg ) diff --git a/tests/regression/29-svcomp/29-witness.c b/tests/regression/29-svcomp/29-witness.c index 72d1c4435a..b56b47a74c 100644 --- a/tests/regression/29-svcomp/29-witness.c +++ b/tests/regression/29-svcomp/29-witness.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! call(reach_error())) )" +// NOCRASH #include #include diff --git a/tests/regression/29-svcomp/32-no-ov.c b/tests/regression/29-svcomp/32-no-ov.c index 0167098c29..3612b34459 100644 --- a/tests/regression/29-svcomp/32-no-ov.c +++ b/tests/regression/29-svcomp/32-no-ov.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.int.interval --enable ana.sv-comp.enabled --enable ana.sv-comp.functions --set ana.specification "CHECK( init(main()), LTL(G ! overflow) )" - +// CRAM int main(){ // This is not an overflow, just implementation defined behavior on a cast int data = ((int)(rand() & 1 ? (((unsigned)rand()<<30) ^ ((unsigned)rand()<<15) ^ rand()) : -(((unsigned)rand()<<30) ^ ((unsigned)rand()<<15) ^ rand()) - 1)); diff --git a/tests/regression/33-constants/01-const.c b/tests/regression/33-constants/01-const.c index 8db984a4b3..436a389545 100644 --- a/tests/regression/33-constants/01-const.c +++ b/tests/regression/33-constants/01-const.c @@ -1,5 +1,6 @@ //PARAM: --set ana.activated '["constants"]' // intentional explicit ana.activated to do tutorial in isolation +// NOCHECK int f(int a, int b){ int d = 3; int z = a + d; diff --git a/tests/regression/33-constants/02-simple.c b/tests/regression/33-constants/02-simple.c index aa370aa4da..75cd33ee8a 100644 --- a/tests/regression/33-constants/02-simple.c +++ b/tests/regression/33-constants/02-simple.c @@ -1,6 +1,6 @@ //PARAM: --set ana.activated '["constants"]' // intentional explicit ana.activated to do tutorial in isolation - +// NOCHECK int main(){ int x = 3; int y = 4; diff --git a/tests/regression/33-constants/03-empty-not-dead-branch.c b/tests/regression/33-constants/03-empty-not-dead-branch.c index 2b6d662589..2bd6a10190 100644 --- a/tests/regression/33-constants/03-empty-not-dead-branch.c +++ b/tests/regression/33-constants/03-empty-not-dead-branch.c @@ -1,6 +1,6 @@ //PARAM: --set ana.activated '["constants"]' // intentional explicit ana.activated to do tutorial in isolation - +// NOCHECK int g; int main() { diff --git a/tests/regression/33-constants/04-empty-not-dead.c b/tests/regression/33-constants/04-empty-not-dead.c index 8ad4199aa8..377a066370 100644 --- a/tests/regression/33-constants/04-empty-not-dead.c +++ b/tests/regression/33-constants/04-empty-not-dead.c @@ -1,6 +1,6 @@ //PARAM: --set ana.activated '["constants"]' // intentional explicit ana.activated to do tutorial in isolation - +// NOCHECK int g; int main() { diff --git a/tests/regression/33-constants/05-fun_ptranal.c b/tests/regression/33-constants/05-fun_ptranal.c index 5ebaf24e22..bb8f2146e5 100644 --- a/tests/regression/33-constants/05-fun_ptranal.c +++ b/tests/regression/33-constants/05-fun_ptranal.c @@ -1,5 +1,6 @@ //PARAM: --set ana.activated '["constants", "ptranal"]' // intentional explicit ana.activated to do tutorial in isolation +// NOCHECK int f(int a, int b){ int d = 3; int z = a + d; diff --git a/tests/regression/34-localwn_restart/05-nested.w.counter.c b/tests/regression/34-localwn_restart/05-nested.w.counter.c index 2d0cca1853..7cc7c6ce59 100644 --- a/tests/regression/34-localwn_restart/05-nested.w.counter.c +++ b/tests/regression/34-localwn_restart/05-nested.w.counter.c @@ -1,4 +1,5 @@ // Variant of nested.c with a counter. +// NOCHECK void main() { int z = 0; diff --git a/tests/regression/36-apron/65-multi-lock-producer-consumer.c b/tests/regression/36-apron/65-multi-lock-producer-consumer.c index ae71c36dcf..e7041a09d3 100644 --- a/tests/regression/36-apron/65-multi-lock-producer-consumer.c +++ b/tests/regression/36-apron/65-multi-lock-producer-consumer.c @@ -1,5 +1,6 @@ // SKIP PARAM: --set ana.activated[+] apron --enable ana.sv-comp.functions --set ana.relation.privatization mutex-meet --set ana.apron.domain polyhedra // TODO: why doesn't mutex-meet-tid succeed? a widening loses some upper bound and we forget a possible overflow, succeeds with assume_none +// NOCHECK #include #include diff --git a/tests/regression/38-int-refinements/05-invalid-widen.c b/tests/regression/38-int-refinements/05-invalid-widen.c index 59d76019a8..ad39ff761c 100644 --- a/tests/regression/38-int-refinements/05-invalid-widen.c +++ b/tests/regression/38-int-refinements/05-invalid-widen.c @@ -1,4 +1,5 @@ //PARAM: --set ana.int.refinement once --enable ana.int.enums +// NOCRASH #include int main() { diff --git a/tests/regression/41-stdlib/03-noqsort.c b/tests/regression/41-stdlib/03-noqsort.c index e7a1de89a3..22672083d7 100644 --- a/tests/regression/41-stdlib/03-noqsort.c +++ b/tests/regression/41-stdlib/03-noqsort.c @@ -1,4 +1,5 @@ // PARAM: --set pre.cppflags[+] -DGOBLINT_NO_QSORT +// CRAM #include // There should be no CIL warning about multiple definitions here diff --git a/tests/regression/41-stdlib/03-noqsort.t b/tests/regression/41-stdlib/03-noqsort.t index f8082a768c..cd56e0047d 100644 --- a/tests/regression/41-stdlib/03-noqsort.t +++ b/tests/regression/41-stdlib/03-noqsort.t @@ -1,7 +1,7 @@ There should be no CIL warning about multiple definitions: $ goblint --set pre.cppflags[+] -DGOBLINT_NO_QSORT 03-noqsort.c - [Warning][Deadcode] Function 'qsort' is uncalled: 1 LLoC (03-noqsort.c:5:1-6:1) + [Warning][Deadcode] Function 'qsort' is uncalled: 1 LLoC (03-noqsort.c:6:1-7:1) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 2 dead: 1 (1 in uncalled functions) diff --git a/tests/regression/43-struct-domain/12-aget.c b/tests/regression/43-struct-domain/12-aget.c index 193e463418..6e67cefe75 100644 --- a/tests/regression/43-struct-domain/12-aget.c +++ b/tests/regression/43-struct-domain/12-aget.c @@ -1,5 +1,5 @@ // PARAM: --set ana.base.structs.domain "sets" - +// NOCHECK // This is shortened from aget.c in the bench repository // There was an issue when testing arrays, as they init to bottom and this code triggers narrowing. /* Generated by CIL v. 1.3.6 */ diff --git a/tests/regression/43-struct-domain/25-aget-keyed.c b/tests/regression/43-struct-domain/25-aget-keyed.c index 94d5495ae1..09c80c44cc 100644 --- a/tests/regression/43-struct-domain/25-aget-keyed.c +++ b/tests/regression/43-struct-domain/25-aget-keyed.c @@ -1,5 +1,5 @@ // PARAM: --set ana.base.structs.domain "keyed" - +// NOCHECK // This is shortened from aget.c in the bench repository // There was an issue when testing arrays, as they init to bottom and this code triggers narrowing. /* Generated by CIL v. 1.3.6 */ diff --git a/tests/regression/44-trier_analyzer/00-A0.c b/tests/regression/44-trier_analyzer/00-A0.c index defd7022f0..bfeb7c5509 100644 --- a/tests/regression/44-trier_analyzer/00-A0.c +++ b/tests/regression/44-trier_analyzer/00-A0.c @@ -1,3 +1,4 @@ +// NOCHECK extern int printf(char *, ...); main () { diff --git a/tests/regression/44-trier_analyzer/01-A1.c b/tests/regression/44-trier_analyzer/01-A1.c index a04fafc238..967b8d79d0 100644 --- a/tests/regression/44-trier_analyzer/01-A1.c +++ b/tests/regression/44-trier_analyzer/01-A1.c @@ -1,3 +1,4 @@ +// NOCHECK extern int printf (char *, ...); extern int scanf (char *, ...); diff --git a/tests/regression/44-trier_analyzer/02-abc.c b/tests/regression/44-trier_analyzer/02-abc.c index 6a23697a7b..f29d3787e7 100644 --- a/tests/regression/44-trier_analyzer/02-abc.c +++ b/tests/regression/44-trier_analyzer/02-abc.c @@ -1,3 +1,4 @@ +// NOCHECK #include #include diff --git a/tests/regression/44-trier_analyzer/03-break.c b/tests/regression/44-trier_analyzer/03-break.c index 4c87a8277f..78a8cf26d6 100644 --- a/tests/regression/44-trier_analyzer/03-break.c +++ b/tests/regression/44-trier_analyzer/03-break.c @@ -1,3 +1,4 @@ +// NOCHECK extern int printf(); main () { diff --git a/tests/regression/44-trier_analyzer/13-ifif.c b/tests/regression/44-trier_analyzer/13-ifif.c index 3e456a9576..e9025f1fa8 100644 --- a/tests/regression/44-trier_analyzer/13-ifif.c +++ b/tests/regression/44-trier_analyzer/13-ifif.c @@ -1,3 +1,4 @@ +// NOCHECK extern int printf(); extern int scanf(); diff --git a/tests/regression/44-trier_analyzer/15-P1.c b/tests/regression/44-trier_analyzer/15-P1.c index 2690a6da44..b169ea4876 100644 --- a/tests/regression/44-trier_analyzer/15-P1.c +++ b/tests/regression/44-trier_analyzer/15-P1.c @@ -1,3 +1,4 @@ +// NOCHECK main () { int y, a; int *p, *q, *t; diff --git a/tests/regression/44-trier_analyzer/16-P2.c b/tests/regression/44-trier_analyzer/16-P2.c index 3942760be7..2f27d5dbe0 100644 --- a/tests/regression/44-trier_analyzer/16-P2.c +++ b/tests/regression/44-trier_analyzer/16-P2.c @@ -1,3 +1,4 @@ +// NOCHECK main () { int y, a, b; int *p, *q; diff --git a/tests/regression/44-trier_analyzer/17-P3.c b/tests/regression/44-trier_analyzer/17-P3.c index 7b8c8a13d8..0bbc9ee2d2 100644 --- a/tests/regression/44-trier_analyzer/17-P3.c +++ b/tests/regression/44-trier_analyzer/17-P3.c @@ -1,3 +1,4 @@ +// NOCHECK #include extern void *malloc(size_t); diff --git a/tests/regression/44-trier_analyzer/23-rec0.c b/tests/regression/44-trier_analyzer/23-rec0.c index aa13bbac8e..ee43820bb1 100644 --- a/tests/regression/44-trier_analyzer/23-rec0.c +++ b/tests/regression/44-trier_analyzer/23-rec0.c @@ -1,3 +1,4 @@ +// NOCHECK extern int printf(char *, ...); extern int scanf(char *, ...); extern void exit(int); diff --git a/tests/regression/44-trier_analyzer/33-recA.c b/tests/regression/44-trier_analyzer/33-recA.c index 74fa54b768..2938403326 100644 --- a/tests/regression/44-trier_analyzer/33-recA.c +++ b/tests/regression/44-trier_analyzer/33-recA.c @@ -1,4 +1,5 @@ //PARAM: --enable ana.context.widen +// NOCHECK //Needs context widening even with only def_exc extern int scanf(char *, ...); extern int printf(char *, ...); diff --git a/tests/regression/46-apron2/28-sv-comp-unroll-term.c b/tests/regression/46-apron2/28-sv-comp-unroll-term.c index a22b0e16bd..2a1f947dca 100644 --- a/tests/regression/46-apron2/28-sv-comp-unroll-term.c +++ b/tests/regression/46-apron2/28-sv-comp-unroll-term.c @@ -2,7 +2,7 @@ // Minimized from sv-benchmarks/c/ldv-linux-3.4-simple/32_1_cilled_ok_nondet_linux-3.4-32_1-drivers--staging--speakup--speakup_spkout.ko-ldv_main0_sequence_infinite_withcheck_stateful.cil.out.i // using loop unrolling of 1. -// Used to not terminate. +// NOTIMEOUT: Used to not terminate. struct speakup_info_t { int port_tts; diff --git a/tests/regression/46-apron2/34-iset_previously_problematic_c.c b/tests/regression/46-apron2/34-iset_previously_problematic_c.c index 3c1847bbcf..2b0f526957 100644 --- a/tests/regression/46-apron2/34-iset_previously_problematic_c.c +++ b/tests/regression/46-apron2/34-iset_previously_problematic_c.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int i = 0; diff --git a/tests/regression/46-apron2/36-iset_previosuly_problematic_g.c b/tests/regression/46-apron2/36-iset_previosuly_problematic_g.c index 4cbcaef064..89253052d5 100644 --- a/tests/regression/46-apron2/36-iset_previosuly_problematic_g.c +++ b/tests/regression/46-apron2/36-iset_previosuly_problematic_g.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int i = 0; diff --git a/tests/regression/46-apron2/37-iset_previosuly_problematic_f.c b/tests/regression/46-apron2/37-iset_previosuly_problematic_f.c index 918e67b0e8..c88aabe377 100644 --- a/tests/regression/46-apron2/37-iset_previosuly_problematic_f.c +++ b/tests/regression/46-apron2/37-iset_previosuly_problematic_f.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int a[256]; diff --git a/tests/regression/46-apron2/39-iset_previosuly_problematic_d.c b/tests/regression/46-apron2/39-iset_previosuly_problematic_d.c index 18a53d31aa..480691409d 100644 --- a/tests/regression/46-apron2/39-iset_previosuly_problematic_d.c +++ b/tests/regression/46-apron2/39-iset_previosuly_problematic_d.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int l; diff --git a/tests/regression/46-apron2/45-iset_previosuly_problematic_i.c b/tests/regression/46-apron2/45-iset_previosuly_problematic_i.c index dab6078b98..b9506cb453 100644 --- a/tests/regression/46-apron2/45-iset_previosuly_problematic_i.c +++ b/tests/regression/46-apron2/45-iset_previosuly_problematic_i.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK char buf2[67]; int main(int argc, char **argv) diff --git a/tests/regression/46-apron2/47-iset_previously_problematic_a.c b/tests/regression/46-apron2/47-iset_previously_problematic_a.c index 2bf6044560..15d61d436b 100644 --- a/tests/regression/46-apron2/47-iset_previously_problematic_a.c +++ b/tests/regression/46-apron2/47-iset_previously_problematic_a.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int top; diff --git a/tests/regression/46-apron2/49-iset_previously_problematic_b.c b/tests/regression/46-apron2/49-iset_previously_problematic_b.c index 19d925013c..336efa4eb0 100644 --- a/tests/regression/46-apron2/49-iset_previously_problematic_b.c +++ b/tests/regression/46-apron2/49-iset_previously_problematic_b.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK typedef int wchar_t; typedef unsigned long size_t; diff --git a/tests/regression/46-apron2/51-iset_previosuly_problematic_e.c b/tests/regression/46-apron2/51-iset_previosuly_problematic_e.c index 551bb731e9..582cd4916c 100644 --- a/tests/regression/46-apron2/51-iset_previosuly_problematic_e.c +++ b/tests/regression/46-apron2/51-iset_previosuly_problematic_e.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int j = -1; diff --git a/tests/regression/46-apron2/53-iset_previously_problematic_h.c b/tests/regression/46-apron2/53-iset_previously_problematic_h.c index 05489e47dc..242f1fb377 100644 --- a/tests/regression/46-apron2/53-iset_previously_problematic_h.c +++ b/tests/regression/46-apron2/53-iset_previously_problematic_h.c @@ -1,6 +1,7 @@ // SKIP PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned --set ana.activated[+] apron // These examples were cases were we saw issues of not reaching a fixpoint during development of the octagon domain. Since those issues might // resurface, these tests without asserts are included +// NOCHECK int main(int argc, char const *argv[]) { int iter = 0; diff --git a/tests/regression/46-apron2/58-issue-1249.c b/tests/regression/46-apron2/58-issue-1249.c index 862c539d15..903eafdac8 100644 --- a/tests/regression/46-apron2/58-issue-1249.c +++ b/tests/regression/46-apron2/58-issue-1249.c @@ -2,7 +2,7 @@ int *a; int b; void c(int d) { - // *a is a null pointer here, so we should warn but maybe not crash + // NOCRASH: *a is a null pointer here, so we should warn but maybe not crash *a = d; } int main() { diff --git a/tests/regression/46-apron2/59-issue-1319.c b/tests/regression/46-apron2/59-issue-1319.c index 1c11d6093e..62520c95c1 100644 --- a/tests/regression/46-apron2/59-issue-1319.c +++ b/tests/regression/46-apron2/59-issue-1319.c @@ -8,7 +8,7 @@ int main() t = &c; - // Type of *t and c do not match, this caused a crash before + // NOCRASH: Type of *t and c do not match, this caused a crash before if(*t == 'a') { t++; } @@ -18,7 +18,7 @@ int main() int other() { - // Same problem, but a bit more involved + // NOCRASH: Same problem, but a bit more involved unsigned char *t; char buf[100] = "bliblablubapk\r"; diff --git a/tests/regression/46-apron2/60-issue-1338.c b/tests/regression/46-apron2/60-issue-1338.c index 899fe613b3..92afa3b74f 100644 --- a/tests/regression/46-apron2/60-issue-1338.c +++ b/tests/regression/46-apron2/60-issue-1338.c @@ -1,4 +1,5 @@ // SKIP PARAM: --set ana.activated[+] apron +// NOCRASH #include int main() { diff --git a/tests/regression/46-apron2/82-fixpoint-not-reached.c b/tests/regression/46-apron2/82-fixpoint-not-reached.c index 1dff575a7c..66f00770da 100644 --- a/tests/regression/46-apron2/82-fixpoint-not-reached.c +++ b/tests/regression/46-apron2/82-fixpoint-not-reached.c @@ -1,5 +1,5 @@ // SKIP PARAM: --set sem.int.signed_overflow assume_none --set ana.activated[+] apron - +// FIXPOINT int main() { int minInt = -2147483647 + -1; int x = (minInt + -1) +1; diff --git a/tests/regression/52-apron-mukherjee/19-mukherjee_fig_3_11.c b/tests/regression/52-apron-mukherjee/19-mukherjee_fig_3_11.c index b00a2b2270..73499179c5 100644 --- a/tests/regression/52-apron-mukherjee/19-mukherjee_fig_3_11.c +++ b/tests/regression/52-apron-mukherjee/19-mukherjee_fig_3_11.c @@ -1,5 +1,5 @@ // SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --set ana.activated[+] threadJoins -// TODO: checks nothing? +// NOCHECK: checks nothing? #include int x; diff --git a/tests/regression/55-loop-unrolling/08-bad.c b/tests/regression/55-loop-unrolling/08-bad.c index e2ad0f0453..df9131d6bf 100644 --- a/tests/regression/55-loop-unrolling/08-bad.c +++ b/tests/regression/55-loop-unrolling/08-bad.c @@ -1,4 +1,5 @@ // PARAM: --set exp.unrolling-factor 1 --enable dbg.run_cil_check +// CRAM int main() { int m; diff --git a/tests/regression/55-loop-unrolling/08-bad.t b/tests/regression/55-loop-unrolling/08-bad.t index 11cded728f..f49ad67b5b 100644 --- a/tests/regression/55-loop-unrolling/08-bad.t +++ b/tests/regression/55-loop-unrolling/08-bad.t @@ -1,6 +1,6 @@ $ goblint --set lib.activated '[]' --set exp.unrolling-factor 1 --enable justcil --set dbg.justcil-printer clean 08-bad.c - [Info] unrolling loop at 08-bad.c:8:7-8:23 with factor 1 - [Info] unrolling loop at 08-bad.c:14:8-14:24 with factor 1 + [Info] unrolling loop at 08-bad.c:9:7-9:23 with factor 1 + [Info] unrolling loop at 08-bad.c:15:8-15:24 with factor 1 int main(void) { int m ; diff --git a/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.c b/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.c index 096c031cf1..4a3f7c1cfa 100644 --- a/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.c +++ b/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.c @@ -1,3 +1,4 @@ +// CRAM int main() { int i = 0; while (i < 10) diff --git a/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t b/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t index 32ec663717..3a3b7c43cf 100644 --- a/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t +++ b/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t @@ -1,7 +1,7 @@ $ cfgDot --unroll 1 11-unrolled-loop-invariant.c - [Info] unrolling loop at 11-unrolled-loop-invariant.c:3:3-4:8 with factor 1 - [Info] unrolling loop at 11-unrolled-loop-invariant.c:8:5-9:10 with factor 1 - [Info] unrolling loop at 11-unrolled-loop-invariant.c:7:3-11:3 with factor 1 + [Info] unrolling loop at 11-unrolled-loop-invariant.c:4:3-5:8 with factor 1 + [Info] unrolling loop at 11-unrolled-loop-invariant.c:9:5-10:10 with factor 1 + [Info] unrolling loop at 11-unrolled-loop-invariant.c:8:3-12:3 with factor 1 $ graph-easy --as=boxart main.dot ┌──────────────────────────────────────────────────────┐ @@ -11,160 +11,160 @@ │ (body) ▼ ┌──────────────────────────────────────────────────────┐ - │ 11-unrolled-loop-invariant.c:2:3-2:12 │ - │ (11-unrolled-loop-invariant.c:2:7-2:12 (synthetic)) │ - │ YAML loc: 11-unrolled-loop-invariant.c:2:3-2:12 │ + │ 11-unrolled-loop-invariant.c:3:3-3:12 │ + │ (11-unrolled-loop-invariant.c:3:7-3:12 (synthetic)) │ + │ YAML loc: 11-unrolled-loop-invariant.c:3:3-3:12 │ │ GraphML: true; server: false │ └──────────────────────────────────────────────────────┘ │ │ i = 0 ▼ ┌──────────────────────────────────────────────────────┐ - │ 11-unrolled-loop-invariant.c:3:3-4:8 (synthetic) │ - │ (11-unrolled-loop-invariant.c:3:10-3:16 (synthetic)) │ - │ YAML loop: 11-unrolled-loop-invariant.c:3:3-4:8 │ + │ 11-unrolled-loop-invariant.c:4:3-5:8 (synthetic) │ + │ (11-unrolled-loop-invariant.c:4:10-4:16 (synthetic)) │ + │ YAML loop: 11-unrolled-loop-invariant.c:4:3-5:8 │ │ GraphML: true; server: false │ - ┌───────────── │ loop: 11-unrolled-loop-invariant.c:3:3-4:8 │ ·┐ + ┌───────────── │ loop: 11-unrolled-loop-invariant.c:4:3-5:8 │ ·┐ │ └──────────────────────────────────────────────────────┘ : │ │ : │ │ Pos(i < 10) : │ ▼ : │ ┌──────────────────────────────────────────────────────┐ : - │ │ 11-unrolled-loop-invariant.c:4:5-4:8 │ : - │ │ (11-unrolled-loop-invariant.c:4:5-4:8) │ : - │ │ YAML loc: 11-unrolled-loop-invariant.c:4:5-4:8 │ : + │ │ 11-unrolled-loop-invariant.c:5:5-5:8 │ : + │ │ (11-unrolled-loop-invariant.c:5:5-5:8) │ : + │ │ YAML loc: 11-unrolled-loop-invariant.c:5:5-5:8 │ : │ │ GraphML: true; server: true │ ·┼····································································┐ │ └──────────────────────────────────────────────────────┘ : : │ │ : : │ │ i = i + 1 : : │ Neg(i < 10) ▼ ▼ : │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : - │ │ 11-unrolled-loop-invariant.c:3:3-4:8 (synthetic) │ : - │ │ (11-unrolled-loop-invariant.c:3:10-3:16 (synthetic)) │ : - │ │ YAML loop: 11-unrolled-loop-invariant.c:3:3-4:8 │ : + │ │ 11-unrolled-loop-invariant.c:4:3-5:8 (synthetic) │ : + │ │ (11-unrolled-loop-invariant.c:4:10-4:16 (synthetic)) │ : + │ │ YAML loop: 11-unrolled-loop-invariant.c:4:3-5:8 │ : │ │ GraphML: true; server: false │ : - │ │ loop: 11-unrolled-loop-invariant.c:3:3-4:8 │ : + │ │ loop: 11-unrolled-loop-invariant.c:4:3-5:8 │ : │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ : │ │ │ ▲ : │ │ Neg(i < 10) │ Pos(i < 10) │ i = i + 1 : │ ▼ │ │ : │ ┌──────────────────────────────────────────────────────┐ │ ┌───────────────────────────────────────────────────┐ : - │ │ 11-unrolled-loop-invariant.c:6:3-6:19 │ │ │ 11-unrolled-loop-invariant.c:4:5-4:8 │ : - │ │ (11-unrolled-loop-invariant.c:6:7-6:12 (synthetic)) │ │ │ (11-unrolled-loop-invariant.c:4:5-4:8) │ : - │ │ YAML loc: 11-unrolled-loop-invariant.c:6:3-6:19 │ │ │ YAML loc: 11-unrolled-loop-invariant.c:4:5-4:8 │ : + │ │ 11-unrolled-loop-invariant.c:7:3-7:19 │ │ │ 11-unrolled-loop-invariant.c:5:5-5:8 │ : + │ │ (11-unrolled-loop-invariant.c:7:7-7:12 (synthetic)) │ │ │ (11-unrolled-loop-invariant.c:5:5-5:8) │ : + │ │ YAML loc: 11-unrolled-loop-invariant.c:7:3-7:19 │ │ │ YAML loc: 11-unrolled-loop-invariant.c:5:5-5:8 │ : └────────────▶ │ GraphML: true; server: false │ └───────────▶ │ GraphML: true; server: true │ ◀┘ └──────────────────────────────────────────────────────┘ └───────────────────────────────────────────────────┘ │ │ j = 0 ▼ ┌──────────────────────────────────────────────────────┐ - │ 11-unrolled-loop-invariant.c:6:3-6:19 (synthetic) │ - │ (11-unrolled-loop-invariant.c:6:14-6:19 (synthetic)) │ + │ 11-unrolled-loop-invariant.c:7:3-7:19 (synthetic) │ + │ (11-unrolled-loop-invariant.c:7:14-7:19 (synthetic)) │ │ GraphML: true; server: false │ └──────────────────────────────────────────────────────┘ │ │ k = 0 ▼ ┌──────────────────────────────────────────────────────┐ ┌───────────────────────────────────────────────────┐ ┌──────────────────┐ - │ 11-unrolled-loop-invariant.c:7:3-11:3 (synthetic) │ │ 11-unrolled-loop-invariant.c:12:3-12:11 │ │ │ - │ (11-unrolled-loop-invariant.c:7:10-7:16 (synthetic)) │ │ (11-unrolled-loop-invariant.c:12:10-12:11) │ │ │ - │ YAML loop: 11-unrolled-loop-invariant.c:7:3-11:3 │ │ YAML loc: 11-unrolled-loop-invariant.c:12:3-12:11 │ │ return of main() │ + │ 11-unrolled-loop-invariant.c:8:3-12:3 (synthetic) │ │ 11-unrolled-loop-invariant.c:13:3-13:11 │ │ │ + │ (11-unrolled-loop-invariant.c:8:10-8:16 (synthetic)) │ │ (11-unrolled-loop-invariant.c:13:10-13:11) │ │ │ + │ YAML loop: 11-unrolled-loop-invariant.c:8:3-12:3 │ │ YAML loc: 11-unrolled-loop-invariant.c:13:3-13:11 │ │ return of main() │ │ GraphML: true; server: false │ Neg(j < 10) │ GraphML: true; server: true │ return 0 │ │ - ┌············· │ loop: 11-unrolled-loop-invariant.c:7:3-11:3 │ ─────────────▶ │ │ ──────────▶ │ │ + ┌············· │ loop: 11-unrolled-loop-invariant.c:8:3-12:3 │ ─────────────▶ │ │ ──────────▶ │ │ : └──────────────────────────────────────────────────────┘ └───────────────────────────────────────────────────┘ └──────────────────┘ : │ ▲ Neg(j < 10) : │ Pos(j < 10) └──────────────────────────────────────────────────────────────────────────────────────────┐ : ▼ │ : ┌──────────────────────────────────────────────────────┐ │ - : │ 11-unrolled-loop-invariant.c:8:5-9:10 (synthetic) │ │ - : │ (11-unrolled-loop-invariant.c:8:12-8:19 (synthetic)) │ │ - : │ YAML loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ │ + : │ 11-unrolled-loop-invariant.c:9:5-10:10 (synthetic) │ │ + : │ (11-unrolled-loop-invariant.c:9:12-9:19 (synthetic)) │ │ + : │ YAML loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ │ : │ GraphML: true; server: false │ │ - ┌──────────────────────────┼───────────── │ loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ ······································································┐ │ + ┌──────────────────────────┼───────────── │ loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ ······································································┐ │ │ : └──────────────────────────────────────────────────────┘ : │ │ : │ : │ │ : │ Pos(k < 100) : │ │ : ▼ : │ │ : ┌──────────────────────────────────────────────────────┐ : │ - │ : │ 11-unrolled-loop-invariant.c:9:7-9:10 │ : │ - │ : │ (11-unrolled-loop-invariant.c:9:7-9:10) │ : │ - │ : │ YAML loc: 11-unrolled-loop-invariant.c:9:7-9:10 │ : │ + │ : │ 11-unrolled-loop-invariant.c:10:7-10:10 │ : │ + │ : │ (11-unrolled-loop-invariant.c:10:7-10:10) │ : │ + │ : │ YAML loc: 11-unrolled-loop-invariant.c:10:7-10:10 │ : │ │ : │ GraphML: true; server: true │ ······································································┼············┐ │ │ : └──────────────────────────────────────────────────────┘ : : │ │ : │ : : │ │ : │ k = k + 1 ┌────────────────────────────────────────────────────┼────────────┼────────────────────────┼─────────────┐ │ : ▼ │ : : │ │ │ : ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : : │ │ - │ : │ 11-unrolled-loop-invariant.c:8:5-9:10 (synthetic) │ : : │ │ - │ : │ (11-unrolled-loop-invariant.c:8:12-8:19 (synthetic)) │ : : │ │ - │ : │ YAML loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ : : │ │ + │ : │ 11-unrolled-loop-invariant.c:9:5-10:10 (synthetic) │ : : │ │ + │ : │ (11-unrolled-loop-invariant.c:9:12-9:19 (synthetic)) │ : : │ │ + │ : │ YAML loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ : : │ │ │ : │ GraphML: true; server: false │ : : │ │ - │ : │ loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ : : │ │ + │ : │ loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ : : │ │ │ : └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ : : │ │ │ : │ : ▲ : : │ │ │ : │ Pos(k < 100) : │ k = k + 1 : : │ │ │ : ▼ : │ : : │ │ │ : ┌──────────────────────────────────────────────────────┐ : │ : : │ │ - │ : │ 11-unrolled-loop-invariant.c:9:7-9:10 │ : │ : : │ │ - │ : │ (11-unrolled-loop-invariant.c:9:7-9:10) │ : │ : : │ │ - │ : │ YAML loc: 11-unrolled-loop-invariant.c:9:7-9:10 │ : │ : : │ │ + │ : │ 11-unrolled-loop-invariant.c:10:7-10:10 │ : │ : : │ │ + │ : │ (11-unrolled-loop-invariant.c:10:7-10:10) │ : │ : : │ │ + │ : │ YAML loc: 11-unrolled-loop-invariant.c:10:7-10:10 │ : │ : : │ │ │ : │ GraphML: true; server: true │ ─┼───────────────┘ : : │ │ │ : └──────────────────────────────────────────────────────┘ : : : │ │ │ : : : : : │ │ ┌────┘ : : : : : │ │ │ : ▼ : : : │ │ │ : ┌──────────────────────────────────────────────────────┐ : : : │ │ - │ : │ 11-unrolled-loop-invariant.c:9:7-9:10 │ : : : │ │ - │ : │ (11-unrolled-loop-invariant.c:9:7-9:10) │ : : : │ │ - │ : │ YAML loc: 11-unrolled-loop-invariant.c:9:7-9:10 │ : : : │ │ + │ : │ 11-unrolled-loop-invariant.c:10:7-10:10 │ : : : │ │ + │ : │ (11-unrolled-loop-invariant.c:10:7-10:10) │ : : : │ │ + │ : │ YAML loc: 11-unrolled-loop-invariant.c:10:7-10:10 │ : : : │ │ │ ┌··························┼············▶ │ GraphML: true; server: true │ ◀┼───────────────┐ : : │ │ │ : : └──────────────────────────────────────────────────────┘ : │ : : │ │ │ : : │ : │ : : │ │ │ : : │ k = k + 1 : │ Pos(k < 100) : : │ │ │ : : ▼ ▼ │ : : │ │ │ : : ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : : │ │ - │ : : │ 11-unrolled-loop-invariant.c:8:5-9:10 (synthetic) │ : : │ │ - │ : : │ (11-unrolled-loop-invariant.c:8:12-8:19 (synthetic)) │ : : │ │ - │ : : │ YAML loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ : : │ │ + │ : : │ 11-unrolled-loop-invariant.c:9:5-10:10 (synthetic) │ : : │ │ + │ : : │ (11-unrolled-loop-invariant.c:9:12-9:19 (synthetic)) │ : : │ │ + │ : : │ YAML loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ : : │ │ │ : k = k + 1 : │ GraphML: true; server: false │ : : │ │ - │ : ┌─────────────────────┼────────────▶ │ loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ ◀┼············┼···················┐ │ │ + │ : ┌─────────────────────┼────────────▶ │ loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ ◀┼············┼···················┐ │ │ │ : │ : └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ : : : │ │ │ : │ : │ : : : │ │ │ : │ : │ Neg(k < 100) : : : │ │ │ : │ : ▼ : : : │ │ │ : │ : ┌──────────────────────────────────────────────────────┐ : : : │ │ - │ : │ : │ 11-unrolled-loop-invariant.c:10:5-10:8 │ : : : │ │ - │ : │ : │ (11-unrolled-loop-invariant.c:10:5-10:8) │ : : : │ │ - │ : │ : │ YAML loc: 11-unrolled-loop-invariant.c:10:5-10:8 │ : : : │ │ + │ : │ : │ 11-unrolled-loop-invariant.c:11:5-11:8 │ : : : │ │ + │ : │ : │ (11-unrolled-loop-invariant.c:11:5-11:8) │ : : : │ │ + │ : │ : │ YAML loc: 11-unrolled-loop-invariant.c:11:5-11:8 │ : : : │ │ │ : │ ┌────────────────┼────────────▶ │ GraphML: true; server: true │ ◀·····································································┼············┼···················┼····┼·············┼····┐ │ : │ │ : └──────────────────────────────────────────────────────┘ : : : │ │ : │ : │ │ : │ : : : │ │ : │ : │ │ : │ j = j + 1 ┌────────────────────────────────────────────────────┼────────────┼───────────────────┼────┘ │ : │ : │ │ : ▼ │ : : : │ : │ : │ │ : ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : : : │ : - │ : │ │ : │ 11-unrolled-loop-invariant.c:7:3-11:3 (synthetic) │ : : : │ : - │ : │ │ : │ (11-unrolled-loop-invariant.c:7:10-7:16 (synthetic)) │ : : : │ : - │ : │ │ Neg(k < 100) : │ YAML loop: 11-unrolled-loop-invariant.c:7:3-11:3 │ : : : │ : + │ : │ │ : │ 11-unrolled-loop-invariant.c:8:3-12:3 (synthetic) │ : : : │ : + │ : │ │ : │ (11-unrolled-loop-invariant.c:8:10-8:16 (synthetic)) │ : : : │ : + │ : │ │ Neg(k < 100) : │ YAML loop: 11-unrolled-loop-invariant.c:8:3-12:3 │ : : : │ : │ : │ │ : │ GraphML: true; server: false │ : : : │ : - │ : │ │ └············▶ │ loop: 11-unrolled-loop-invariant.c:7:3-11:3 │ ◀┼────────────┼───────────────────┼────┐ │ : + │ : │ │ └············▶ │ loop: 11-unrolled-loop-invariant.c:8:3-12:3 │ ◀┼────────────┼───────────────────┼────┐ │ : │ : │ │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ : : : │ │ : │ : │ │ │ : : : │ │ : │ : │ │ │ Pos(j < 10) : : : │ │ : │ : │ │ ▼ : : : │ │ : │ : │ │ ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ : : : │ │ : - │ : │ │ │ 11-unrolled-loop-invariant.c:8:5-9:10 (synthetic) │ : : : │ │ : - │ : │ │ │ (11-unrolled-loop-invariant.c:8:12-8:19 (synthetic)) │ : : : │ │ : - │ : │ │ │ YAML loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ : : : │ j = j + 1 │ : + │ : │ │ │ 11-unrolled-loop-invariant.c:9:5-10:10 (synthetic) │ : : : │ │ : + │ : │ │ │ (11-unrolled-loop-invariant.c:9:12-9:19 (synthetic)) │ : : : │ │ : + │ : │ │ │ YAML loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ : : : │ j = j + 1 │ : │ : │ │ │ GraphML: true; server: false │ : : : │ │ : - │ : │ └────────────────────────────── │ loop: 11-unrolled-loop-invariant.c:8:5-9:10 │ ◀┘ : : │ │ : + │ : │ └────────────────────────────── │ loop: 11-unrolled-loop-invariant.c:9:5-10:10 │ ◀┘ : : │ │ : │ : │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ : : │ │ : │ : │ │ : : : │ │ : │ : │ │ Pos(k < 100) └·································································┼···················┘ │ │ : │ : │ ▼ : │ │ : │ : │ ┌──────────────────────────────────────────────────────┐ : │ │ : - │ : │ │ 11-unrolled-loop-invariant.c:9:7-9:10 │ : │ │ : - │ : │ │ (11-unrolled-loop-invariant.c:9:7-9:10) │ : │ │ : - │ : │ │ YAML loc: 11-unrolled-loop-invariant.c:9:7-9:10 │ : │ │ : + │ : │ │ 11-unrolled-loop-invariant.c:10:7-10:10 │ : │ │ : + │ : │ │ (11-unrolled-loop-invariant.c:10:7-10:10) │ : │ │ : + │ : │ │ YAML loc: 11-unrolled-loop-invariant.c:10:7-10:10 │ : │ │ : │ : └─────────────────────────────────── │ GraphML: true; server: true │ ◀··················································································┘ ┌····┼·············┼····┘ │ : └──────────────────────────────────────────────────────┘ : │ │ │ : : : │ │ @@ -174,42 +174,42 @@ │ ┌·····························································································································································┘ │ │ │ : │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ - │ │ 11-unrolled-loop-invariant.c:10:5-10:8 │ │ │ - │ │ (11-unrolled-loop-invariant.c:10:5-10:8) │ │ │ - │ Neg(k < 100) │ YAML loc: 11-unrolled-loop-invariant.c:10:5-10:8 │ │ │ + │ │ 11-unrolled-loop-invariant.c:11:5-11:8 │ │ │ + │ │ (11-unrolled-loop-invariant.c:11:5-11:8) │ │ │ + │ Neg(k < 100) │ YAML loc: 11-unrolled-loop-invariant.c:11:5-11:8 │ │ │ └────────────────────────────────────────────▶ │ GraphML: true; server: true │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────┘ │ ▲ Neg(k < 100) │ └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ $ goblint --set lib.activated '[]' --set exp.unrolling-factor 5 --enable ana.int.interval --enable witness.yaml.enabled --set witness.yaml.entry-types '["location_invariant", "loop_invariant"]' 11-unrolled-loop-invariant.c - [Info] unrolling loop at 11-unrolled-loop-invariant.c:3:3-4:8 with factor 5 - [Info] unrolling loop at 11-unrolled-loop-invariant.c:8:5-9:10 with factor 5 - [Info] unrolling loop at 11-unrolled-loop-invariant.c:7:3-11:3 with factor 5 + [Info] unrolling loop at 11-unrolled-loop-invariant.c:4:3-5:8 with factor 5 + [Info] unrolling loop at 11-unrolled-loop-invariant.c:9:5-10:10 with factor 5 + [Info] unrolling loop at 11-unrolled-loop-invariant.c:8:3-12:3 with factor 5 [Info][Deadcode] Logical lines of code (LLoC) summary: live: 10 dead: 0 total lines: 10 - [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:7:10-7:16) - [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:7:10-7:16) - [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:3:10-3:16) - [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:3:10-3:16) - [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:3:10-3:16) - [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:3:10-3:16) - [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:3:10-3:16) - [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:7:10-7:16) - [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:7:10-7:16) - [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:12-8:19) - [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:7:10-7:16) + [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:10-8:16) + [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:10-8:16) + [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:4:10-4:16) + [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:4:10-4:16) + [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:4:10-4:16) + [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:4:10-4:16) + [Warning][Deadcode][CWE-571] condition 'i < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:4:10-4:16) + [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:10-8:16) + [Warning][Deadcode][CWE-570] condition 'k < 100' (possibly inserted by CIL) is always false (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:10-8:16) + [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:9:12-9:19) + [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:10-8:16) [Info][Witness] witness generation summary: total generation entries: 16 @@ -218,7 +218,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 5 function: main loop_invariant: @@ -229,7 +229,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 5 function: main loop_invariant: @@ -243,7 +243,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 7 + line: 8 column: 3 function: main loop_invariant: @@ -254,7 +254,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 7 + line: 8 column: 3 function: main loop_invariant: @@ -266,7 +266,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 3 + line: 4 column: 3 function: main loop_invariant: @@ -278,7 +278,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 3 function: main location_invariant: @@ -289,7 +289,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 3 function: main location_invariant: @@ -300,7 +300,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 3 function: main location_invariant: @@ -311,7 +311,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 10 + line: 11 column: 5 function: main location_invariant: @@ -322,7 +322,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 10 + line: 11 column: 5 function: main location_invariant: @@ -333,7 +333,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 10 + line: 11 column: 5 function: main location_invariant: @@ -345,7 +345,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 7 function: main location_invariant: @@ -356,7 +356,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 7 function: main location_invariant: @@ -367,7 +367,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 7 function: main location_invariant: @@ -379,7 +379,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 6 + line: 7 column: 3 function: main location_invariant: @@ -390,7 +390,7 @@ location: file_name: 11-unrolled-loop-invariant.c file_hash: $FILE_HASH - line: 4 + line: 5 column: 5 function: main location_invariant: diff --git a/tests/regression/56-witness/46-top-bool-invariant.c b/tests/regression/56-witness/46-top-bool-invariant.c index 2c90a55a2d..a11fea0991 100644 --- a/tests/regression/56-witness/46-top-bool-invariant.c +++ b/tests/regression/56-witness/46-top-bool-invariant.c @@ -1,5 +1,5 @@ // PARAM: --enable witness.yaml.enabled --set witness.yaml.entry-types '["location_invariant"]' --enable ana.int.def_exc --enable ana.int.interval --enable ana.int.enums --enable ana.int.congruence --enable ana.int.interval_set --disable witness.invariant.inexact-type-bounds - +// CRAM int main() { _Bool x; return 0; diff --git a/tests/regression/56-witness/47-top-int-invariant.c b/tests/regression/56-witness/47-top-int-invariant.c index 45f6106ce8..ef39ecd9b2 100644 --- a/tests/regression/56-witness/47-top-int-invariant.c +++ b/tests/regression/56-witness/47-top-int-invariant.c @@ -1,5 +1,5 @@ // PARAM: --enable witness.yaml.enabled --set witness.yaml.entry-types '["location_invariant"]' --enable ana.int.def_exc --enable ana.int.interval --enable ana.int.enums --enable ana.int.congruence --enable ana.int.interval_set --disable witness.invariant.inexact-type-bounds - +// CRAM int main() { int x; return 0; diff --git a/tests/regression/56-witness/52-witness-lifter-ps2.c b/tests/regression/56-witness/52-witness-lifter-ps2.c index bcb7c1410c..1eb3495235 100644 --- a/tests/regression/56-witness/52-witness-lifter-ps2.c +++ b/tests/regression/56-witness/52-witness-lifter-ps2.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.sv-comp.enabled --enable ana.sv-comp.functions --enable witness.graphml.enabled --set ana.specification 'CHECK( init(main()), LTL(G valid-memtrack) )' --set ana.activated[+] memLeak --set ana.path_sens[+] memLeak --set ana.malloc.unique_address_count 1 +// NOCRASH struct _twoIntsStruct { int intOne ; int intTwo ; diff --git a/tests/regression/56-witness/53-witness-lifter-ps3.c b/tests/regression/56-witness/53-witness-lifter-ps3.c index 06b73b3888..ff368a88fc 100644 --- a/tests/regression/56-witness/53-witness-lifter-ps3.c +++ b/tests/regression/56-witness/53-witness-lifter-ps3.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.sv-comp.enabled --enable ana.sv-comp.functions --enable witness.graphml.enabled --set ana.specification 'CHECK( init(main()), LTL(G valid-memtrack) )' --set ana.activated[+] memLeak --set ana.path_sens[+] memLeak --set ana.malloc.unique_address_count 1 +// NOCRASH struct _twoIntsStruct { int intOne ; int intTwo ; diff --git a/tests/regression/61-evalAssert/01-union_evalAssert.c b/tests/regression/61-evalAssert/01-union_evalAssert.c index 22e72e0e51..150d1fada2 100644 --- a/tests/regression/61-evalAssert/01-union_evalAssert.c +++ b/tests/regression/61-evalAssert/01-union_evalAssert.c @@ -1,5 +1,5 @@ // PARAM: --set trans.activated[+] "assert" - +// NOCHECK // Running the assert transformation on this test used to yield code that cannot be compiled with gcc, due to superfluous offsets on a pointer struct s { int a; diff --git a/tests/regression/63-affeq/14-norm_inv.c b/tests/regression/63-affeq/14-norm_inv.c index d93fa00cd4..df144fc402 100644 --- a/tests/regression/63-affeq/14-norm_inv.c +++ b/tests/regression/63-affeq/14-norm_inv.c @@ -3,6 +3,7 @@ // Normalization should be triggered when an invertible expression is assigned. // No asserts, likely fixpoint regression. // TODO: used to have list-based matrices, issue was only with those? +// NOCHECK int main() { int A, B; int r, d, p, q; diff --git a/tests/regression/63-affeq/17-verify.c b/tests/regression/63-affeq/17-verify.c index 7ac1b202e4..2ae7d338ba 100644 --- a/tests/regression/63-affeq/17-verify.c +++ b/tests/regression/63-affeq/17-verify.c @@ -1,5 +1,5 @@ //SKIP PARAM: --set ana.activated[+] affeq --sem.int.signed_overflow "assume_none" --enable ana.int.interval -// Error in leq check led to verify error +// FIXPOINT: Error in leq check led to verify error int main() { int n, a, b; diff --git a/tests/regression/66-interval-set-one/00-was_problematic_2.c b/tests/regression/66-interval-set-one/00-was_problematic_2.c index e5b3938a76..187e6f39df 100644 --- a/tests/regression/66-interval-set-one/00-was_problematic_2.c +++ b/tests/regression/66-interval-set-one/00-was_problematic_2.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned +// NOCHECK int main(void) { int arr[260]; diff --git a/tests/regression/66-interval-set-one/03-was_problematic_3.c b/tests/regression/66-interval-set-one/03-was_problematic_3.c index 59ce6e5cb6..2a8bd4bc46 100644 --- a/tests/regression/66-interval-set-one/03-was_problematic_3.c +++ b/tests/regression/66-interval-set-one/03-was_problematic_3.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned +// NOCHECK struct some_struct { int dir[7]; diff --git a/tests/regression/66-interval-set-one/14-no-int-context.c b/tests/regression/66-interval-set-one/14-no-int-context.c index 69d2aa2aa7..d701caf59e 100644 --- a/tests/regression/66-interval-set-one/14-no-int-context.c +++ b/tests/regression/66-interval-set-one/14-no-int-context.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.int.interval_set --set solver slr3t --disable ana.base.context.int - +// NOCHECK int f (int i) { // -2 return i+1; } // -3 void g(int j) { // -4 diff --git a/tests/regression/66-interval-set-one/39-calls.c b/tests/regression/66-interval-set-one/39-calls.c index 67ff46ad77..acfade3084 100644 --- a/tests/regression/66-interval-set-one/39-calls.c +++ b/tests/regression/66-interval-set-one/39-calls.c @@ -1,5 +1,6 @@ // PARAM: --enable ana.int.interval_set --disable ana.int.def_exc --set ana.base.arrays.domain partitioned // Variable-sized arrays +// NOCHECK void foo(int n, int a[n]); void foo2(int n, int a[30][n]); void foo3(int n, int a[n][30]); diff --git a/tests/regression/66-interval-set-one/93-enum.c b/tests/regression/66-interval-set-one/93-enum.c index 5d2b45043d..ca769fb126 100644 --- a/tests/regression/66-interval-set-one/93-enum.c +++ b/tests/regression/66-interval-set-one/93-enum.c @@ -1,4 +1,5 @@ // PARAM: --disable ana.int.interval_set --disable ana.int.def_exc --enable ana.int.enums +// NOCHECK void main(){ int n = 1; for (; n; n++) { // fixed point not reached here diff --git a/tests/regression/67-interval-sets-two/03-def_exc-interval-inconsistent.c b/tests/regression/67-interval-sets-two/03-def_exc-interval-inconsistent.c index 8d56fa0e3c..f5291fdcdc 100644 --- a/tests/regression/67-interval-sets-two/03-def_exc-interval-inconsistent.c +++ b/tests/regression/67-interval-sets-two/03-def_exc-interval-inconsistent.c @@ -1,6 +1,7 @@ // PARAM: --enable ana.int.def_exc --enable ana.int.interval_set --enable ana.sv-comp.functions --set sem.int.signed_overflow assume_none --set ana.int.refinement never // used to crash in branch when is_bool returned true, but to_bool returned None on (0,[1,1]) // manually minimized from sv-benchmarks/c/recursive/MultCommutative-2.c +// NOCHECK extern int __VERIFIER_nondet_int(void); void f(int m) { diff --git a/tests/regression/67-interval-sets-two/04-unsupported.c b/tests/regression/67-interval-sets-two/04-unsupported.c index 97ce11258a..4127da4d8b 100644 --- a/tests/regression/67-interval-sets-two/04-unsupported.c +++ b/tests/regression/67-interval-sets-two/04-unsupported.c @@ -1,6 +1,7 @@ // PARAM: --enable ana.int.interval_set --disable exp.fast_global_inits --set ana.base.arrays.domain partitioned // This is just to test that the analysis does not cause problems for features that are not explicitly dealt with +// NOCHECK: what problems? int main(void) { callok(); } diff --git a/tests/regression/67-interval-sets-two/14-trylock_rc_slr.c b/tests/regression/67-interval-sets-two/14-trylock_rc_slr.c index af46023135..a5e5e937cb 100644 --- a/tests/regression/67-interval-sets-two/14-trylock_rc_slr.c +++ b/tests/regression/67-interval-sets-two/14-trylock_rc_slr.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set --set solver slr3t +// NOCHECK #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/tests/regression/67-interval-sets-two/15-interval-bot.c b/tests/regression/67-interval-sets-two/15-interval-bot.c index ab7d043b92..6ab90062ae 100644 --- a/tests/regression/67-interval-sets-two/15-interval-bot.c +++ b/tests/regression/67-interval-sets-two/15-interval-bot.c @@ -1,5 +1,5 @@ // PARAM: --enable ana.int.interval_set --enable ana.int.def_exc - +// NOCHECK int main(){ unsigned long long a ; diff --git a/tests/regression/67-interval-sets-two/24-arithmetic-bot.c b/tests/regression/67-interval-sets-two/24-arithmetic-bot.c index f238788bb3..f9a2d0086a 100644 --- a/tests/regression/67-interval-sets-two/24-arithmetic-bot.c +++ b/tests/regression/67-interval-sets-two/24-arithmetic-bot.c @@ -1,5 +1,6 @@ // PARAM: --enable ana.int.interval_set --enable ana.int.def_exc // from: ldv-linux-3.0/usb_urb-drivers-vhost-vhost_net.ko.cil.out.i +// NOCHECK typedef unsigned long long u64; int main( ) diff --git a/tests/regression/67-interval-sets-two/31-ptrdiff.c b/tests/regression/67-interval-sets-two/31-ptrdiff.c index d7bd4667df..d6135f8734 100644 --- a/tests/regression/67-interval-sets-two/31-ptrdiff.c +++ b/tests/regression/67-interval-sets-two/31-ptrdiff.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set --set ana.base.arrays.domain partitioned --set ana.activated[+] var_eq +// NOCHECK int *tmp; int main () diff --git a/tests/regression/67-interval-sets-two/44-comparision-bot.c b/tests/regression/67-interval-sets-two/44-comparision-bot.c index 5b3622828a..eb6e90b5ea 100644 --- a/tests/regression/67-interval-sets-two/44-comparision-bot.c +++ b/tests/regression/67-interval-sets-two/44-comparision-bot.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set --enable ana.int.def_exc +// NOCHECK #include int main(){ int a = 0; diff --git a/tests/regression/67-interval-sets-two/56-interval-set-dead-code.c b/tests/regression/67-interval-sets-two/56-interval-set-dead-code.c index e1345155d9..df1d7346bd 100644 --- a/tests/regression/67-interval-sets-two/56-interval-set-dead-code.c +++ b/tests/regression/67-interval-sets-two/56-interval-set-dead-code.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set +// NOCHECK #include #include diff --git a/tests/regression/67-interval-sets-two/58-interval-set-dead-code-with-fun-call.c b/tests/regression/67-interval-sets-two/58-interval-set-dead-code-with-fun-call.c index b63ebd6fab..1a709243cb 100644 --- a/tests/regression/67-interval-sets-two/58-interval-set-dead-code-with-fun-call.c +++ b/tests/regression/67-interval-sets-two/58-interval-set-dead-code-with-fun-call.c @@ -1,4 +1,5 @@ // PARAM: --enable ana.int.interval_set +// NOCHECK #include #include diff --git a/tests/regression/71-doublelocking/15-rec-dyn-nested.c b/tests/regression/71-doublelocking/15-rec-dyn-nested.c index d5dac9cd81..472783a9f3 100644 --- a/tests/regression/71-doublelocking/15-rec-dyn-nested.c +++ b/tests/regression/71-doublelocking/15-rec-dyn-nested.c @@ -1,5 +1,5 @@ // PARAM: --set ana.activated[+] 'pthreadMutexType' -// Check we don't have a stack overflow because of tracking multiplicities +// NOCRASH: Check we don't have a stack overflow because of tracking multiplicities #define _GNU_SOURCE #include #include diff --git a/tests/regression/74-invalid_deref/15-juliet-uaf-global-var.c b/tests/regression/74-invalid_deref/15-juliet-uaf-global-var.c index cc9819950f..93d4d6f307 100644 --- a/tests/regression/74-invalid_deref/15-juliet-uaf-global-var.c +++ b/tests/regression/74-invalid_deref/15-juliet-uaf-global-var.c @@ -1,4 +1,5 @@ //PARAM: --set ana.activated[+] useAfterFree +// NOCHECK #include int *global; From 5de8823149be753d59e7e3f55c2eb0975e8fd09e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 18:52:31 +0300 Subject: [PATCH 428/689] Add NOCHECK and CRAM annotations to incremental tests --- tests/incremental/00-basic/01-global.c | 1 + tests/incremental/00-basic/01-global.patch | 1 + tests/incremental/00-basic/04-rename_ids.c | 1 + tests/incremental/00-basic/08-refine_interval_with_def_exc.c | 1 + tests/incremental/00-basic/12-rec-type.c | 2 +- tests/incremental/00-basic/12-rec-type.patch | 4 ++-- tests/incremental/00-basic/15-reluctant-test.c | 2 +- tests/incremental/04-var-rename/01-rename_and_shuffle.c | 2 +- tests/incremental/04-var-rename/01-rename_and_shuffle.patch | 2 +- tests/incremental/04-var-rename/02-rename_with_usage.c | 2 +- tests/incremental/04-var-rename/02-rename_with_usage.patch | 2 +- tests/incremental/04-var-rename/04-renamed_param.c | 1 + tests/incremental/04-var-rename/04-renamed_param.patch | 1 + .../04-var-rename/05-renamed_param_usage_changed.c | 2 +- .../04-var-rename/05-renamed_param_usage_changed.patch | 2 +- tests/incremental/05-method-rename/00-simple_rename.c | 2 +- tests/incremental/05-method-rename/00-simple_rename.patch | 2 +- tests/incremental/05-method-rename/01-dependent_rename.c | 2 +- tests/incremental/05-method-rename/01-dependent_rename.patch | 2 +- .../05-method-rename/02-cyclic_rename_dependency.c | 2 +- .../05-method-rename/02-cyclic_rename_dependency.patch | 2 +- tests/incremental/05-method-rename/03-cyclic_with_swap.c | 2 +- tests/incremental/05-method-rename/03-cyclic_with_swap.patch | 2 +- tests/incremental/05-method-rename/04-deep_change.c | 2 +- tests/incremental/05-method-rename/04-deep_change.patch | 2 +- tests/incremental/05-method-rename/05-common_rename.c | 2 +- tests/incremental/05-method-rename/05-common_rename.patch | 2 +- tests/incremental/05-method-rename/06-recursive_rename.c | 1 + tests/incremental/05-method-rename/06-recursive_rename.patch | 3 ++- tests/incremental/06-glob-var-rename/00-simple_rename.c | 2 +- tests/incremental/06-glob-var-rename/00-simple_rename.patch | 2 +- .../06-glob-var-rename/01-duplicate_local_global.c | 2 +- .../06-glob-var-rename/01-duplicate_local_global.patch | 2 +- tests/incremental/06-glob-var-rename/02-add_new_gvar.c | 2 +- tests/incremental/06-glob-var-rename/02-add_new_gvar.patch | 2 +- tests/incremental/11-restart/00-justglob.c | 1 + 36 files changed, 38 insertions(+), 29 deletions(-) diff --git a/tests/incremental/00-basic/01-global.c b/tests/incremental/00-basic/01-global.c index 8eac5b92a1..5b3a1feb6a 100644 --- a/tests/incremental/00-basic/01-global.c +++ b/tests/incremental/00-basic/01-global.c @@ -1,5 +1,6 @@ // Previosuly, the function was erroneously not reanalyzed when the global initializer/the start state changed // when hash-consing is activated. +// NOCHECK int g = 0; int main(){ diff --git a/tests/incremental/00-basic/01-global.patch b/tests/incremental/00-basic/01-global.patch index 2b86496f5a..9c74751174 100644 --- a/tests/incremental/00-basic/01-global.patch +++ b/tests/incremental/00-basic/01-global.patch @@ -3,6 +3,7 @@ @@ -1,6 +1,6 @@ // Previosuly, the function was erroneously not reanalyzed when the global initializer/the start state changed // when hash-consing is activated. + // NOCHECK -int g = 0; +int g = 35; diff --git a/tests/incremental/00-basic/04-rename_ids.c b/tests/incremental/00-basic/04-rename_ids.c index e5c9727edc..7f2884854d 100644 --- a/tests/incremental/00-basic/04-rename_ids.c +++ b/tests/incremental/00-basic/04-rename_ids.c @@ -1,3 +1,4 @@ +// NOCHECK int a; void b(); void c(); diff --git a/tests/incremental/00-basic/08-refine_interval_with_def_exc.c b/tests/incremental/00-basic/08-refine_interval_with_def_exc.c index da6cb9dd65..3fcf60e83a 100644 --- a/tests/incremental/00-basic/08-refine_interval_with_def_exc.c +++ b/tests/incremental/00-basic/08-refine_interval_with_def_exc.c @@ -1,3 +1,4 @@ +// NOCHECK struct input_state; typedef struct input_state input_state; struct input_state { diff --git a/tests/incremental/00-basic/12-rec-type.c b/tests/incremental/00-basic/12-rec-type.c index 7c862a107a..1c92e6f94b 100644 --- a/tests/incremental/00-basic/12-rec-type.c +++ b/tests/incremental/00-basic/12-rec-type.c @@ -4,7 +4,7 @@ typedef struct s_t s_t; union union_t { int i; - s_t *s[sizeof(s_t *)]; // This caused problems + s_t *s[sizeof(s_t *)]; // NOCRASH: This caused problems }; struct s_t { diff --git a/tests/incremental/00-basic/12-rec-type.patch b/tests/incremental/00-basic/12-rec-type.patch index 2a5bd8f478..5d00033464 100644 --- a/tests/incremental/00-basic/12-rec-type.patch +++ b/tests/incremental/00-basic/12-rec-type.patch @@ -5,8 +5,8 @@ index 7c862a107..a043e249c 100644 @@ -2,6 +2,7 @@ struct s_t ; typedef struct s_t s_t; - + +// Dummy change union union_t { int i; - s_t *s[sizeof(s_t *)]; // This caused problems + s_t *s[sizeof(s_t *)]; // NOCRASH: This caused problems diff --git a/tests/incremental/00-basic/15-reluctant-test.c b/tests/incremental/00-basic/15-reluctant-test.c index 6328061b29..a0c96977b7 100644 --- a/tests/incremental/00-basic/15-reluctant-test.c +++ b/tests/incremental/00-basic/15-reluctant-test.c @@ -1,5 +1,5 @@ #include -// This test used to resulted in an unreached fixpoint in the incremental implementation. +// FIXPOINT: This test used to resulted in an unreached fixpoint in the incremental implementation. int g = 3; diff --git a/tests/incremental/04-var-rename/01-rename_and_shuffle.c b/tests/incremental/04-var-rename/01-rename_and_shuffle.c index 7d6ea81e6f..0acafcae90 100644 --- a/tests/incremental/04-var-rename/01-rename_and_shuffle.c +++ b/tests/incremental/04-var-rename/01-rename_and_shuffle.c @@ -1,5 +1,5 @@ #include - +// CRAM // a is renamed to c, but the usage of a is replaced by b (semantic changes) int main() { int a = 0; diff --git a/tests/incremental/04-var-rename/01-rename_and_shuffle.patch b/tests/incremental/04-var-rename/01-rename_and_shuffle.patch index 94e27d9a80..fa6342b0ef 100644 --- a/tests/incremental/04-var-rename/01-rename_and_shuffle.patch +++ b/tests/incremental/04-var-rename/01-rename_and_shuffle.patch @@ -1,7 +1,7 @@ --- tests/incremental/04-var-rename/01-rename_and_shuffle.c +++ tests/incremental/04-var-rename/01-rename_and_shuffle.c @@ -2,10 +2,10 @@ - + // CRAM // a is renamed to c, but the usage of a is replaced by b (semantic changes) int main() { - int a = 0; diff --git a/tests/incremental/04-var-rename/02-rename_with_usage.c b/tests/incremental/04-var-rename/02-rename_with_usage.c index 2c93c487d8..928a8014d1 100644 --- a/tests/incremental/04-var-rename/02-rename_with_usage.c +++ b/tests/incremental/04-var-rename/02-rename_with_usage.c @@ -1,5 +1,5 @@ #include - +// CRAM //a is renamed to c, but its usages stay the same int main() { int a = 0; diff --git a/tests/incremental/04-var-rename/02-rename_with_usage.patch b/tests/incremental/04-var-rename/02-rename_with_usage.patch index 6cfe41bbb1..b6d0e4cb19 100644 --- a/tests/incremental/04-var-rename/02-rename_with_usage.patch +++ b/tests/incremental/04-var-rename/02-rename_with_usage.patch @@ -1,7 +1,7 @@ --- tests/incremental/04-var-rename/02-rename_with_usage.c +++ tests/incremental/04-var-rename/02-rename_with_usage.c @@ -2,10 +2,10 @@ - + // CRAM //a is renamed to c, but its usages stay the same int main() { - int a = 0; diff --git a/tests/incremental/04-var-rename/04-renamed_param.c b/tests/incremental/04-var-rename/04-renamed_param.c index 770af2683c..1d45695b1b 100644 --- a/tests/incremental/04-var-rename/04-renamed_param.c +++ b/tests/incremental/04-var-rename/04-renamed_param.c @@ -1,4 +1,5 @@ // function param is renamed (no semantic changes) +// CRAM void method(int a) { int c = a; } diff --git a/tests/incremental/04-var-rename/04-renamed_param.patch b/tests/incremental/04-var-rename/04-renamed_param.patch index 50a9b69f6a..7753ded6df 100644 --- a/tests/incremental/04-var-rename/04-renamed_param.patch +++ b/tests/incremental/04-var-rename/04-renamed_param.patch @@ -1,6 +1,7 @@ --- tests/incremental/04-var-rename/04-renamed_param.c +++ tests/incremental/04-var-rename/04-renamed_param.c @@ -2,5 +2,5 @@ + // CRAM -void method(int a) { - int c = a; +void method(int b) { diff --git a/tests/incremental/04-var-rename/05-renamed_param_usage_changed.c b/tests/incremental/04-var-rename/05-renamed_param_usage_changed.c index aed642566c..1453e5707a 100644 --- a/tests/incremental/04-var-rename/05-renamed_param_usage_changed.c +++ b/tests/incremental/04-var-rename/05-renamed_param_usage_changed.c @@ -1,5 +1,5 @@ //This test should mark foo and main as changed - +// CRAM void foo(int a, int b) { int x = a; int y = b; diff --git a/tests/incremental/04-var-rename/05-renamed_param_usage_changed.patch b/tests/incremental/04-var-rename/05-renamed_param_usage_changed.patch index 9ffc2c1cea..7e46542911 100644 --- a/tests/incremental/04-var-rename/05-renamed_param_usage_changed.patch +++ b/tests/incremental/04-var-rename/05-renamed_param_usage_changed.patch @@ -2,7 +2,7 @@ +++ tests/incremental/04-var-rename/05-renamed_param_usage_changed.c @@ -1,6 +1,6 @@ //This test should mark foo and main as changed - + // CRAM -void foo(int a, int b) { +void foo(int b, int a) { int x = a; diff --git a/tests/incremental/05-method-rename/00-simple_rename.c b/tests/incremental/05-method-rename/00-simple_rename.c index 5d1e6fe872..0dd7b4ba1c 100644 --- a/tests/incremental/05-method-rename/00-simple_rename.c +++ b/tests/incremental/05-method-rename/00-simple_rename.c @@ -1,5 +1,5 @@ #include - +// CRAM void foo() { printf("foo"); } diff --git a/tests/incremental/05-method-rename/00-simple_rename.patch b/tests/incremental/05-method-rename/00-simple_rename.patch index ed7b40014c..31f0bf18cc 100644 --- a/tests/incremental/05-method-rename/00-simple_rename.patch +++ b/tests/incremental/05-method-rename/00-simple_rename.patch @@ -2,7 +2,7 @@ +++ tests/incremental/05-method-rename/00-simple_rename.c @@ -1,10 +1,10 @@ #include - + // CRAM -void foo() { +void bar() { printf("foo"); diff --git a/tests/incremental/05-method-rename/01-dependent_rename.c b/tests/incremental/05-method-rename/01-dependent_rename.c index 66c1a5a634..c5c43d5cde 100644 --- a/tests/incremental/05-method-rename/01-dependent_rename.c +++ b/tests/incremental/05-method-rename/01-dependent_rename.c @@ -1,5 +1,5 @@ #include - +// CRAM void fun1() { printf("fun1"); } diff --git a/tests/incremental/05-method-rename/01-dependent_rename.patch b/tests/incremental/05-method-rename/01-dependent_rename.patch index f3a4a9a3f8..3712f75059 100644 --- a/tests/incremental/05-method-rename/01-dependent_rename.patch +++ b/tests/incremental/05-method-rename/01-dependent_rename.patch @@ -2,7 +2,7 @@ +++ tests/incremental/05-method-rename/01-dependent_rename.c @@ -1,14 +1,14 @@ #include - + // CRAM -void fun1() { +void bar1() { printf("fun1"); diff --git a/tests/incremental/05-method-rename/02-cyclic_rename_dependency.c b/tests/incremental/05-method-rename/02-cyclic_rename_dependency.c index 331a5e25cb..41813818cb 100644 --- a/tests/incremental/05-method-rename/02-cyclic_rename_dependency.c +++ b/tests/incremental/05-method-rename/02-cyclic_rename_dependency.c @@ -1,5 +1,5 @@ #include - +// CRAM void foo1(int c) { if (c < 10) foo2(c + 1); } diff --git a/tests/incremental/05-method-rename/02-cyclic_rename_dependency.patch b/tests/incremental/05-method-rename/02-cyclic_rename_dependency.patch index 7f15d88c3a..3b62220898 100644 --- a/tests/incremental/05-method-rename/02-cyclic_rename_dependency.patch +++ b/tests/incremental/05-method-rename/02-cyclic_rename_dependency.patch @@ -1,7 +1,7 @@ --- tests/incremental/05-method-rename/02-cyclic_rename_dependency.c +++ tests/incremental/05-method-rename/02-cyclic_rename_dependency.c @@ -2,14 +2,14 @@ - + // CRAM -void foo1(int c) { - if (c < 10) foo2(c + 1); +void bar1(int c) { diff --git a/tests/incremental/05-method-rename/03-cyclic_with_swap.c b/tests/incremental/05-method-rename/03-cyclic_with_swap.c index 34026afa92..898f15fe6d 100644 --- a/tests/incremental/05-method-rename/03-cyclic_with_swap.c +++ b/tests/incremental/05-method-rename/03-cyclic_with_swap.c @@ -1,5 +1,5 @@ #include - +// CRAM void foo1(int c) { if (c < 10) foo2(c + 1); } diff --git a/tests/incremental/05-method-rename/03-cyclic_with_swap.patch b/tests/incremental/05-method-rename/03-cyclic_with_swap.patch index 0886106162..3373449875 100644 --- a/tests/incremental/05-method-rename/03-cyclic_with_swap.patch +++ b/tests/incremental/05-method-rename/03-cyclic_with_swap.patch @@ -1,7 +1,7 @@ --- tests/incremental/05-method-rename/03-cyclic_with_swap.c +++ tests/incremental/05-method-rename/03-cyclic_with_swap.c @@ -2,13 +2,17 @@ - + // CRAM -void foo1(int c) { - if (c < 10) foo2(c + 1); +void newFun(int c) { diff --git a/tests/incremental/05-method-rename/04-deep_change.c b/tests/incremental/05-method-rename/04-deep_change.c index 80037f934d..4258329f2e 100644 --- a/tests/incremental/05-method-rename/04-deep_change.c +++ b/tests/incremental/05-method-rename/04-deep_change.c @@ -1,5 +1,5 @@ #include - +// CRAM void zap() { printf("zap"); } diff --git a/tests/incremental/05-method-rename/04-deep_change.patch b/tests/incremental/05-method-rename/04-deep_change.patch index 687b8f74bc..6d7ec21bf8 100644 --- a/tests/incremental/05-method-rename/04-deep_change.patch +++ b/tests/incremental/05-method-rename/04-deep_change.patch @@ -2,7 +2,7 @@ +++ tests/incremental/05-method-rename/04-deep_change.c @@ -1,7 +1,7 @@ #include - + // CRAM void zap() { - printf("zap"); + printf("drap"); diff --git a/tests/incremental/05-method-rename/05-common_rename.c b/tests/incremental/05-method-rename/05-common_rename.c index ce72a6dda1..643bba554a 100644 --- a/tests/incremental/05-method-rename/05-common_rename.c +++ b/tests/incremental/05-method-rename/05-common_rename.c @@ -1,5 +1,5 @@ #include - +// CRAM void foo() { printf("foo"); } diff --git a/tests/incremental/05-method-rename/05-common_rename.patch b/tests/incremental/05-method-rename/05-common_rename.patch index 93904d5780..dcf6d15719 100644 --- a/tests/incremental/05-method-rename/05-common_rename.patch +++ b/tests/incremental/05-method-rename/05-common_rename.patch @@ -2,7 +2,7 @@ +++ tests/incremental/05-method-rename/05-common_rename.c @@ -1,20 +1,20 @@ #include - + // CRAM -void foo() { +void bar() { printf("foo"); diff --git a/tests/incremental/05-method-rename/06-recursive_rename.c b/tests/incremental/05-method-rename/06-recursive_rename.c index dc9ac72e94..3d1dd2b9d1 100644 --- a/tests/incremental/05-method-rename/06-recursive_rename.c +++ b/tests/incremental/05-method-rename/06-recursive_rename.c @@ -1,3 +1,4 @@ +// CRAM void foo(int x) { if(x > 1) foo(x - 1); } diff --git a/tests/incremental/05-method-rename/06-recursive_rename.patch b/tests/incremental/05-method-rename/06-recursive_rename.patch index 356f959256..e29be521be 100644 --- a/tests/incremental/05-method-rename/06-recursive_rename.patch +++ b/tests/incremental/05-method-rename/06-recursive_rename.patch @@ -1,6 +1,7 @@ --- tests/incremental/05-method-rename/06-recursive_rename.c +++ tests/incremental/05-method-rename/06-recursive_rename.c -@@ -1,7 +1,7 @@ +@@ -1,8 +1,8 @@ + // CRAM -void foo(int x) { - if(x > 1) foo(x - 1); +void bar(int x) { diff --git a/tests/incremental/06-glob-var-rename/00-simple_rename.c b/tests/incremental/06-glob-var-rename/00-simple_rename.c index 56650e98ed..c06ba3a85a 100644 --- a/tests/incremental/06-glob-var-rename/00-simple_rename.c +++ b/tests/incremental/06-glob-var-rename/00-simple_rename.c @@ -1,5 +1,5 @@ #include - +// CRAM int foo = 1; int main() { diff --git a/tests/incremental/06-glob-var-rename/00-simple_rename.patch b/tests/incremental/06-glob-var-rename/00-simple_rename.patch index 1e0f3b2565..b9d20af358 100644 --- a/tests/incremental/06-glob-var-rename/00-simple_rename.patch +++ b/tests/incremental/06-glob-var-rename/00-simple_rename.patch @@ -2,7 +2,7 @@ +++ tests/incremental/06-glob-var-rename/00-simple_rename.c @@ -1,9 +1,9 @@ #include - + // CRAM -int foo = 1; +int bar = 1; diff --git a/tests/incremental/06-glob-var-rename/01-duplicate_local_global.c b/tests/incremental/06-glob-var-rename/01-duplicate_local_global.c index 9ad715e50d..35e527225c 100644 --- a/tests/incremental/06-glob-var-rename/01-duplicate_local_global.c +++ b/tests/incremental/06-glob-var-rename/01-duplicate_local_global.c @@ -1,5 +1,5 @@ #include - +// CRAM int foo = 1; int main() { diff --git a/tests/incremental/06-glob-var-rename/01-duplicate_local_global.patch b/tests/incremental/06-glob-var-rename/01-duplicate_local_global.patch index 1d65c5672a..2c44da4cce 100644 --- a/tests/incremental/06-glob-var-rename/01-duplicate_local_global.patch +++ b/tests/incremental/06-glob-var-rename/01-duplicate_local_global.patch @@ -2,7 +2,7 @@ +++ tests/incremental/06-glob-var-rename/01-duplicate_local_global.c @@ -1,14 +1,14 @@ #include - + // CRAM -int foo = 1; +int bar = 1; diff --git a/tests/incremental/06-glob-var-rename/02-add_new_gvar.c b/tests/incremental/06-glob-var-rename/02-add_new_gvar.c index 5efe319981..c399e1f784 100644 --- a/tests/incremental/06-glob-var-rename/02-add_new_gvar.c +++ b/tests/incremental/06-glob-var-rename/02-add_new_gvar.c @@ -1,5 +1,5 @@ #include - +// CRAM int myVar = 1; int main() { diff --git a/tests/incremental/06-glob-var-rename/02-add_new_gvar.patch b/tests/incremental/06-glob-var-rename/02-add_new_gvar.patch index f0c145107a..0ca97da64f 100644 --- a/tests/incremental/06-glob-var-rename/02-add_new_gvar.patch +++ b/tests/incremental/06-glob-var-rename/02-add_new_gvar.patch @@ -2,7 +2,7 @@ +++ tests/incremental/06-glob-var-rename/02-add_new_gvar.c @@ -1,8 +1,9 @@ #include - + // CRAM int myVar = 1; +int foo = 1; diff --git a/tests/incremental/11-restart/00-justglob.c b/tests/incremental/11-restart/00-justglob.c index 61b059f8ea..1e35604d3f 100644 --- a/tests/incremental/11-restart/00-justglob.c +++ b/tests/incremental/11-restart/00-justglob.c @@ -1,2 +1,3 @@ int max_domains = 0; int main() {} +// CRAM From 205f058e3dea0aaf17953aef4fd9de5d75aa7a3a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 18:59:56 +0300 Subject: [PATCH 429/689] Error on missing automatic checks in regression tests --- scripts/update_suite.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index 0e90bbf828..e760cdd721 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -379,6 +379,7 @@ def parse_tests (lines) end if tests.empty? then puts "No automatic checks in #{@id} (maybe NOCRASH/FIXPOINT/NOTIMEOUT/CRAM?)" + exit 1 end Tests.new(self, tests, tests_line, todo) end From 8da70467421f2ecb0f0712848da93743a8d6e67a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Jul 2024 19:06:07 +0300 Subject: [PATCH 430/689] Document meta annotations for regression tests --- docs/developer-guide/testing.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/developer-guide/testing.md b/docs/developer-guide/testing.md index 22b0070fa4..a336228fde 100644 --- a/docs/developer-guide/testing.md +++ b/docs/developer-guide/testing.md @@ -69,6 +69,16 @@ Other useful constructs are the following: | `__goblint_check(1); // reachable` | Checks that the line is reachable according
to Goblint results (soundness). | | `__goblint_check(0); // NOWARN (unreachable)` | Checks that the line is unreachable (precision). | +#### Meta +Comments at the end of lines can also indicate metaproperties: + +| Annotation | Expected result/comment | +| ---------- | ----- | +| `NOCRASH` | No analyzer crash | +| `FIXPOINT` | No fixpoint error | +| `NOTIMEOUT` | Analyer terminates | +| `CRAM` | Automatic checks are only in corresponding Cram test | + ## Cram Tests [Cram-style tests](https://dune.readthedocs.io/en/stable/tests.html#cram-tests) are also used to verify that existing functionality hasn't been broken. They check the complete standard output of running the Goblint binary with specified command-line arguments. From 14d51d51fe952f6edad9871350f71cfccaea710d Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 12 Jul 2024 16:58:31 +0200 Subject: [PATCH 431/689] Check overflows when generating witnesses --- src/cdomains/apron/sharedFunctions.apron.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 4809e97917..a9406d48e9 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -274,7 +274,7 @@ struct let expr = ref (fst @@ coeff_to_const false (Linexpr1.get_cst linexpr1)) in let append_summand (c:Coeff.union_5) v = match V.to_cil_varinfo v with - | Some vinfo -> + | Some vinfo when IntDomain.Size.is_cast_injective ~from_type:vinfo.vtype ~to_type:(TInt(ILongLong,[])) -> (* TODO: What to do with variables that have a type that cannot be stored into ILongLong to avoid overflows? *) let var = Cilfacade.mkCast ~e:(Lval(Var vinfo,NoOffset)) ~newt:longlong in let coeff, flip = coeff_to_const true c in @@ -284,6 +284,7 @@ struct else expr := BinOp(PlusA,!expr,prod,longlong) | None -> M.warn ~category:Analyzer "Invariant Apron: cannot convert to cil var: %s" (Var.to_string v); raise Unsupported_Linexpr1 + | _ -> M.warn ~category:Analyzer "Invariant Apron: cannot convert to cil var in overflow preserving manner: %s" (Var.to_string v); raise Unsupported_Linexpr1 in Linexpr1.iter append_summand linexpr1; !expr From 726725b88015547e9aeab38232fe130ab113993f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 17 Jul 2024 11:15:45 +0300 Subject: [PATCH 432/689] Add Printable functions to GobApron.Var --- src/analyses/apron/relationAnalysis.apron.ml | 4 +-- .../apron/affineEqualityDomain.apron.ml | 10 +++--- src/cdomains/apron/gobApron.apron.ml | 9 ++++++ .../apron/linearTwoVarEqualityDomain.apron.ml | 32 +++++++++---------- src/cdomains/apron/sharedFunctions.apron.ml | 4 +-- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index a42d78d71a..6dd2a65cee 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -295,7 +295,7 @@ struct (* there should be smarter ways to do this, e.g. by keeping track of which values are written etc. ... *) (* See, e.g, Beckschulze E, Kowalewski S, Brauer J (2012) Access-based localization for octagons. Electron Notes Theor Comput Sci 287:29–40 *) (* Also, a local *) - let vname = Apron.Var.to_string var in + let vname = GobApron.Var.show var in let locals = fundec.sformals @ fundec.slocals in match List.find_opt (fun v -> VM.var_name (Local v) = vname) locals with (* TODO: optimize *) | None -> true @@ -418,7 +418,7 @@ struct in let any_local_reachable = any_local_reachable fundec reachable_from_args in let arg_vars = f.sformals |> List.filter (RD.Tracked.varinfo_tracked) |> List.map RV.arg in - if M.tracing then M.tracel "combine-rel" "relation remove vars: %a" (docList (fun v -> Pretty.text (Apron.Var.to_string v))) arg_vars; + if M.tracing then M.tracel "combine-rel" "relation remove vars: %a" (docList (GobApron.Var.pretty ())) arg_vars; RD.remove_vars_with new_fun_rel arg_vars; (* fine to remove arg vars that also exist in caller because unify from new_rel adds them back with proper constraints *) let tainted = f_ask.f Queries.MayBeTainted in let tainted_vars = TaintPartialContexts.conv_varset tainted in diff --git a/src/cdomains/apron/affineEqualityDomain.apron.ml b/src/cdomains/apron/affineEqualityDomain.apron.ml index 8bb99f2264..ec0bb9b940 100644 --- a/src/cdomains/apron/affineEqualityDomain.apron.ml +++ b/src/cdomains/apron/affineEqualityDomain.apron.ml @@ -181,7 +181,7 @@ struct else if Z.lt coeff Z.minus_one then Z.to_string coeff else Format.asprintf "+%s" (Z.to_string coeff) in - coeff_str ^ Var.to_string var + coeff_str ^ Var.show var in let const_to_str vl = if Z.equal vl Z.zero then @@ -429,8 +429,8 @@ struct let assign_exp ask t var exp no_ov = let res = assign_exp ask t var exp no_ov in - if M.tracing then M.tracel "ops" "assign_exp t:\n %s \n var: %s \n exp: %a\n no_ov: %b -> \n %s" - (show t) (Var.to_string var) d_exp exp (Lazy.force no_ov) (show res) ; + if M.tracing then M.tracel "ops" "assign_exp t:\n %s \n var: %a \n exp: %a\n no_ov: %b -> \n %s" + (show t) Var.pretty var d_exp exp (Lazy.force no_ov) (show res); res let assign_var (t: VarManagement(Vc)(Mx).t) v v' = @@ -440,7 +440,7 @@ struct let assign_var t v v' = let res = assign_var t v v' in - if M.tracing then M.tracel "ops" "assign_var t:\n %s \n v: %s \n v': %s\n -> %s" (show t) (Var.to_string v) (Var.to_string v') (show res) ; + if M.tracing then M.tracel "ops" "assign_var t:\n %s \n v: %a \n v': %a\n -> %s" (show t) Var.pretty v Var.pretty v' (show res); res let assign_var_parallel t vv's = @@ -498,7 +498,7 @@ struct let substitute_exp ask t var exp no_ov = let res = substitute_exp ask t var exp no_ov in - if M.tracing then M.tracel "ops" "Substitute_expr t: \n %s \n var: %s \n exp: %a \n -> \n %s" (show t) (Var.to_string var) d_exp exp (show res); + if M.tracing then M.tracel "ops" "Substitute_expr t: \n %s \n var: %a \n exp: %a \n -> \n %s" (show t) Var.pretty var d_exp exp (show res); res let substitute_exp ask t var exp no_ov = timing_wrap "substitution" (substitute_exp ask t var exp) no_ov diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index f2322c1473..fca28ff8f0 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -11,6 +11,15 @@ end module Var = struct include Var + + let pp = print + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) + let equal x y = Var.compare x y = 0 end diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index bd6b81402a..c13aca60ea 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -158,7 +158,7 @@ module EqualitiesConjunction = struct let (newref,offs,divi) = (get_rhs d head) in let (coeff,y) = BatOption.get newref in let (y,yrhs) = inverse head (coeff,y,offs,divi) in (* reassemble yrhs out of components *) - let shifted_cluster = (List.fold (fun map i -> + let shifted_cluster = (List.fold (fun map i -> let irhs = (get_rhs d i) in (* old entry is i = irhs *) Rhs.subst yrhs y irhs |> (* new entry for i is irhs [yrhs/y] *) set_rhs map i @@ -222,7 +222,7 @@ module EqualitiesConjunction = struct | Some (coeff,j), ((Some (coeff1,h1), o1, divi1) as oldi)-> (match get_rhs ts j with (* ts[x_j]=o2/d2 ========> ... *) - | (None , o2, divi2) -> + | (None , o2, divi2) -> let newxi = Rhs.subst (None,o2,divi2) j (Some (coeff,j),offs,divi) in let newxh1 = snd @@ inverse i (coeff1,h1,o1,divi1) in let newxh1 = Rhs.subst newxi i newxh1 in @@ -251,7 +251,7 @@ module EqualitiesConjunction = struct else (* var_i = var_i, i.e. it may occur on the rhs of other equalities *) (* so now, we transform with the inverse of the transformer: *) let inv = snd (inverse i (coeff,j,offs,divi)) in - IntMap.fold (fun k v acc -> + IntMap.fold (fun k v acc -> match v with | (Some (c,x),o,d) when x=i-> set_rhs acc k (Rhs.subst inv i v) | _ -> acc @@ -281,7 +281,7 @@ struct let multiply a b = (* if one of them is a constant, then multiply. Otherwise, the expression is not linear *) match a, b with - | [(None,coeff, divi)], c + | [(None,coeff, divi)], c | c, [(None,coeff, divi)] -> multiply_with_Q coeff divi c | _ -> raise NotLinearExpr in @@ -314,7 +314,7 @@ struct | x -> Some(x) (** convert and simplify (wrt. reference variables) a texpr into a tuple of a list of monomials (coeff,varidx,divi) and a (constant/divi) *) - let simplified_monomials_from_texp (t: t) texp = + let simplified_monomials_from_texp (t: t) texp = BatOption.bind (monomials_from_texp t texp) (fun monomiallist -> let d = Option.get t.d in @@ -323,7 +323,7 @@ struct | None -> let gcdee = Z.gcd adiv divi in exprcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi) | Some (coeff,idx) -> let (somevar,someoffs,somedivi)=Rhs.subst (EConj.get_rhs d idx) idx (v,offs,divi) in (* normalize! *) let newcache = Option.map_default (fun (coef,ter) -> IMap.add ter Q.((IMap.find_default zero ter exprcache) + make coef somedivi) exprcache) exprcache somevar in - let gcdee = Z.gcd adiv divi in + let gcdee = Z.gcd adiv divi in (newcache,(Z.(aconst*divi/gcdee + offs*adiv/gcdee),Z.lcm adiv divi)) in let (expr,constant) = List.fold_left accumulate_constants (IMap.empty,(Z.zero,Z.one)) monomiallist in (* abstract simplification of the guard wrt. reference variables *) @@ -339,7 +339,7 @@ struct BatOption.bind (simplified_monomials_from_texp t texp ) (fun (sum_of_terms, (constant,divisor)) -> (match sum_of_terms with - | [] -> Some (None, constant,divisor) + | [] -> Some (None, constant,divisor) | [(coeff,var,divi)] -> Some (Rhs.canonicalize (Some (Z.mul divisor coeff,var), Z.mul constant divi,Z.mul divisor divi)) |_ -> None)) @@ -447,7 +447,7 @@ struct let t1 = change_d t1 sup_env ~add:true ~del:false in let t2 = change_d t2 sup_env ~add:true ~del:false in match t1.d, t2.d with - | Some d1', Some d2' -> + | Some d1', Some d2' -> EConj.IntMap.fold (fun lhs rhs map -> meet_with_one_conj map lhs rhs) (snd d2') t1 (* even on sparse d2, this will chose the relevant conjs to meet with*) | _ -> {d = None; env = sup_env} @@ -489,7 +489,7 @@ struct - lhs itself - criteria A and B that characterize equivalence class, depending on the reference variable and the affine expression parameters wrt. each EConj - rhs1 - - rhs2 + - rhs2 however, we have to account for the sparseity of EConj maps by manually patching holes with default values *) let joinfunction lhs rhs1 rhs2 = ( @@ -516,15 +516,15 @@ struct let varentry ci offi ch offh xh = let (coeff,off,d) = Q.(ci,(offi*ch)-(ci*offh),ch) in (* compute new rhs in Q *) let (coeff,off,d) = Z.(coeff.num*d.den*off.den,off.num*d.den*coeff.den,d. num*coeff.den*off.den) in (* convert that back into Z *) - Rhs.canonicalize (Some(coeff,xh),off,d) + Rhs.canonicalize (Some(coeff,xh),off,d) in (* ci1 = a*ch1+b /\ ci2 = a*ch2+b *) (* ===> a = (ci1-ci2)/(ch1-ch2) b = ci2-a*ch2 *) - let constentry ci1 ci2 ch1 ch2 xh = + let constentry ci1 ci2 ch1 ch2 xh = let a = Q.((ci1-ci2) / (ch1-ch2)) in let b = Q.(ci2 - a*ch2) in Rhs.canonicalize (Some (Z.(a.num*b.den),xh),Z.(b.num*a.den) ,Z.(a.den*b.den) ) in - let iterate map l = + let iterate map l = match l with | (_, _, _, rhs , rhs' ) :: t when Rhs.equal rhs rhs' -> List.fold (fun acc (x,_,_,rh,_) -> EConj.set_rhs acc x rh) map l | (h, _, _, ((Some (ch,_),oh,dh)), ((Some _,_,_) )) :: t -> List.fold (fun acc (i,_,_,(monom,oi,di),_) -> EConj.set_rhs acc i (varentry Q.(make (fst@@Option.get monom) di) Q.(make oi di) Q.(make ch dh) Q.(make oh dh) h)) map t @@ -630,8 +630,8 @@ struct let assign_exp ask t var exp no_ov = let res = assign_exp ask t var exp no_ov in - if M.tracing then M.tracel "ops" "assign_exp t:\n %s \n var: %s \n exp: %a\n no_ov: %b -> \n %s" - (show t) (Var.to_string var) d_exp exp (Lazy.force no_ov) (show res) ; + if M.tracing then M.tracel "ops" "assign_exp t:\n %s \n var: %a \n exp: %a\n no_ov: %b -> \n %s" + (show t) Var.pretty var d_exp exp (Lazy.force no_ov) (show res); res let assign_var (t: VarManagement.t) v v' = @@ -640,7 +640,7 @@ struct let assign_var t v v' = let res = assign_var t v v' in - if M.tracing then M.tracel "ops" "assign_var t:\n %s \n v: %s \n v': %s\n -> %s" (show t) (Var.to_string v) (Var.to_string v') (show res) ; + if M.tracing then M.tracel "ops" "assign_var t:\n %s \n v: %a \n v': %a\n -> %s" (show t) Var.pretty v Var.pretty v' (show res); res (** Parallel assignment of variables. @@ -693,7 +693,7 @@ struct let substitute_exp ask t var exp no_ov = let res = substitute_exp ask t var exp no_ov in - if M.tracing then M.tracel "ops" "Substitute_expr t: \n %s \n var: %s \n exp: %a \n -> \n %s" (show t) (Var.to_string var) d_exp exp (show res); + if M.tracing then M.tracel "ops" "Substitute_expr t: \n %s \n var: %a \n exp: %a \n -> \n %s" (show t) Var.pretty var d_exp exp (show res); res let substitute_exp ask t var exp no_ov = timing_wrap "substitution" (substitute_exp ask t var exp) no_ov diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 9627b4762a..1e0a223571 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -136,7 +136,7 @@ struct let expr = (** simplify asks for a constant value of some subexpression e, similar to a constant fold. In particular but not exclusively this query is answered by the 2 var equalities domain itself. This normalizes arbitrary expressions to a point where they - might be able to be represented by means of 2 var equalities + might be able to be represented by means of 2 var equalities This simplification happens during a time, when there are temporary variables a#in and a#out part of the expression, but are not represented in the ctx, thus queries may result in top for these variables. Wrapping this in speculative @@ -279,7 +279,7 @@ struct expr := BinOp(MinusA,!expr,prod,longlong) else expr := BinOp(PlusA,!expr,prod,longlong) - | None -> M.warn ~category:Analyzer "Invariant Apron: cannot convert to cil var: %s" (Var.to_string v); raise Unsupported_Linexpr1 + | None -> M.warn ~category:Analyzer "Invariant Apron: cannot convert to cil var: %a" Var.pretty v; raise Unsupported_Linexpr1 in Linexpr1.iter append_summand linexpr1; !expr From b735727192db12f77c2778fd2d21d2d1c431e3ce Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 17 Jul 2024 11:24:22 +0300 Subject: [PATCH 433/689] Add Printable functions to GobApron.Scalar --- src/cdomains/apron/gobApron.apron.ml | 13 +++++++++++++ src/cdomains/apron/sharedFunctions.apron.ml | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index fca28ff8f0..80d32f1821 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -1,6 +1,19 @@ open Batteries include Apron +module Scalar = +struct + include Scalar + + let pp = print + include Printable.SimpleFormat ( + struct + type nonrec t = t + let pp = pp + end + ) +end + module Coeff = struct include Coeff diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 1e0a223571..dc918be571 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -36,7 +36,7 @@ let int_of_scalar ?round (scalar: Scalar.t) = in Z_mlgmpidl.z_of_mpzf z | _ -> - failwith ("int_of_scalar: unsupported: " ^ Scalar.to_string scalar) + failwith ("int_of_scalar: unsupported: " ^ Scalar.show scalar) module type ConvertArg = @@ -263,7 +263,7 @@ struct else Const (CInt(i,ILongLong,None)), false else - (M.warn ~category:Analyzer "Invariant Apron: coefficient is not int: %s" (Scalar.to_string c); raise Unsupported_Linexpr1) + (M.warn ~category:Analyzer "Invariant Apron: coefficient is not int: %a" Scalar.pretty c; raise Unsupported_Linexpr1) | None -> raise Unsupported_Linexpr1) | _ -> raise Unsupported_Linexpr1 in From 8f0ebc506662946192a96faf75e97af9fdeabf70 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 17 Jul 2024 11:24:43 +0300 Subject: [PATCH 434/689] Use GobZ.pretty in lin2var tracing --- src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index c13aca60ea..65775d9188 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -361,7 +361,7 @@ struct else match simplify_to_ref_and_offset t (Texpr1.to_expr texpr) with | Some (None, offset, divisor) when Z.equal (Z.rem offset divisor) Z.zero -> let res = Z.div offset divisor in - (if M.tracing then M.tracel "bounds" "min: %s max: %s" (IntOps.BigIntOps.to_string res) (IntOps.BigIntOps.to_string res); + (if M.tracing then M.tracel "bounds" "min: %a max: %a" GobZ.pretty res GobZ.pretty res; Some res, Some res) | _ -> None, None From 06ea5e050df7d03692912bbfc3022a068cf411f4 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Wed, 17 Jul 2024 13:24:46 +0200 Subject: [PATCH 435/689] Rm resolved TODO --- src/cdomains/apron/sharedFunctions.apron.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index a9406d48e9..8121635e89 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -275,7 +275,6 @@ struct let append_summand (c:Coeff.union_5) v = match V.to_cil_varinfo v with | Some vinfo when IntDomain.Size.is_cast_injective ~from_type:vinfo.vtype ~to_type:(TInt(ILongLong,[])) -> - (* TODO: What to do with variables that have a type that cannot be stored into ILongLong to avoid overflows? *) let var = Cilfacade.mkCast ~e:(Lval(Var vinfo,NoOffset)) ~newt:longlong in let coeff, flip = coeff_to_const true c in let prod = BinOp(Mult, coeff, var, longlong) in @@ -291,7 +290,7 @@ struct let lcm_den linexpr1 = - let exception UnsupportedScalar + let exception UnsupportedScalar in let frac_of_scalar scalar = if Scalar.is_infty scalar <> 0 then (* infinity means unbounded *) From 0f99b6652ada5e5c3863e80dcb6c8d746bcd4f3f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Jul 2024 20:06:08 +0300 Subject: [PATCH 436/689] Vendor ppx_easy_deriving --- dune-project | 2 +- goblint.opam | 3 +- goblint.opam.locked | 6 - goblint.opam.template | 1 - src/ppx/lattice/dune | 1 - src/ppx/printable/dune | 1 - src/vendor/ppx_easy_deriving/README.md | 4 + src/vendor/ppx_easy_deriving/deriver.ml | 100 ++++++++ src/vendor/ppx_easy_deriving/deriver.mli | 3 + src/vendor/ppx_easy_deriving/deriver_intf.ml | 13 + src/vendor/ppx_easy_deriving/dune | 4 + src/vendor/ppx_easy_deriving/intf.ml | 64 +++++ src/vendor/ppx_easy_deriving/pat_exp.ml | 46 ++++ src/vendor/ppx_easy_deriving/pat_exp.mli | 16 ++ .../ppx_easy_deriving/ppx_easy_deriving.ml | 15 ++ src/vendor/ppx_easy_deriving/product.ml | 226 ++++++++++++++++++ src/vendor/ppx_easy_deriving/product.mli | 3 + src/vendor/ppx_easy_deriving/product_intf.ml | 132 ++++++++++ src/vendor/ppx_easy_deriving/util.ml | 12 + src/vendor/ppx_easy_deriving/util.mli | 8 + 20 files changed, 648 insertions(+), 12 deletions(-) create mode 100644 src/vendor/ppx_easy_deriving/README.md create mode 100644 src/vendor/ppx_easy_deriving/deriver.ml create mode 100644 src/vendor/ppx_easy_deriving/deriver.mli create mode 100644 src/vendor/ppx_easy_deriving/deriver_intf.ml create mode 100644 src/vendor/ppx_easy_deriving/dune create mode 100644 src/vendor/ppx_easy_deriving/intf.ml create mode 100644 src/vendor/ppx_easy_deriving/pat_exp.ml create mode 100644 src/vendor/ppx_easy_deriving/pat_exp.mli create mode 100644 src/vendor/ppx_easy_deriving/ppx_easy_deriving.ml create mode 100644 src/vendor/ppx_easy_deriving/product.ml create mode 100644 src/vendor/ppx_easy_deriving/product.mli create mode 100644 src/vendor/ppx_easy_deriving/product_intf.ml create mode 100644 src/vendor/ppx_easy_deriving/util.ml create mode 100644 src/vendor/ppx_easy_deriving/util.mli diff --git a/dune-project b/dune-project index 9071eb989f..97a06a220a 100644 --- a/dune-project +++ b/dune-project @@ -45,7 +45,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e (ppx_deriving (>= 6.0.2)) (ppx_deriving_hash (>= 0.1.2)) (ppx_deriving_yojson (>= 3.7.0)) - ppx_easy_deriving + (ppxlib (>= 0.30.0)) ; ppx_easy_deriving (ounit2 :with-test) (qcheck-ounit :with-test) (odoc :with-doc) diff --git a/goblint.opam b/goblint.opam index c0b0b52960..78a8fb76e7 100644 --- a/goblint.opam +++ b/goblint.opam @@ -45,7 +45,7 @@ depends: [ "ppx_deriving" {>= "6.0.2"} "ppx_deriving_hash" {>= "0.1.2"} "ppx_deriving_yojson" {>= "3.7.0"} - "ppx_easy_deriving" + "ppxlib" {>= "0.30.0"} "ounit2" {with-test} "qcheck-ounit" {with-test} "odoc" {with-doc} @@ -98,7 +98,6 @@ available: os-distribution != "alpine" & arch != "arm64" pin-depends: [ # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] - [ "ppx_easy_deriving.~dev" "git+https://github.com/sim642/ppx_easy_deriving.git#3d599fdfb231e4a1f9bad0e914068210901533a4" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index b9540fa629..37f22c3230 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -58,7 +58,6 @@ depends: [ "dune-private-libs" {= "3.7.1"} "dune-site" {= "3.7.1"} "dyn" {= "3.7.1"} - "either" {= "1.0.0"} "fileutils" {= "0.6.4"} "fmt" {= "0.9.0"} "fpath" {= "0.7.3"} @@ -86,7 +85,6 @@ depends: [ "ppx_deriving" {= "6.0.2"} "ppx_deriving_hash" {= "0.1.2"} "ppx_deriving_yojson" {= "3.7.0"} - "ppx_easy_deriving" {= "~dev"} "ppxlib" {= "0.32.1"} "qcheck-core" {= "0.20"} "qcheck-ounit" {= "0.20" & with-test} @@ -139,10 +137,6 @@ pin-depends: [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] - [ - "ppx_easy_deriving.~dev" - "git+https://github.com/sim642/ppx_easy_deriving.git#3d599fdfb231e4a1f9bad0e914068210901533a4" - ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} description: """\ diff --git a/goblint.opam.template b/goblint.opam.template index e9b53c42b4..a730d5c064 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -4,7 +4,6 @@ available: os-distribution != "alpine" & arch != "arm64" pin-depends: [ # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] - [ "ppx_easy_deriving.~dev" "git+https://github.com/sim642/ppx_easy_deriving.git#3d599fdfb231e4a1f9bad0e914068210901533a4" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/src/ppx/lattice/dune b/src/ppx/lattice/dune index 4c057c6fab..1f4dac4b82 100644 --- a/src/ppx/lattice/dune +++ b/src/ppx/lattice/dune @@ -4,5 +4,4 @@ (name ppx_deriving_lattice) (kind ppx_deriver) (libraries ppxlib ppx_easy_deriving) - (ppx_runtime_libraries ppx_easy_deriving.runtime) (preprocess (pps ppxlib.metaquot))) diff --git a/src/ppx/printable/dune b/src/ppx/printable/dune index 2b620d2319..9164e487e0 100644 --- a/src/ppx/printable/dune +++ b/src/ppx/printable/dune @@ -4,5 +4,4 @@ (name ppx_deriving_printable) (kind ppx_deriver) (libraries ppxlib ppx_easy_deriving) - (ppx_runtime_libraries ppx_easy_deriving.runtime) (preprocess (pps ppxlib.metaquot))) diff --git a/src/vendor/ppx_easy_deriving/README.md b/src/vendor/ppx_easy_deriving/README.md new file mode 100644 index 0000000000..99a5e7e140 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/README.md @@ -0,0 +1,4 @@ +# ppx_easy_deriving + +Goblint vendors a subset of the unreleased [ppx_easy_deriving](https://github.com/sim642/ppx_easy_deriving) library. +It only includes products, excluding simples and variants. diff --git a/src/vendor/ppx_easy_deriving/deriver.ml b/src/vendor/ppx_easy_deriving/deriver.ml new file mode 100644 index 0000000000..533a77959c --- /dev/null +++ b/src/vendor/ppx_easy_deriving/deriver.ml @@ -0,0 +1,100 @@ +open Ppxlib +open Ast_builder.Default + +include Deriver_intf + +module Make (Arg: Intf.S): S = +struct + let attr = Attribute.declare (Printf.sprintf "deriving.%s.%s" Arg.name Arg.name) Attribute.Context.core_type Ast_pattern.(single_expr_payload __) (fun expr -> expr) + + let unit ~loc = Arg.tuple ~loc [] + + let rec expr ~loc ~quoter ct = + match Attribute.get attr ct with + | Some expr -> + Expansion_helpers.Quoter.quote quoter expr + | None -> + match ct with + | [%type: unit] -> + unit ~loc + | {ptyp_desc = Ptyp_constr ({txt = lid; loc}, args); _} -> + let ident = pexp_ident ~loc {loc; txt = Expansion_helpers.mangle_lid (Prefix Arg.name) lid} in + let ident = Expansion_helpers.Quoter.quote quoter ident in + let apply_args = List.map (fun ct -> + (Nolabel, expr ~loc ~quoter ct) + ) args + in + pexp_apply ~loc ident apply_args + | {ptyp_desc = Ptyp_tuple elems; _} -> + expr_tuple ~loc ~quoter elems + | {ptyp_desc = Ptyp_var name; _} -> + evar ~loc ("poly_" ^ name) + | _ -> + pexp_extension ~loc (Location.error_extensionf ~loc "unsupported core type") + + and expr_record ~loc ~quoter (lds: label_declaration list) = + let les = List.map (fun {pld_name = {txt = label; _}; pld_type; _} -> + (Lident label, expr ~loc ~quoter pld_type) + ) lds + in + Arg.record ~loc les + + and expr_tuple ~loc ~quoter elems = + let es = List.map (expr ~loc ~quoter) elems in + Arg.tuple ~loc es + + let expr_declaration ~loc ~quoter = function + | {ptype_kind = Ptype_abstract; ptype_manifest = Some ct; _} -> + expr ~loc ~quoter ct + | {ptype_kind = Ptype_abstract; _} -> + pexp_extension ~loc (Location.error_extensionf ~loc "unsupported abstract type") + | {ptype_kind = Ptype_variant constrs; _} -> + pexp_extension ~loc (Location.error_extensionf ~loc "unsupported variant type") + | {ptype_kind = Ptype_open; _} -> + pexp_extension ~loc (Location.error_extensionf ~loc "unsupported open type") + | {ptype_kind = Ptype_record fields; _} -> + expr_record ~loc ~quoter fields + + let typ ~loc td = + let ct = Ppx_deriving.core_type_of_type_decl td in + Ppx_deriving.poly_arrow_of_type_decl + (Arg.typ ~loc) + td + (Arg.typ ~loc ct) + + let generate_impl ~ctxt (_rec_flag, type_declarations) = + let loc = Expansion_context.Deriver.derived_item_loc ctxt in + let vbs = List.map (fun td -> + let quoter = Expansion_helpers.Quoter.create () in + let expr = expr_declaration ~loc ~quoter td in + let expr = Expansion_helpers.Quoter.sanitize quoter expr in + let expr = Ppx_deriving.poly_fun_of_type_decl td expr in + let ct = typ ~loc td in + let pat = ppat_var ~loc {loc; txt = Expansion_helpers.mangle_type_decl (Prefix Arg.name) td} in + let pat = ppat_constraint ~loc pat ct in + Ast_helper.Vb.mk ~loc ~attrs:[Ppx_deriving.attr_warning [%expr "-39"]] pat expr + ) type_declarations + in + [Ast_helper.Str.value ~loc Recursive vbs] + + let generate_intf ~ctxt (_rec_flag, type_declarations) = + let loc = Expansion_context.Deriver.derived_item_loc ctxt in + List.map (fun td -> + let ct = typ ~loc td in + let val_ = Ast_helper.Val.mk ~loc {loc; txt = Expansion_helpers.mangle_type_decl (Prefix Arg.name) td} ct in + Ast_helper.Sig.value ~loc val_ + ) type_declarations + + let impl_generator = Deriving.Generator.V2.make_noarg generate_impl + let intf_generator = Deriving.Generator.V2.make_noarg generate_intf + let extension ~loc ~path:_ ct = + let quoter = Expansion_helpers.Quoter.create () in + let expr = expr ~loc ~quoter ct in + Expansion_helpers.Quoter.sanitize quoter expr + + let register () = + Deriving.add Arg.name + ~sig_type_decl:intf_generator + ~str_type_decl:impl_generator + ~extension +end diff --git a/src/vendor/ppx_easy_deriving/deriver.mli b/src/vendor/ppx_easy_deriving/deriver.mli new file mode 100644 index 0000000000..a8238f6f6f --- /dev/null +++ b/src/vendor/ppx_easy_deriving/deriver.mli @@ -0,0 +1,3 @@ +(** Registerable deriver. *) + +include Deriver_intf.Deriver (** @inline *) diff --git a/src/vendor/ppx_easy_deriving/deriver_intf.ml b/src/vendor/ppx_easy_deriving/deriver_intf.ml new file mode 100644 index 0000000000..565a6aef38 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/deriver_intf.ml @@ -0,0 +1,13 @@ +module type S = +sig + val register: unit -> Ppxlib.Deriving.t + (** Register deriver with ppxlb. *) +end + +module type Deriver = +sig + module type S = S + + module Make (_: Intf.S): S + (** Make registerable deriver. *) +end diff --git a/src/vendor/ppx_easy_deriving/dune b/src/vendor/ppx_easy_deriving/dune new file mode 100644 index 0000000000..7d50a56e43 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/dune @@ -0,0 +1,4 @@ +(library + (name ppx_easy_deriving) + (libraries ppxlib ppx_deriving.api) + (preprocess (pps ppxlib.metaquot))) diff --git a/src/vendor/ppx_easy_deriving/intf.ml b/src/vendor/ppx_easy_deriving/intf.ml new file mode 100644 index 0000000000..b30c7c36a0 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/intf.ml @@ -0,0 +1,64 @@ +(** Main interfaces. *) + +open Ppxlib + +(** Deriver name interface. *) +module type Name = +sig + val name: string + (** Deriver name. + + For example, with the name "equal": + + Use [[@@deriving equal]] after a type definition. + + The derived value/function is [val equal: ...] (if the type is named [t]) or [val equal_ty: ...] (otherwise if the type is named [ty]). + + Use [[@equal ...]] after a type expression to override the underlying value/function used for it. + + Use [[%equal: ty]] as an expression for the value/function of type [ty]. *) +end + +(** Deriver base interface. *) +module type Base = +sig + include Name + val typ: loc:location -> core_type -> core_type + (** Derived value/function type for a given type. + + For example, "equal" deriver would map [t] to [t -> t -> bool]. *) +end + +module Tuple = +struct + + (** Tuple deriver interface. *) + module type S = + sig + include Base + val tuple: loc:location -> expression list -> expression + (** Compose derived values/functions for tuple elements into derived value/function for the tuple. *) + end +end + +module Record = +struct + + (** Record deriver interface. *) + module type S = + sig + include Base + val record: loc:location -> (longident * expression) list -> expression + (** Compose derived values/functions for record fields into derived value/function for the record. *) + end +end + +module Full = +struct + + (** Full deriver interface. *) + module type S = + sig + include Tuple.S + include Record.S + end +end + +module type S = Full.S +(** Deriver interface. *) diff --git a/src/vendor/ppx_easy_deriving/pat_exp.ml b/src/vendor/ppx_easy_deriving/pat_exp.ml new file mode 100644 index 0000000000..a9d43d07e6 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/pat_exp.ml @@ -0,0 +1,46 @@ +open Ppxlib +open Ast_builder.Default + +type t = + | Record of (longident * t) list + | Tuple of t list + | Unit + | Base of string +let create_record ~prefix ls = + Record (List.mapi (fun i l -> (l, Base (prefix ^ string_of_int (i + 1)))) ls) +let create_tuple ~prefix n = + match n with + | 0 -> Unit + | 1 -> Base (prefix ^ "1") + | n -> Tuple (List.init n (fun i -> Base (prefix ^ string_of_int (i + 1)))) +let rec to_pat ~loc = function + | Record xs -> + ppat_record ~loc (List.map (fun (l, x) -> + (Located.mk ~loc l, to_pat ~loc x) + ) xs) Closed + | Tuple xs -> + ppat_tuple ~loc (List.map (to_pat ~loc) xs) + | Unit -> + [%pat? ()] + | Base s -> + ppat_var ~loc (Located.mk ~loc s) +let rec to_exps ~loc = function + | Record xs -> + List.flatten (List.map (fun (_, x) -> to_exps ~loc x) xs) + | Tuple xs -> + List.flatten (List.map (to_exps ~loc) xs) + | Unit -> + [] + | Base s -> + [pexp_ident ~loc {loc; txt = Lident s}] +let rec to_exp ~loc = function + | Record xs -> + pexp_record ~loc (List.map (fun (l, x) -> + (Located.mk ~loc l, to_exp ~loc x) + ) xs) None + | Tuple xs -> + pexp_tuple ~loc (List.map (to_exp ~loc) xs) + | Unit -> + [%expr ()] + | Base s -> + pexp_ident ~loc {loc; txt = Lident s} diff --git a/src/vendor/ppx_easy_deriving/pat_exp.mli b/src/vendor/ppx_easy_deriving/pat_exp.mli new file mode 100644 index 0000000000..a4878afa81 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/pat_exp.mli @@ -0,0 +1,16 @@ +(** Common representation of patterns and expressions. *) + +open Ppxlib + +type t = + | Record of (longident * t) list + | Tuple of t list + | Unit + | Base of string + +val create_record: prefix:string -> longident list -> t +val create_tuple: prefix:string -> int -> t + +val to_pat: loc:location -> t -> pattern +val to_exps: loc:location -> t -> expression list +val to_exp: loc:location -> t -> expression diff --git a/src/vendor/ppx_easy_deriving/ppx_easy_deriving.ml b/src/vendor/ppx_easy_deriving/ppx_easy_deriving.ml new file mode 100644 index 0000000000..a490f33557 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/ppx_easy_deriving.ml @@ -0,0 +1,15 @@ +(** Library for easily defining PPX derivers without boilerplate and runtime overhead. *) + +(** {1 Interfaces} *) + +include Intf (** @inline *) + + +(** {1 Deriver} *) + +module Deriver = Deriver + + +(** {1 Easier constructs} *) + +module Product = Product diff --git a/src/vendor/ppx_easy_deriving/product.ml b/src/vendor/ppx_easy_deriving/product.ml new file mode 100644 index 0000000000..2135552b63 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/product.ml @@ -0,0 +1,226 @@ +open Ppxlib +open Ast_builder.Default + +include Product_intf + +module type Product_S = S + +module Make (P: S): Intf.S = +struct + include P + + let tuple ~loc es = + let n = List.length es in + let pe_create = Pat_exp.create_tuple n in + P.product ~loc ~pe_create es + + let record ~loc les = + let ls = List.map fst les in + let pe_create = Pat_exp.create_record ls in + let es = List.map snd les in + P.product ~loc ~pe_create es +end + +module Reduce = +struct + include Reduce + + module Conjunctive = + struct + include Conjunctive + + module Make (C: S): Reduce.S = + struct + let name = C.name + let typ ~loc _ = [%type: bool] + let unit ~loc = [%expr true] + let both ~loc e1 e2 = [%expr [%e e1] && [%e e2]] + end + end +end + +module Reduce1 = +struct + include Reduce1 + + module Make (R1: S): Intf.S = + struct + module P: Product_S = + struct + let name = R1.name + let typ ~loc t = [%type: [%t t] -> [%t R1.typ ~loc t]] + + let product ~loc ~pe_create es = + let pe = pe_create ~prefix:"x" in + let body = + let es = List.map2 (fun e x -> + [%expr [%e e] [%e x]] + ) es (Pat_exp.to_exps ~loc pe) + in + Util.reduce ~unit:(R1.unit ~loc) ~both:(R1.both ~loc) es + in + [%expr fun [%p Pat_exp.to_pat ~loc pe] -> [%e body]] + end + + include Make (P) + end +end + +module Reduce2 = +struct + include Reduce2 + + module Make (R2: S): Intf.S = + struct + module P: Product_S = + struct + let name = R2.name + let typ ~loc t = [%type: [%t t] -> [%t t] -> [%t R2.typ ~loc t]] + + let product ~loc ~pe_create es = + let pel = pe_create ~prefix:"l" in + let per = pe_create ~prefix:"r" in + let body = + let esl = Pat_exp.to_exps ~loc pel in + let esr = Pat_exp.to_exps ~loc per in + let es = Util.map3 (fun e l r -> + [%expr [%e e] [%e l] [%e r]] + ) es esl esr + in + Util.reduce ~unit:(R2.unit ~loc) ~both:(R2.both ~loc) es + in + let pl = Pat_exp.to_pat ~loc pel in + let pr = Pat_exp.to_pat ~loc per in + [%expr fun [%p pl] [%p pr] -> [%e body]] + end + + include Make (P) + end +end + +module Create = +struct + include Create + + module Make (C: S): Intf.S = + struct + let name = C.name + let typ ~loc t = [%type: [%t C.typ ~loc t] -> [%t t]] + + let tuple ~loc es = + match es with + | [] -> [%expr fun _ -> ()] + | [e] -> e + | _ :: _ -> + let elems = List.map (fun e -> + [%expr [%e e] x] + ) es + in + let body = pexp_tuple ~loc elems in + [%expr fun x -> [%e body]] + + let record ~loc les = + let fields = List.map (fun (l, e) -> + (Located.mk ~loc l, [%expr [%e e] x]) + ) les + in + let body = pexp_record ~loc fields None in + [%expr fun x -> [%e body]] + end +end + +module Map1 = +struct + include Map1 + + module Make (M1: S): Intf.S = + struct + let name = M1.name + let typ ~loc t = [%type: [%t t] -> [%t t]] + + let tuple ~loc es = + let n = List.length es in + let pe = Pat_exp.create_tuple ~prefix:"x" n in + let elems = + List.map2 (fun e x -> + [%expr [%e e] [%e x]] + ) es (Pat_exp.to_exps ~loc pe) + in + let body = + match elems with + | [] -> [%expr ()] + | [elem] -> elem + | _ :: _ -> pexp_tuple ~loc elems + in + [%expr fun [%p Pat_exp.to_pat ~loc pe] -> [%e body]] + + let record ~loc les = + let ls = List.map fst les in + let pe = Pat_exp.create_record ~prefix:"x" ls in + let es = List.map snd les in + let elems = + List.map2 (fun e x -> + [%expr [%e e] [%e x]] + ) es (Pat_exp.to_exps ~loc pe) + in + let fields = List.map2 (fun l elem -> + (Located.mk ~loc l, elem) + ) ls elems + in + let body = pexp_record ~loc fields None in + [%expr fun [%p Pat_exp.to_pat ~loc pe] -> [%e body]] + end +end + +module Map2 = +struct + include Map2 + + module Make (M2: S): Intf.S = + struct + let name = M2.name + let typ ~loc t = [%type: [%t t] -> [%t t] -> [%t t]] + + let tuple ~loc es = + let n = List.length es in + let pel = Pat_exp.create_tuple ~prefix:"l" n in + let per = Pat_exp.create_tuple ~prefix:"r" n in + let elems = + let esl = Pat_exp.to_exps ~loc pel in + let esr = Pat_exp.to_exps ~loc per in + Util.map3 (fun e l r -> + [%expr [%e e] [%e l] [%e r]] + ) es esl esr + in + let body = + match elems with + | [] -> [%expr ()] + | [elem] -> elem + | _ :: _ -> pexp_tuple ~loc elems + in + let pl = Pat_exp.to_pat ~loc pel in + let pr = Pat_exp.to_pat ~loc per in + [%expr fun [%p pl] [%p pr] -> [%e body]] + + let record ~loc les = + let ls = List.map fst les in + let pel = Pat_exp.create_record ~prefix:"l" ls in + let per = Pat_exp.create_record ~prefix:"r" ls in + let es = List.map snd les in + let elems = + let esl = Pat_exp.to_exps ~loc pel in + let esr = Pat_exp.to_exps ~loc per in + Util.map3 (fun e l r -> + [%expr [%e e] [%e l] [%e r]] + ) es esl esr + in + let fields = List.map2 (fun l elem -> + (Located.mk ~loc l, elem) + ) ls elems + in + let body = pexp_record ~loc fields None in + let pl = Pat_exp.to_pat ~loc pel in + let pr = Pat_exp.to_pat ~loc per in + [%expr fun [%p pl] [%p pr] -> [%e body]] + end +end diff --git a/src/vendor/ppx_easy_deriving/product.mli b/src/vendor/ppx_easy_deriving/product.mli new file mode 100644 index 0000000000..d0b45f106c --- /dev/null +++ b/src/vendor/ppx_easy_deriving/product.mli @@ -0,0 +1,3 @@ +(** Product derivers which unify tuple and record derivers. *) + +include Product_intf.Product (** @inline *) diff --git a/src/vendor/ppx_easy_deriving/product_intf.ml b/src/vendor/ppx_easy_deriving/product_intf.ml new file mode 100644 index 0000000000..14964bbee7 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/product_intf.ml @@ -0,0 +1,132 @@ +open Ppxlib + +module type S = +sig + include Intf.Base + val product: loc:location -> pe_create:(prefix:string -> Pat_exp.t) -> expression list -> expression + (** Compose derived values/functions for product elements into derived value/function for the product. + + @param pe_create factory for patterns/expressions of the actual type. *) +end + +module Reduce = +struct + module type S = + sig + include Intf.Base + val unit: loc:location -> expression + (** Derived value/function for [unit] type. *) + + val both: loc:location -> expression -> expression -> expression + (** Compose derived values/functions in a product into derived value/function for the pair. *) + end + + module Conjunctive = + struct + module type S = Intf.Name + end +end + +module Reduce1 = +struct + module type S = Reduce.S +end + +module Reduce2 = +struct + module type S = Reduce.S +end + +module Create = +struct + module type S = + sig + include Intf.Base + end +end + +module Map1 = +struct + module type S = Intf.Name +end + +module Map2 = +struct + module type S = Intf.Name +end + +module type Product = +sig + module type S = S + (** Product deriver interface. *) + + module Make (P: S): Intf.S + (** Make deriver from product deriver. *) + + (** Reductions for reducing derivers. *) + module Reduce : + sig + module type S = Reduce.S + (** Reduction interface. *) + + (** Conjunctive reduction. *) + module Conjunctive : + sig + module type S = Reduce.Conjunctive.S + (** Conjunctive reduction interface. *) + + module Make (C: S): Reduce.S + (** Make reduction from conjunctive reduction. *) + end + end + + (** Unary reducing deriver. *) + module Reduce1 : + sig + module type S = Reduce1.S + (** Unary reducing deriver interface. *) + + module Make (R1: S): Intf.S + (** Make deriver from unary reducing deriver. *) + end + + (** Binary reducing deriver. *) + module Reduce2 : + sig + module type S = Reduce2.S + (** Binary reducing deriver interface. *) + + module Make (R2: S): Intf.S + (** Make deriver from binary reducing deriver. *) + end + + (** Unary creating deriver. *) + module Create : + sig + module type S = Create.S + (** Unary creating deriver interface. *) + + module Make (C: S): Intf.S + (** Make deriver from unary creating deriver. *) + end + + (** Unary mapping deriver. *) + module Map1 : + sig + module type S = Map1.S + (** Unary mapping deriver interface. *) + + module Make (M1: S): Intf.S + (** Make deriver from unary mapping deriver. *) + end + + (** Binary mapping deriver. *) + module Map2 : + sig + module type S = Map2.S + (** Binary mapping deriver interface. *) + + module Make (M2: S): Intf.S + (** Make deriver from binary mapping deriver. *) + end +end diff --git a/src/vendor/ppx_easy_deriving/util.ml b/src/vendor/ppx_easy_deriving/util.ml new file mode 100644 index 0000000000..fbb9d3f642 --- /dev/null +++ b/src/vendor/ppx_easy_deriving/util.ml @@ -0,0 +1,12 @@ +let reduce ~unit ~both = function + | [] -> unit + | [x] -> x + | xs -> + let xs = List.rev xs in + match xs with + | x :: xs -> + List.fold_right both (List.rev xs) x (* omits hash_empty *) + | [] -> assert false + +let map3 f l1 l2 l3 = + List.map2 (fun x1 (x2, x3) -> f x1 x2 x3) l1 (List.combine l2 l3) (* TODO: optimize *) diff --git a/src/vendor/ppx_easy_deriving/util.mli b/src/vendor/ppx_easy_deriving/util.mli new file mode 100644 index 0000000000..0f896e7efc --- /dev/null +++ b/src/vendor/ppx_easy_deriving/util.mli @@ -0,0 +1,8 @@ +(** Utility functions. *) + +val reduce: unit:'a -> both:('a -> 'a -> 'a) -> 'a list -> 'a +(** Reduce a list of values "optimally", + i.e. without unnecessary [~unit] and [~both]. *) + +val map3: ('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list -> 'd list +(** Map three lists into one. *) From a39ab19882e9fc27fc1ba2e9e75ca290bda07e49 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Jul 2024 20:12:24 +0300 Subject: [PATCH 437/689] Deduplicate (include_subdirs no) in src/ppx --- src/ppx/dune | 1 + src/ppx/lattice/dune | 2 -- src/ppx/printable/dune | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) create mode 100644 src/ppx/dune diff --git a/src/ppx/dune b/src/ppx/dune new file mode 100644 index 0000000000..ff757cb8ca --- /dev/null +++ b/src/ppx/dune @@ -0,0 +1 @@ +(include_subdirs no) diff --git a/src/ppx/lattice/dune b/src/ppx/lattice/dune index 1f4dac4b82..862298be13 100644 --- a/src/ppx/lattice/dune +++ b/src/ppx/lattice/dune @@ -1,5 +1,3 @@ -(include_subdirs no) - (library (name ppx_deriving_lattice) (kind ppx_deriver) diff --git a/src/ppx/printable/dune b/src/ppx/printable/dune index 9164e487e0..8e08232de6 100644 --- a/src/ppx/printable/dune +++ b/src/ppx/printable/dune @@ -1,5 +1,3 @@ -(include_subdirs no) - (library (name ppx_deriving_printable) (kind ppx_deriver) From cd793b9e7293bd94920a09b7388e5cc19bf8518c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Jul 2024 20:17:00 +0300 Subject: [PATCH 438/689] Exclude PPX-s from Goblint_lib documentation check --- scripts/goblint-lib-modules.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/goblint-lib-modules.py b/scripts/goblint-lib-modules.py index 017530f838..ba25a1403c 100755 --- a/scripts/goblint-lib-modules.py +++ b/scripts/goblint-lib-modules.py @@ -42,6 +42,10 @@ "Goblint_build_info", "Dune_build_info", + # ppx-s + "Ppx_deriving_printable", + "Ppx_deriving_lattice", + "MessageCategory", # included in Messages "PreValueDomain", # included in ValueDomain From 2e1d5fec8e9a8c955b0a86fdd22a63a2d0b05ec3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Jul 2024 20:58:27 +0300 Subject: [PATCH 439/689] Add LICENSE for vendored ppx_easy_deriving --- src/vendor/ppx_easy_deriving/LICENSE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/vendor/ppx_easy_deriving/LICENSE.md diff --git a/src/vendor/ppx_easy_deriving/LICENSE.md b/src/vendor/ppx_easy_deriving/LICENSE.md new file mode 100644 index 0000000000..ae6337b11b --- /dev/null +++ b/src/vendor/ppx_easy_deriving/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Simmo Saan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 50b7e145cfb81c3c72e5d3b22a9df4ac74fecaa9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Jul 2024 13:57:07 +0300 Subject: [PATCH 440/689] Add yamlWitnessStripDiff for cram test diff binary gives differently biased output on OSX, this should be fully deterministic. --- tests/regression/36-apron/52-queuesize.t | 53 +++++++++-------- tests/regression/dune | 6 +- tests/util/dune | 4 +- tests/util/yamlWitnessStrip.ml | 65 +------------------- tests/util/yamlWitnessStripCommon.ml | 75 ++++++++++++++++++++++++ tests/util/yamlWitnessStripDiff.ml | 29 +++++++++ 6 files changed, 139 insertions(+), 93 deletions(-) create mode 100644 tests/util/yamlWitnessStripCommon.ml create mode 100644 tests/util/yamlWitnessStripDiff.ml diff --git a/tests/regression/36-apron/52-queuesize.t b/tests/regression/36-apron/52-queuesize.t index 987fe53f77..62851f2ec9 100644 --- a/tests/regression/36-apron/52-queuesize.t +++ b/tests/regression/36-apron/52-queuesize.t @@ -252,29 +252,30 @@ With diff-box: Compare witnesses: - $ diff witness-disable-diff-box.yml witness-enable-diff-box.yml - 9,19d8 - < string: 2147483647LL - (long long )capacity >= 0LL - < type: assertion - < format: C - < - entry_type: location_invariant - < location: - < file_name: 52-queuesize.c - < file_hash: $FILE_HASH - < line: 36 - < column: 3 - < function: push - < location_invariant: - 44,54d32 - < type: assertion - < format: C - < - entry_type: location_invariant - < location: - < file_name: 52-queuesize.c - < file_hash: $FILE_HASH - < line: 15 - < column: 3 - < function: pop - < location_invariant: - < string: 2147483647LL - (long long )capacity >= 0LL - [1] + $ yamlWitnessStripDiff witness-disable-diff-box.yml witness-enable-diff-box.yml + # Left-only entries: + - entry_type: location_invariant + location: + file_name: 52-queuesize.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: push + location_invariant: + string: 2147483647LL - (long long )capacity >= 0LL + type: assertion + format: C + - entry_type: location_invariant + location: + file_name: 52-queuesize.c + file_hash: $FILE_HASH + line: 15 + column: 3 + function: pop + location_invariant: + string: 2147483647LL - (long long )capacity >= 0LL + type: assertion + format: C + --- + # Right-only entries: + [] diff --git a/tests/regression/dune b/tests/regression/dune index 8f550d190e..0fd8052478 100644 --- a/tests/regression/dune +++ b/tests/regression/dune @@ -2,7 +2,8 @@ (_ (binaries ./cfg/util/cfgDot.exe - ../util/yamlWitnessStrip.exe))) + ../util/yamlWitnessStrip.exe + ../util/yamlWitnessStripDiff.exe))) (rule (alias runtest) @@ -24,4 +25,5 @@ (alias runcramtest) (deps (package goblint) - %{bin:yamlWitnessStrip})) + %{bin:yamlWitnessStrip} + %{bin:yamlWitnessStripDiff})) diff --git a/tests/util/dune b/tests/util/dune index 6637217651..0e32304d4f 100644 --- a/tests/util/dune +++ b/tests/util/dune @@ -1,5 +1,5 @@ -(executable - (name yamlWitnessStrip) +(executables + (names yamlWitnessStrip yamlWitnessStripDiff) (libraries batteries.unthreaded goblint_std diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 8a5046d6ff..ece604f9a8 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -1,55 +1,5 @@ open Goblint_lib -open YamlWitnessType - -module StrippedEntry = -struct - type t = { - entry_type: EntryType.t; - } - [@@deriving ord] - - let strip_file_hashes {entry_type} = - let stripped_file_hash = "$FILE_HASH" in - let location_strip_file_hash location: Location.t = - {location with file_hash = stripped_file_hash} - in - let target_strip_file_hash target: Target.t = - {target with file_hash = stripped_file_hash} - in - let invariant_strip_file_hash ({invariant_type}: InvariantSet.Invariant.t): InvariantSet.Invariant.t = - let invariant_type: InvariantSet.InvariantType.t = - match invariant_type with - | LocationInvariant x -> - LocationInvariant {x with location = location_strip_file_hash x.location} - | LoopInvariant x -> - LoopInvariant {x with location = location_strip_file_hash x.location} - in - {invariant_type} - in - let entry_type: EntryType.t = - match entry_type with - | LocationInvariant x -> - LocationInvariant {x with location = location_strip_file_hash x.location} - | LoopInvariant x -> - LoopInvariant {x with location = location_strip_file_hash x.location} - | FlowInsensitiveInvariant x -> - FlowInsensitiveInvariant x (* no location to strip *) - | PreconditionLoopInvariant x -> - PreconditionLoopInvariant {x with location = location_strip_file_hash x.location} - | LoopInvariantCertificate x -> - LoopInvariantCertificate {x with target = target_strip_file_hash x.target} - | PreconditionLoopInvariantCertificate x -> - PreconditionLoopInvariantCertificate {x with target = target_strip_file_hash x.target} - | InvariantSet x -> - InvariantSet {content = List.map invariant_strip_file_hash x.content} - in - {entry_type} - - let to_yaml {entry_type} = - `O ([ - ("entry_type", `String (EntryType.entry_type entry_type)); - ] @ EntryType.to_yaml' entry_type) -end +open YamlWitnessStripCommon (* Use set for output, so order is deterministic regardless of Goblint. *) module StrippedEntrySet = Set.Make (StrippedEntry) @@ -69,18 +19,7 @@ let main () = stripped_entries ) StrippedEntrySet.empty yaml_entries in - let stripped_yaml_entries = - StrippedEntrySet.elements stripped_entries - |> List.map StrippedEntry.strip_file_hashes - |> List.rev_map StrippedEntry.to_yaml - in - let stripped_yaml = `A stripped_yaml_entries in - (* to_file/to_string uses a fixed-size buffer... *) - let stripped_yaml_str = match GobYaml.to_string' stripped_yaml with - | Ok text -> text - | Error (`Msg m) -> failwith ("Yaml.to_string: " ^ m) - in - Batteries.output_string Batteries.stdout stripped_yaml_str + print_stripped_entries stripped_entries let () = main () diff --git a/tests/util/yamlWitnessStripCommon.ml b/tests/util/yamlWitnessStripCommon.ml new file mode 100644 index 0000000000..e2c6905f02 --- /dev/null +++ b/tests/util/yamlWitnessStripCommon.ml @@ -0,0 +1,75 @@ +open Goblint_lib +open YamlWitnessType + +module StrippedEntry = +struct + type t = { + entry_type: EntryType.t; + } + [@@deriving ord] + + let strip_file_hashes {entry_type} = + let stripped_file_hash = "$FILE_HASH" in + let location_strip_file_hash location: Location.t = + {location with file_hash = stripped_file_hash} + in + let target_strip_file_hash target: Target.t = + {target with file_hash = stripped_file_hash} + in + let invariant_strip_file_hash ({invariant_type}: InvariantSet.Invariant.t): InvariantSet.Invariant.t = + let invariant_type: InvariantSet.InvariantType.t = + match invariant_type with + | LocationInvariant x -> + LocationInvariant {x with location = location_strip_file_hash x.location} + | LoopInvariant x -> + LoopInvariant {x with location = location_strip_file_hash x.location} + in + {invariant_type} + in + let entry_type: EntryType.t = + match entry_type with + | LocationInvariant x -> + LocationInvariant {x with location = location_strip_file_hash x.location} + | LoopInvariant x -> + LoopInvariant {x with location = location_strip_file_hash x.location} + | FlowInsensitiveInvariant x -> + FlowInsensitiveInvariant x (* no location to strip *) + | PreconditionLoopInvariant x -> + PreconditionLoopInvariant {x with location = location_strip_file_hash x.location} + | LoopInvariantCertificate x -> + LoopInvariantCertificate {x with target = target_strip_file_hash x.target} + | PreconditionLoopInvariantCertificate x -> + PreconditionLoopInvariantCertificate {x with target = target_strip_file_hash x.target} + | InvariantSet x -> + InvariantSet {content = List.map invariant_strip_file_hash x.content} + in + {entry_type} + + let to_yaml {entry_type} = + `O ([ + ("entry_type", `String (EntryType.entry_type entry_type)); + ] @ EntryType.to_yaml' entry_type) + + let of_yaml y = + let open GobYaml in + let+ entry_type = y |> EntryType.of_yaml in + {entry_type} +end + +(* Use set for output, so order is deterministic regardless of Goblint. *) +module StrippedEntrySet = Set.Make (StrippedEntry) + +let print_stripped_entries stripped_entries = + let stripped_yaml_entries = + StrippedEntrySet.elements stripped_entries + |> List.map StrippedEntry.strip_file_hashes + |> List.rev_map StrippedEntry.to_yaml + in + + let stripped_yaml = `A stripped_yaml_entries in + (* to_file/to_string uses a fixed-size buffer... *) + let stripped_yaml_str = match GobYaml.to_string' stripped_yaml with + | Ok text -> text + | Error (`Msg m) -> failwith ("Yaml.to_string: " ^ m) + in + Batteries.output_string Batteries.stdout stripped_yaml_str diff --git a/tests/util/yamlWitnessStripDiff.ml b/tests/util/yamlWitnessStripDiff.ml new file mode 100644 index 0000000000..8a993382b3 --- /dev/null +++ b/tests/util/yamlWitnessStripDiff.ml @@ -0,0 +1,29 @@ +open YamlWitnessStripCommon + +let read_stripped_entries path = + let yaml_str = BatFile.with_file_in path BatIO.read_all in + let yaml = Yaml.of_string_exn yaml_str in + let yaml_entries = yaml |> GobYaml.list |> BatResult.get_ok in + + List.fold_left (fun stripped_entries yaml_entry -> + match StrippedEntry.of_yaml yaml_entry with + | Ok stripped_entry -> + StrippedEntrySet.add stripped_entry stripped_entries + | Error (`Msg e) -> + Format.eprintf "couldn't parse entry: %s" e; + stripped_entries + ) StrippedEntrySet.empty yaml_entries + +let main () = + let left_stripped_entries = read_stripped_entries Sys.argv.(1) in + let right_stripped_entries = read_stripped_entries Sys.argv.(2) in + let left_only_stripped_entries = StrippedEntrySet.diff left_stripped_entries right_stripped_entries in + let right_only_stripped_entries = StrippedEntrySet.diff right_stripped_entries left_stripped_entries in + + print_endline "# Left-only entries:"; + print_stripped_entries left_only_stripped_entries; + print_endline "---"; + print_endline "# Right-only entries:"; + print_stripped_entries right_only_stripped_entries + +let () = main () From 65d4c02128083cb42ce2a51d3f60eb50f97f37f5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Jul 2024 14:08:57 +0300 Subject: [PATCH 441/689] Add pretty-deterministic output for cram test --- src/config/options.schema.json | 4 ++-- src/framework/analysisResult.ml | 13 +++++++++++ .../00-sanity/33-hoare-over-paths.t | 22 +++++++++---------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 0cb1b6ee67..4243c29590 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -79,9 +79,9 @@ "result": { "title": "result", "description": - "Result style: none, fast_xml, json, pretty, json-messages, sarif.", + "Result style: none, fast_xml, json, pretty, pretty-deterministic, json-messages, sarif.", "type": "string", - "enum": ["none", "fast_xml", "json", "pretty", "json-messages", "sarif"], + "enum": ["none", "fast_xml", "json", "pretty", "pretty-deterministic", "json-messages", "sarif"], "default": "none" }, "solver": { diff --git a/src/framework/analysisResult.ml b/src/framework/analysisResult.ml index 41c2bbd2c7..c1d7fde8a5 100644 --- a/src/framework/analysisResult.ml +++ b/src/framework/analysisResult.ml @@ -45,6 +45,18 @@ struct let defline () = dprintf "OTHERS -> Not available\n" in dprintf "@[Mapping {\n @[%t%t@]}@]" content defline + let pretty_deterministic () mapping = + let bindings = + to_list mapping + |> List.sort [%ord: ResultNode.t * Range.t] + in + let f dok (key, st) = + dok ++ dprintf "%a ->@? @[%a@]\n" ResultNode.pretty key Range.pretty st + in + let content () = List.fold_left f nil bindings in + let defline () = dprintf "OTHERS -> Not available\n" in + dprintf "@[Mapping {\n @[%t%t@]}@]" content defline + include C let printXml f xs = @@ -91,6 +103,7 @@ struct let out = Messages.get_out result_name !Messages.out in match get_string "result" with | "pretty" -> ignore (fprintf out "%a\n" pretty (Lazy.force table)) + | "pretty-deterministic" -> ignore (fprintf out "%a\n" pretty_deterministic (Lazy.force table)) | "fast_xml" -> let module SH = BatHashtbl.Make (Basetype.RawStrings) in let file2funs = SH.create 100 in diff --git a/tests/regression/00-sanity/33-hoare-over-paths.t b/tests/regression/00-sanity/33-hoare-over-paths.t index 4d34cd4561..5148f5e1f2 100644 --- a/tests/regression/00-sanity/33-hoare-over-paths.t +++ b/tests/regression/00-sanity/33-hoare-over-paths.t @@ -1,4 +1,4 @@ - $ goblint --set ana.path_sens[+] mutex --set result pretty --set outfile pretty.txt 33-hoare-over-paths.c + $ goblint --set ana.path_sens[+] mutex --set result pretty-deterministic --set outfile pretty.txt 33-hoare-over-paths.c [Success][Assert] Assertion "1" will succeed (33-hoare-over-paths.c:11:5-11:24) [Success][Assert] Assertion "1" will succeed (33-hoare-over-paths.c:16:5-16:24) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -169,9 +169,6 @@ Global { m -> mutex } - Temp { - RETURN -> 0 - } }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, @@ -179,12 +176,13 @@ escape:{}, mutexEvents:(), access:(), - mutex:(lockset:{m}, multiplicity:{}), + mutex:(lockset:{}, multiplicity:{}), race:(), mhp:(), assert:(), - pthreadMutexType:()], map:{}), - (MCP.D:[expRelation:(), + pthreadMutexType:()], map:{})} + 33-hoare-over-paths.c:7:1-34:1(main) -> + PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), mallocWrapper:(wrapper call:Unknown node, unique calls:{}), base:({ Global { @@ -200,18 +198,20 @@ escape:{}, mutexEvents:(), access:(), - mutex:(lockset:{}, multiplicity:{}), + mutex:(lockset:{m}, multiplicity:{}), race:(), mhp:(), assert:(), - pthreadMutexType:()], map:{})} - 33-hoare-over-paths.c:7:1-34:1(main) -> - PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), + pthreadMutexType:()], map:{}), + (MCP.D:[expRelation:(), mallocWrapper:(wrapper call:Unknown node, unique calls:{}), base:({ Global { m -> mutex } + Temp { + RETURN -> 0 + } }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, From 62f1e2e0de72df4b09ffcd7d34a86c1616c740af Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 26 Jun 2024 17:43:07 +0300 Subject: [PATCH 442/689] Try to print selenium logs for Gobview test --- scripts/test-gobview.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/test-gobview.py b/scripts/test-gobview.py index f5961108d7..10808a9b62 100644 --- a/scripts/test-gobview.py +++ b/scripts/test-gobview.py @@ -6,6 +6,7 @@ from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from threading import Thread import subprocess @@ -17,6 +18,11 @@ # cleanup def cleanup(browser, thread): print("cleanup") + + # print messages + for entry in browser.get_log('browser'): + print(entry) + browser.close() p.kill() thread.join() @@ -35,6 +41,8 @@ def serve(): print("starting installation of browser\n") options = Options() options.add_argument('headless') +# options.set_capability("loggingPrefs", { 'browser':'ALL' }) +options.set_capability("goog:loggingPrefs", { 'browser':'ALL' }) browser = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=options) print("finished webdriver installation \n") browser.maximize_window() From 23643df9f573ab88296247fe17a07dc3205db249 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Jul 2024 10:46:11 +0300 Subject: [PATCH 443/689] Add js_of_ocaml upper bound for Gobview --- gobview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gobview b/gobview index 4069f32f82..03b0682f97 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 4069f32f82efdefb43c970fb77ca29671a4b6972 +Subproject commit 03b0682f973eab0d26cf8aea74c63a9e869c9716 From 72713a62ad3a3e09f57ec6b8a70e16cfa09ff76a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Jul 2024 13:31:06 +0300 Subject: [PATCH 444/689] Add initial CHANGELOG for v2.4.0 --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d285480259..73b235883f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## v2.4.0 (unreleased) +* Remove unmaintained analyses: spec, file (#1281). +* Add linear two-variable equalities analysis (#1297, #1412, #1466). +* Add callstring, loopfree callstring and context gas analyses (#1038, #1340, #1379, #1427, #1439). +* Add non-relational thread-modular value analyses with thread IDs (#1366, #1398, #1399). +* Add NULL byte array domain (#1076). +* Fix spurious overflow warnings from internal evaluations (#1406, #1411, #1511). +* Refactor non-definite mutex handling to fix unsoundness (#1430, #1500, #1409). +* Fix non-relational thread-modular value analysis unsoundness with ambiguous points-to sets (#1457, #1458). +* Fix mutex type analysis unsoundness and enable it by default (#1414, #1416, #1510). +* Add points-to set refinement on mutex path splitting (#1287, #1343, #1374, #1396, #1407). +* Improve narrowing operators (#1502, #1540, #1543). +* Extract automatic configuration tuning for soundness (#1369). +* Fix many locations in witnesses (#1355, #1372, #1400, #1403). +* Improve output readability (#1294, #1312, #1405, #1497). +* Refactor logging (#1117). +* Modernize all library function specifications (#1029, #688, #1174, #1289, #1447, #1487). +* Remove OCaml 4.10, 4.11, 4.12 and 4.13 support (#1448). + ## v2.3.0 Functionally equivalent to Goblint in SV-COMP 2024. From a00ca1b507b638cffa7404ee5e5bba9ddaa1a586 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Jul 2024 17:15:07 +0300 Subject: [PATCH 445/689] Remove goblint.build-info.js and goblint.sites.js --- gobview | 2 +- src/build-info/build_info_js/dune | 5 ----- src/build-info/build_info_js/dune_build_info.ml | 1 - src/sites/sites_js/dune | 6 ------ src/sites/sites_js/goblint_sites.ml | 6 ------ 5 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 src/build-info/build_info_js/dune delete mode 100644 src/build-info/build_info_js/dune_build_info.ml delete mode 100644 src/sites/sites_js/dune delete mode 100644 src/sites/sites_js/goblint_sites.ml diff --git a/gobview b/gobview index 03b0682f97..1895e62dab 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 03b0682f973eab0d26cf8aea74c63a9e869c9716 +Subproject commit 1895e62dab67cfb05a5981bcfd7f36d46acd2b7e diff --git a/src/build-info/build_info_js/dune b/src/build-info/build_info_js/dune deleted file mode 100644 index 9400f564ff..0000000000 --- a/src/build-info/build_info_js/dune +++ /dev/null @@ -1,5 +0,0 @@ -; goblint.build-info implementation which works with js_of_ocaml and doesn't use dune-build-info -(library - (name goblint_build_info_js) - (public_name goblint.build-info.js) - (implements goblint.build-info)) diff --git a/src/build-info/build_info_js/dune_build_info.ml b/src/build-info/build_info_js/dune_build_info.ml deleted file mode 100644 index 002015cd31..0000000000 --- a/src/build-info/build_info_js/dune_build_info.ml +++ /dev/null @@ -1 +0,0 @@ -let statically_linked_libraries = [] diff --git a/src/sites/sites_js/dune b/src/sites/sites_js/dune deleted file mode 100644 index 4e20871974..0000000000 --- a/src/sites/sites_js/dune +++ /dev/null @@ -1,6 +0,0 @@ -; goblint.sites implementation which works with js_of_ocaml and doesn't use dune-site -(library - (name goblint_sites_js) - (public_name goblint.sites.js) - (implements goblint.sites) - (modules goblint_sites)) diff --git a/src/sites/sites_js/goblint_sites.ml b/src/sites/sites_js/goblint_sites.ml deleted file mode 100644 index 3a7b353064..0000000000 --- a/src/sites/sites_js/goblint_sites.ml +++ /dev/null @@ -1,6 +0,0 @@ -let lib = [] -let lib_stub_include = [] -let lib_stub_src = [] -let lib_runtime_include = [] -let lib_runtime_src = [] -let conf = [] From 5a50fa1e16e63ab3ebe5004dce2a3bf3cb4aba6f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Jul 2024 17:26:08 +0300 Subject: [PATCH 446/689] Unvirtualize goblint.build-info and goblint.sites --- gobview | 2 +- src/build-info/build_info_dune/dune | 6 ------ src/build-info/dune | 8 +------- .../{build_info_dune => }/dune_build_info.ml | 0 src/dune | 8 ++++---- src/sites/dune | 12 +++++------- src/sites/{sites_dune => }/goblint_sites.ml | 0 src/sites/sites_dune/dune | 12 ------------ tests/regression/cfg/util/dune | 4 ++-- tests/unit/dune | 2 +- tests/util/dune | 4 ++-- 11 files changed, 16 insertions(+), 42 deletions(-) delete mode 100644 src/build-info/build_info_dune/dune rename src/build-info/{build_info_dune => }/dune_build_info.ml (100%) rename src/sites/{sites_dune => }/goblint_sites.ml (100%) delete mode 100644 src/sites/sites_dune/dune diff --git a/gobview b/gobview index 1895e62dab..f9ce8bcad3 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 1895e62dab67cfb05a5981bcfd7f36d46acd2b7e +Subproject commit f9ce8bcad3552ad95488bc4988dcc0d5ed57b365 diff --git a/src/build-info/build_info_dune/dune b/src/build-info/build_info_dune/dune deleted file mode 100644 index ec46f4b3d1..0000000000 --- a/src/build-info/build_info_dune/dune +++ /dev/null @@ -1,6 +0,0 @@ -; goblint.build-info implementation which properly uses dune-build-info -(library - (name goblint_build_info_dune) - (public_name goblint.build-info.dune) - (implements goblint.build-info) - (libraries dune-build-info)) diff --git a/src/build-info/dune b/src/build-info/dune index e1a45ef8fc..4ffa1f4550 100644 --- a/src/build-info/dune +++ b/src/build-info/dune @@ -1,15 +1,9 @@ (include_subdirs no) -; virtual library to allow js build (for gobview) without dune-build-info -; dune-build-info seems to be incompatible with js_of_ocaml -; File "gobview/src/.App.eobjs/build_info_data.ml-gen", line 1: -; Error: Could not find the .cmi file for interface -; gobview/src/.App.eobjs/build_info_data.ml-gen. (library (name goblint_build_info) (public_name goblint.build-info) - (libraries batteries.unthreaded) - (virtual_modules dune_build_info)) + (libraries dune-build-info batteries.unthreaded)) (rule (target configVersion.ml) diff --git a/src/build-info/build_info_dune/dune_build_info.ml b/src/build-info/dune_build_info.ml similarity index 100% rename from src/build-info/build_info_dune/dune_build_info.ml rename to src/build-info/dune_build_info.ml diff --git a/src/dune b/src/dune index 5265821b5a..c549fd5d7d 100644 --- a/src/dune +++ b/src/dune @@ -88,7 +88,7 @@ (public_names goblint) (modes byte native) ; https://dune.readthedocs.io/en/stable/dune-files.html#linking-modes (modules goblint) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) + (libraries goblint.lib goblint.sites goblint.build-info goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) @@ -96,7 +96,7 @@ (executable (name privPrecCompare) (modules privPrecCompare) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) + (libraries goblint.lib goblint.sites goblint.build-info goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) @@ -104,7 +104,7 @@ (executable (name apronPrecCompare) (modules apronPrecCompare) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) + (libraries goblint.lib goblint.sites goblint.build-info goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) @@ -112,7 +112,7 @@ (executable (name messagesCompare) (modules messagesCompare) - (libraries goblint.lib goblint.sites.dune goblint.build-info.dune goblint_std) + (libraries goblint.lib goblint.sites goblint.build-info goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) diff --git a/src/sites/dune b/src/sites/dune index d8663e37fe..6de3a5a32a 100644 --- a/src/sites/dune +++ b/src/sites/dune @@ -1,12 +1,10 @@ (include_subdirs no) -; virtual library to allow js build (for gobview) without dune-site -; dune-site seems to be incompatible with js_of_ocaml -; File "gobview/src/.App.eobjs/dune_site_data.ml-gen", line 1: -; Error: Could not find the .cmi file for interface -; gobview/src/.App.eobjs/dune_site_data.ml-gen. (library (name goblint_sites) (public_name goblint.sites) - (virtual_modules goblint_sites) - (libraries fpath)) + (libraries dune-site fpath)) + +(generate_sites_module + (module dunesite) + (sites goblint)) diff --git a/src/sites/sites_dune/goblint_sites.ml b/src/sites/goblint_sites.ml similarity index 100% rename from src/sites/sites_dune/goblint_sites.ml rename to src/sites/goblint_sites.ml diff --git a/src/sites/sites_dune/dune b/src/sites/sites_dune/dune deleted file mode 100644 index b7f90a8892..0000000000 --- a/src/sites/sites_dune/dune +++ /dev/null @@ -1,12 +0,0 @@ -; goblint.sites implementation which properly uses dune-site -(library - (name goblint_sites_dune) - (public_name goblint.sites.dune) - (implements goblint.sites) - (modules goblint_sites dunesite) - (private_modules dunesite) ; must also be in modules - (libraries dune-site)) - -(generate_sites_module - (module dunesite) - (sites goblint)) diff --git a/tests/regression/cfg/util/dune b/tests/regression/cfg/util/dune index fb3c5e6899..4c41de07e4 100644 --- a/tests/regression/cfg/util/dune +++ b/tests/regression/cfg/util/dune @@ -6,6 +6,6 @@ goblint_common goblint_lib ; TODO: avoid: extract LoopUnrolling and WitnessUtil node predicates from goblint_lib fpath - goblint.sites.dune - goblint.build-info.dune) + goblint.sites + goblint.build-info) (preprocess (pps ppx_deriving.std))) diff --git a/tests/unit/dune b/tests/unit/dune index 5f0b909a77..6c3083dc1a 100644 --- a/tests/unit/dune +++ b/tests/unit/dune @@ -2,7 +2,7 @@ (test (name mainTest) - (libraries ounit2 qcheck-ounit goblint.std goblint.common goblint.lib goblint.constraint goblint.solver goblint.cdomain.value goblint.sites.dune goblint.build-info.dune) + (libraries ounit2 qcheck-ounit goblint.std goblint.common goblint.lib goblint.constraint goblint.solver goblint.cdomain.value goblint.sites goblint.build-info) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall)) diff --git a/tests/util/dune b/tests/util/dune index 6637217651..fb630bd15b 100644 --- a/tests/util/dune +++ b/tests/util/dune @@ -5,7 +5,7 @@ goblint_std goblint_lib yaml - goblint.sites.dune - goblint.build-info.dune) + goblint.sites + goblint.build-info) (flags :standard -open Goblint_std) (preprocess (pps ppx_deriving.std))) From a5ab08b1a744f647ea4ef86a24173b6d545c103f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Jul 2024 17:27:39 +0300 Subject: [PATCH 447/689] Remove unused goblint.build-info and goblint.sites dependency from most executables --- gobview | 2 +- src/dune | 8 ++++---- src/index.mld | 6 ------ tests/regression/cfg/util/dune | 4 +--- tests/unit/dune | 2 +- tests/util/dune | 4 +--- 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/gobview b/gobview index f9ce8bcad3..4e965cf1bb 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit f9ce8bcad3552ad95488bc4988dcc0d5ed57b365 +Subproject commit 4e965cf1bb7be5e7ceef2a40586ea445682cca64 diff --git a/src/dune b/src/dune index c549fd5d7d..2ba497c629 100644 --- a/src/dune +++ b/src/dune @@ -88,7 +88,7 @@ (public_names goblint) (modes byte native) ; https://dune.readthedocs.io/en/stable/dune-files.html#linking-modes (modules goblint) - (libraries goblint.lib goblint.sites goblint.build-info goblint_std) + (libraries goblint.lib goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) @@ -96,7 +96,7 @@ (executable (name privPrecCompare) (modules privPrecCompare) - (libraries goblint.lib goblint.sites goblint.build-info goblint_std) + (libraries goblint.lib goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) @@ -104,7 +104,7 @@ (executable (name apronPrecCompare) (modules apronPrecCompare) - (libraries goblint.lib goblint.sites goblint.build-info goblint_std) + (libraries goblint.lib goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) @@ -112,7 +112,7 @@ (executable (name messagesCompare) (modules messagesCompare) - (libraries goblint.lib goblint.sites goblint.build-info goblint_std) + (libraries goblint.lib goblint_std) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall -open Goblint_std) ) diff --git a/src/index.mld b/src/index.mld index f0d63a0fc7..a2ef15482e 100644 --- a/src/index.mld +++ b/src/index.mld @@ -44,15 +44,9 @@ 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} diff --git a/tests/regression/cfg/util/dune b/tests/regression/cfg/util/dune index 4c41de07e4..8ab300b531 100644 --- a/tests/regression/cfg/util/dune +++ b/tests/regression/cfg/util/dune @@ -5,7 +5,5 @@ goblint_logs goblint_common goblint_lib ; TODO: avoid: extract LoopUnrolling and WitnessUtil node predicates from goblint_lib - fpath - goblint.sites - goblint.build-info) + fpath) (preprocess (pps ppx_deriving.std))) diff --git a/tests/unit/dune b/tests/unit/dune index 6c3083dc1a..07c87e7822 100644 --- a/tests/unit/dune +++ b/tests/unit/dune @@ -2,7 +2,7 @@ (test (name mainTest) - (libraries ounit2 qcheck-ounit goblint.std goblint.common goblint.lib goblint.constraint goblint.solver goblint.cdomain.value goblint.sites goblint.build-info) + (libraries ounit2 qcheck-ounit goblint.std goblint.common goblint.lib goblint.constraint goblint.solver goblint.cdomain.value) (preprocess (pps ppx_deriving.std ppx_deriving_hash ppx_deriving_yojson)) (flags :standard -linkall)) diff --git a/tests/util/dune b/tests/util/dune index fb630bd15b..d37c38dc7c 100644 --- a/tests/util/dune +++ b/tests/util/dune @@ -4,8 +4,6 @@ batteries.unthreaded goblint_std goblint_lib - yaml - goblint.sites - goblint.build-info) + yaml) (flags :standard -open Goblint_std) (preprocess (pps ppx_deriving.std))) From 40b34346ff77e078a29dbaef2d195fe552402e86 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Jul 2024 11:04:28 +0300 Subject: [PATCH 448/689] Add TODOs about IntDomain refinement --- src/cdomain/value/cdomains/intDomain.ml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 2d40e6a161..c983e543fa 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2794,7 +2794,7 @@ module Enums : S with type int_t = Z.t = struct | Inc e, Some (c, m) -> Inc (BISet.filter (contains c m) e) | _ -> a - let refine_with_interval ik a b = a + let refine_with_interval ik a b = a (* TODO: refine inclusion (exclusion?) set *) let refine_with_excl_list ik a b = match b with @@ -3577,7 +3577,7 @@ module IntDomTupleImpl = struct in [(fun (a, b, c, d, e) -> refine_with_excl_list ik (a, b, c, d, e) (to_excl_list (a, b, c, d, e))); (fun (a, b, c, d, e) -> refine_with_incl_list ik (a, b, c, d, e) (to_incl_list (a, b, c, d, e))); - (fun (a, b, c, d, e) -> maybe refine_with_interval ik (a, b, c, d, e) b); + (fun (a, b, c, d, e) -> maybe refine_with_interval ik (a, b, c, d, e) b); (* TODO: get interval across all domains with minimal and maximal *) (fun (a, b, c, d, e) -> maybe refine_with_congruence ik (a, b, c, d, e) d)] let refine ik ((a, b, c, d, e) : t ) : t = @@ -3791,6 +3791,7 @@ module IntDomTupleImpl = struct | _ -> BatPrintf.fprintf f "\n\n%s\n\n\n" (show x) let invariant_ikind e ik ((_, _, _, x_cong, x_intset) as x) = + (* TODO: do refinement before to ensure incl_list being more precise than intervals, etc (https://github.com/goblint/analyzer/pull/1517#discussion_r1693998515), requires refine functions to actually refine that *) let simplify_int fallback = match to_int x with | Some v -> From e5f097c4eea6214c71aee679fcf6c6374cdb1152 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 26 Jan 2024 12:53:35 +0200 Subject: [PATCH 449/689] Enable ana.sv-comp.functions in some Apron tests using __VERIFIER_nondet_int --- tests/regression/36-apron/45-context.c | 2 +- tests/regression/36-apron/46-no-context.c | 2 +- tests/regression/36-apron/47-no-context-attribute.c | 2 +- tests/regression/36-apron/48-context-attribute.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/regression/36-apron/45-context.c b/tests/regression/36-apron/45-context.c index 94328af97f..eda945abd5 100644 --- a/tests/regression/36-apron/45-context.c +++ b/tests/regression/36-apron/45-context.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --enable ana.relation.context +// SKIP PARAM: --enable ana.sv-comp.functions --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --enable ana.relation.context extern int __VERIFIER_nondet_int(); #include diff --git a/tests/regression/36-apron/46-no-context.c b/tests/regression/36-apron/46-no-context.c index bf115cee24..640784b913 100644 --- a/tests/regression/36-apron/46-no-context.c +++ b/tests/regression/36-apron/46-no-context.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --disable ana.relation.context +// SKIP PARAM: --enable ana.sv-comp.functions --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --disable ana.relation.context extern int __VERIFIER_nondet_int(); #include diff --git a/tests/regression/36-apron/47-no-context-attribute.c b/tests/regression/36-apron/47-no-context-attribute.c index 90b58cdc28..cf111f5ffc 100644 --- a/tests/regression/36-apron/47-no-context-attribute.c +++ b/tests/regression/36-apron/47-no-context-attribute.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --enable ana.relation.context +// SKIP PARAM: --enable ana.sv-comp.functions --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --enable ana.relation.context extern int __VERIFIER_nondet_int(); #include diff --git a/tests/regression/36-apron/48-context-attribute.c b/tests/regression/36-apron/48-context-attribute.c index 5e5ecf01fe..3304c20388 100644 --- a/tests/regression/36-apron/48-context-attribute.c +++ b/tests/regression/36-apron/48-context-attribute.c @@ -1,4 +1,4 @@ -// SKIP PARAM: --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --disable ana.relation.context +// SKIP PARAM: --enable ana.sv-comp.functions --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.int.interval --disable ana.relation.context extern int __VERIFIER_nondet_int(); #include From bc85d30c340457c8599360981c90a0768693b7dc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 26 Jan 2024 18:37:24 +0200 Subject: [PATCH 450/689] Make SetDomain hash non-commutative --- src/domain/setDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain/setDomain.ml b/src/domain/setDomain.ml index 9b545a78ee..c552363f3d 100644 --- a/src/domain/setDomain.ml +++ b/src/domain/setDomain.ml @@ -184,7 +184,7 @@ struct end ) - let hash x = fold (fun x y -> y + Base.hash x) x 0 + let hash x = fold (fun x y -> 13 * y + Base.hash x) x 0 let relift x = map Base.relift x From 2a714b81804eb1bb4c06ba36aee34aa18bc9de10 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Jul 2024 15:53:17 +0300 Subject: [PATCH 451/689] Simplify and generalize malloc fix in relational mutex-meet --- src/analyses/apron/relationPriv.apron.ml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 78a06dc227..ad4d26dfbf 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -479,25 +479,19 @@ struct let get_mutex_inits' = keep_only_protected_globals ask m get_mutex_inits in RD.join get_m get_mutex_inits' - let get_mutex_global_g_with_mutex_inits (ask:Q.ask) getg g = + let get_mutex_global_g_with_mutex_inits ask getg g = let g_var = AV.global g in let get_mutex_global_g = - let r = - if Param.handle_atomic then - (* Unprotected invariant is one big relation. *) - RD.keep_vars (getg (V.mutex atomic_mutex)) [g_var] - else - getg (V.global g) - in - if RD.is_bot r && (ask.f (Queries.IsAllocVar g)) then - (* malloc'ed blobs may not have a value here yet *) - RD.top () + if Param.handle_atomic then ( + (* Unprotected invariant is one big relation. *) + RD.keep_vars (getg (V.mutex atomic_mutex)) [g_var] + ) else - r + getg (V.global g) in let get_mutex_inits = getg V.mutex_inits in let get_mutex_inits' = RD.keep_vars get_mutex_inits [g_var] in - if not (RD.mem_var get_mutex_inits' g_var) then (* TODO: is this just a workaround for an escape bug? https://github.com/goblint/analyzer/pull/1354/files#r1498882657 *) + if RD.mem_var get_mutex_global_g g_var && not (RD.mem_var get_mutex_inits' g_var) then (* TODO: is this just a workaround for an escape bug? https://github.com/goblint/analyzer/pull/1354/files#r1498882657 *) (* This is an escaped variable whose value was never side-effected to get_mutex_inits' *) get_mutex_global_g else From c18061e000b830157f17f09c544320a83f9d756a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 11:26:54 +0300 Subject: [PATCH 452/689] Remove pthreadMutexType from ghost witness tests It is now enabled by default and default mutex type is assumed non-recursive now. --- .../regression/13-privatized/04-priv_multi.t | 4 +-- tests/regression/13-privatized/25-struct_nr.t | 2 +- tests/regression/13-privatized/74-mutex.c | 4 +-- tests/regression/13-privatized/74-mutex.t | 26 +++++++++---------- tests/regression/13-privatized/92-idx_priv.t | 2 +- tests/regression/29-svcomp/16-atomic_priv.t | 4 +-- .../regression/36-apron/12-traces-min-rpb1.t | 2 +- .../56-witness/64-ghost-multiple-protecting.c | 2 +- .../56-witness/64-ghost-multiple-protecting.t | 6 ++--- .../56-witness/65-ghost-ambiguous-lock.c | 2 +- .../56-witness/65-ghost-ambiguous-lock.t | 2 +- .../56-witness/66-ghost-alloc-lock.c | 8 +++--- .../56-witness/66-ghost-alloc-lock.t | 26 +++++++++---------- .../56-witness/67-ghost-no-unlock.c | 2 +- .../56-witness/67-ghost-no-unlock.t | 2 +- .../56-witness/68-ghost-ambiguous-idx.t | 2 +- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index 576c89ad4d..b1a45dd917 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -174,7 +174,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t index 342cfaf99c..88f205a431 100644 --- a/tests/regression/13-privatized/25-struct_nr.t +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) diff --git a/tests/regression/13-privatized/74-mutex.c b/tests/regression/13-privatized/74-mutex.c index 7c57688238..8ed9448b7b 100644 --- a/tests/regression/13-privatized/74-mutex.c +++ b/tests/regression/13-privatized/74-mutex.c @@ -29,8 +29,8 @@ void* producer() int main() { pthread_t tid; - pthread_mutexattr_t mutexattr; pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL); - pthread_mutex_init(&m, &mutexattr); + + pthread_mutex_init(&m, 0); pthread_create(&tid, 0, producer, 0); pthread_mutex_lock(&m); diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index f6f2fa8463..8999d394ec 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,11 +1,11 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -84,14 +84,14 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -138,9 +138,9 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 @@ -150,14 +150,14 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -241,9 +241,9 @@ Should also work with earlyglobs. [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index bd6db7e2ef..b157dfed4b 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c [Success][Assert] Assertion "data == 0" will succeed (92-idx_priv.c:22:3-22:29) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 83bc201a6c..eea47295d5 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -43,7 +43,7 @@ Non-atomic privatization: - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 1c3253afbc..df34013d16 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,4 +1,4 @@ - $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index 589aa92bff..699d133f2b 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +// PARAM: --set ana.activated[+] mutexGhosts #include #include int g1, g2; diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 943934a7be..e78d0d75aa 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -144,7 +144,7 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -295,7 +295,7 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.c b/tests/regression/56-witness/65-ghost-ambiguous-lock.c index b1df0ee2e8..f45334e755 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.c +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +// PARAM: --set ana.activated[+] mutexGhosts #include #include diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index d7d57d8a00..a6e0c12b74 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 23 dead: 0 diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.c b/tests/regression/56-witness/66-ghost-alloc-lock.c index 2c1028564a..073540b9db 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.c +++ b/tests/regression/56-witness/66-ghost-alloc-lock.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 +// PARAM: --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 #include #include @@ -18,11 +18,11 @@ void *t_fun(void *arg) { return NULL; } -int main() { pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); // https://github.com/goblint/analyzer/pull/1414 +int main() { m1 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m1, &attr); + pthread_mutex_init(m1, NULL); m2 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m2, &attr); + pthread_mutex_init(m2, NULL); pthread_t id; pthread_create(&id, NULL, t_fun, NULL); diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index e4268ec1cb..8e45272538 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -24,7 +24,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -33,7 +33,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -42,7 +42,7 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -51,7 +51,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -60,7 +60,7 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -69,7 +69,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -78,7 +78,7 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -87,7 +87,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -101,23 +101,23 @@ type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked scope: global type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked scope: global type: int initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m817990718_locked || g2 == 0)' + string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m334174073_locked || g1 == 0)' + string: '! multithreaded || (alloc_m559918035_locked || g1 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant diff --git a/tests/regression/56-witness/67-ghost-no-unlock.c b/tests/regression/56-witness/67-ghost-no-unlock.c index fc10b919d0..69ad571118 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.c +++ b/tests/regression/56-witness/67-ghost-no-unlock.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +// PARAM: --set ana.activated[+] mutexGhosts #include #include diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t index aed0ac3414..85b7a0b897 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.t +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 9f50ab7429..02cecfd8f6 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) [Info][Deadcode] Logical lines of code (LLoC) summary: From 6055e8dd7e768d2b061c16b9da61a579e120b146 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 11:29:15 +0300 Subject: [PATCH 453/689] Activate abortUnless in svcomp-ghost conf also --- conf/svcomp-ghost.json | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 84f127eb91..108b261322 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -31,6 +31,7 @@ "region", "thread", "threadJoins", + "abortUnless", "mutexGhosts", "pthreadMutexType" ], From 6e793142a53781763f9232d31302c5d21fea3b47 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 11:31:52 +0300 Subject: [PATCH 454/689] Update TODO comment about base earlyglobs flow-insensitive invariants --- src/analyses/base.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 4ae2fc711c..782b5662c6 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1247,8 +1247,8 @@ struct let query_invariant_global ctx g = if GobConfig.get_bool "ana.base.invariant.enabled" then ( (* Currently these global invariants are only sound with earlyglobs enabled for both single- and multi-threaded programs. - Otherwise, the values of globals in single-threaded mode are not accounted for. *) - (* TODO: account for single-threaded values without earlyglobs. *) + Otherwise, the values of globals in single-threaded mode are not accounted for. + They are also made sound without earlyglobs using the multithreaded mode ghost variable. *) match g with | `Left g' -> (* priv *) let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' in From 10a63d0acc1248d1399eb2ed397b3253db185002 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 12:41:00 +0300 Subject: [PATCH 455/689] Make unavailable on BSD On FreeBSD gcc package installs cpp13 (not cpp-13), not cpp (which is clang's). Also, tcsh has no compgen to look up existing cpp-s. --- goblint.opam | 2 +- goblint.opam.locked | 2 +- goblint.opam.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/goblint.opam b/goblint.opam index 7fe108f682..f342a85069 100644 --- a/goblint.opam +++ b/goblint.opam @@ -93,7 +93,7 @@ build: [ 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" +available: os-family != "bsd" & os-distribution != "alpine" & arch != "arm64" pin-depends: [ # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] diff --git a/goblint.opam.locked b/goblint.opam.locked index 252459d517..9d1b688e14 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -128,7 +128,7 @@ build: [ ["dune" "install" "-p" name "--create-install-files" name] ] dev-repo: "git+https://github.com/goblint/analyzer.git" -available: os-distribution != "alpine" & arch != "arm64" +available: os-family != "bsd" & os-distribution != "alpine" & arch != "arm64" conflicts: [ "result" {< "1.5"} "ez-conf-lib" {= "1"} diff --git a/goblint.opam.template b/goblint.opam.template index a730d5c064..fc8f1d419b 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,6 +1,6 @@ # 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" +available: os-family != "bsd" & os-distribution != "alpine" & arch != "arm64" pin-depends: [ # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] From bc8811c8034ec1600823923e4cdc625bfe949d1c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 10:06:18 +0300 Subject: [PATCH 456/689] Finalize CHANGELOG for v2.4.0 --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73b235883f..420cc7145e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ -## v2.4.0 (unreleased) +## v2.4.0 * Remove unmaintained analyses: spec, file (#1281). * Add linear two-variable equalities analysis (#1297, #1412, #1466). * Add callstring, loopfree callstring and context gas analyses (#1038, #1340, #1379, #1427, #1439). * Add non-relational thread-modular value analyses with thread IDs (#1366, #1398, #1399). * Add NULL byte array domain (#1076). * Fix spurious overflow warnings from internal evaluations (#1406, #1411, #1511). -* Refactor non-definite mutex handling to fix unsoundness (#1430, #1500, #1409). +* Refactor non-definite mutex handling to fix unsoundness (#1430, #1500, #1503, #1409). * Fix non-relational thread-modular value analysis unsoundness with ambiguous points-to sets (#1457, #1458). * Fix mutex type analysis unsoundness and enable it by default (#1414, #1416, #1510). * Add points-to set refinement on mutex path splitting (#1287, #1343, #1374, #1396, #1407). From cffe5c2e35fd1912a5c927bd1a5377035a4bee7e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 10:22:28 +0300 Subject: [PATCH 457/689] Replace goblint-cil pin with published 2.0.4, remove pins for v2.4.0 release --- dune-project | 2 +- goblint.opam | 10 +++++----- goblint.opam.locked | 9 +-------- goblint.opam.template | 8 ++++---- gobview | 2 +- src/common/util/cilType.ml | 1 + src/incremental/compareAST.ml | 1 + 7 files changed, 14 insertions(+), 19 deletions(-) diff --git a/dune-project b/dune-project index 3927e77bdd..f854518419 100644 --- a/dune-project +++ b/dune-project @@ -37,7 +37,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e "concurrency")) (depends (ocaml (>= 4.14)) - (goblint-cil (>= 2.0.3)) ; TODO no way to define as pin-depends? Used goblint.opam.template to add it for now. https://github.com/ocaml/dune/issues/3231. Alternatively, removing this line and adding cil as a git submodule and `(vendored_dirs cil)` as ./dune also works. This way, no more need to reinstall the pinned cil opam package on changes. However, then cil is cleaned and has to be rebuild together with goblint. + (goblint-cil (>= 2.0.4)) ; TODO no way to define as pin-depends? Used goblint.opam.template to add it for now. https://github.com/ocaml/dune/issues/3231. Alternatively, removing this line and adding cil as a git submodule and `(vendored_dirs cil)` as ./dune also works. This way, no more need to reinstall the pinned cil opam package on changes. However, then cil is cleaned and has to be rebuild together with goblint. (batteries (>= 3.5.1)) (zarith (>= 1.10)) (yojson (>= 2.0.0)) diff --git a/goblint.opam b/goblint.opam index f342a85069..6809044a7e 100644 --- a/goblint.opam +++ b/goblint.opam @@ -37,7 +37,7 @@ bug-reports: "https://github.com/goblint/analyzer/issues" depends: [ "dune" {>= "3.7"} "ocaml" {>= "4.14"} - "goblint-cil" {>= "2.0.3"} + "goblint-cil" {>= "2.0.4"} "batteries" {>= "3.5.1"} "zarith" {>= "1.10"} "yojson" {>= "2.0.0"} @@ -94,10 +94,10 @@ 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-family != "bsd" & os-distribution != "alpine" & arch != "arm64" -pin-depends: [ - # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed - [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] -] +# pin-depends: [ + # published goblint-cil 2.0.4 is currently up-to-date, so no pin needed + # [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] +# ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] diff --git a/goblint.opam.locked b/goblint.opam.locked index 9d1b688e14..5c1eb95709 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -64,7 +64,7 @@ depends: [ "fileutils" {= "0.6.4"} "fmt" {= "0.9.0"} "fpath" {= "0.7.3"} - "goblint-cil" {= "2.0.3"} + "goblint-cil" {= "2.0.4"} "hex" {= "1.5.0"} "integers" {= "0.7.0"} "json-data-encoding" {= "1.0.1"} @@ -136,13 +136,6 @@ conflicts: [ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] -# TODO: manually reordered to avoid opam pin crash: https://github.com/ocaml/opam/issues/4936 -pin-depends: [ - [ - "goblint-cil.2.0.3" - "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" - ] -] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} description: """\ Goblint is a sound static analysis framework for C programs using abstract interpretation. diff --git a/goblint.opam.template b/goblint.opam.template index fc8f1d419b..53260fb576 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,10 +1,10 @@ # 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-family != "bsd" & os-distribution != "alpine" & arch != "arm64" -pin-depends: [ - # published goblint-cil 2.0.3 is currently up-to-date, so no pin needed - [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] -] +# pin-depends: [ + # published goblint-cil 2.0.4 is currently up-to-date, so no pin needed + # [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] +# ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] diff --git a/gobview b/gobview index 03b0682f97..76e42c34d3 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 03b0682f973eab0d26cf8aea74c63a9e869c9716 +Subproject commit 76e42c34d36bd2ab6900efd661a972ba4824f065 diff --git a/src/common/util/cilType.ml b/src/common/util/cilType.ml index a484a228bd..5a473b7d60 100644 --- a/src/common/util/cilType.ml +++ b/src/common/util/cilType.ml @@ -698,6 +698,7 @@ struct | AAddrOf of t | AIndex of t * t | AQuestion of t * t * t + | AAssign of t * t [@@deriving eq, ord, hash] let name () = "attrparam" diff --git a/src/incremental/compareAST.ml b/src/incremental/compareAST.ml index f3de153658..2449cdac47 100644 --- a/src/incremental/compareAST.ml +++ b/src/incremental/compareAST.ml @@ -210,6 +210,7 @@ and eq_attrparam (a: attrparam) (b: attrparam) ~(rename_mapping: rename_mapping) | AAddrOf attrparam1, AAddrOf attrparam2 -> eq_attrparam attrparam1 attrparam2 ~rename_mapping ~acc | AIndex (left1, right1), AIndex (left2, right2) -> eq_attrparam left1 left2 ~rename_mapping ~acc &&>> eq_attrparam right1 right2 ~acc | AQuestion (left1, middle1, right1), AQuestion (left2, middle2, right2) -> eq_attrparam left1 left2 ~rename_mapping ~acc &&>> eq_attrparam middle1 middle2 ~acc &&>> eq_attrparam right1 right2 ~acc + | AAssign (left1, right1), AAssign (left2, right2) -> eq_attrparam left1 left2 ~rename_mapping ~acc &&>> eq_attrparam right1 right2 ~acc | a, b -> a = b, rename_mapping and eq_attribute (a: attribute) (b: attribute) ~(acc: (typ * typ) list) ~(rename_mapping: rename_mapping) = match a, b with From 8dd27a167601b98d79f58747060464bd06122289 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 10:24:11 +0300 Subject: [PATCH 458/689] Fix unused parameter error in BenchSet --- bench/basic/benchSet.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/basic/benchSet.ml b/bench/basic/benchSet.ml index 14eb03be82..ae38c156da 100644 --- a/bench/basic/benchSet.ml +++ b/bench/basic/benchSet.ml @@ -73,7 +73,7 @@ let () = ] ); "const" @> lazy ( - let args = ((fun x -> 42), set1) in + let args = ((fun _ -> 42), set1) in throughputN 1 [ ("map1", map1, args); ("map2", map2, args); From e09d31b3002d1e9f87d85d8a31a52c56a759486f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 10:28:33 +0300 Subject: [PATCH 459/689] Make available on arm64 --- goblint.opam | 2 +- goblint.opam.locked | 2 +- goblint.opam.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/goblint.opam b/goblint.opam index 6809044a7e..85068b4114 100644 --- a/goblint.opam +++ b/goblint.opam @@ -93,7 +93,7 @@ build: [ 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-family != "bsd" & os-distribution != "alpine" & arch != "arm64" +available: os-family != "bsd" & os-distribution != "alpine" # pin-depends: [ # published goblint-cil 2.0.4 is currently up-to-date, so no pin needed # [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] diff --git a/goblint.opam.locked b/goblint.opam.locked index 5c1eb95709..ca03f318b4 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -128,7 +128,7 @@ build: [ ["dune" "install" "-p" name "--create-install-files" name] ] dev-repo: "git+https://github.com/goblint/analyzer.git" -available: os-family != "bsd" & os-distribution != "alpine" & arch != "arm64" +available: os-family != "bsd" & os-distribution != "alpine" conflicts: [ "result" {< "1.5"} "ez-conf-lib" {= "1"} diff --git a/goblint.opam.template b/goblint.opam.template index 53260fb576..605f07751c 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,6 +1,6 @@ # 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-family != "bsd" & os-distribution != "alpine" & arch != "arm64" +available: os-family != "bsd" & os-distribution != "alpine" # pin-depends: [ # published goblint-cil 2.0.4 is currently up-to-date, so no pin needed # [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] From 0ad776f1ab4204878813c02b04b709cfdc3928a1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 10:28:42 +0300 Subject: [PATCH 460/689] Add M1 OSX to unlocked CI --- .github/workflows/unlocked.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 6a9eced42c..0c4433d0af 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -33,6 +33,8 @@ jobs: - os: ubuntu-latest ocaml-compiler: 4.14.x z3: true + - os: macos-latest + ocaml-compiler: 4.14.x # customize name to use readable string for apron instead of just a boolean # workaround for missing ternary operator: https://github.com/actions/runner/issues/409 From ad95965788dcd2accb884df584966fd77fa48569 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 14:53:49 +0300 Subject: [PATCH 461/689] Update releasing documentation --- docs/developer-guide/releasing.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/developer-guide/releasing.md b/docs/developer-guide/releasing.md index d875c0d3bf..7530d9ad20 100644 --- a/docs/developer-guide/releasing.md +++ b/docs/developer-guide/releasing.md @@ -24,6 +24,8 @@ All changes must be committed because the working tree is not checked. + The warning `[FAIL] opam field doc cannot be parsed by dune-release` is fine and can be ignored (see ). + 8. Check that "unlocked" workflow passes on GitHub Actions. It can be run manually on the release branch for checking. @@ -36,12 +38,13 @@ 1. Pull Docker image: `docker pull ocaml/opam:ubuntu-22.04-ocaml-4.14` (or newer). 2. Extract distribution archive. 3. Run Docker container in extracted directory: `docker run -it --rm -v $(pwd):/goblint ocaml/opam:ubuntu-22.04-ocaml-4.14` (or newer). - 4. Navigate to distribution archive inside Docker container: `cd /goblint`. - 5. Install and test package from distribution archive: `opam-2.1 install --with-test .`. - 6. Activate opam environment: `eval $(opam env)`. - 7. Check version: `goblint --version`. - 8. Check that analysis works: `goblint -v tests/regression/04-mutex/01-simple_rc.c`. - 9. Exit Docker container. + 4. Update opam-repository from git: `opam-2.1 repository add git git+https://github.com/ocaml/opam-repository.git && opam-2.1 update`. + 5. Navigate to distribution archive inside Docker container: `cd /goblint`. + 6. Install and test package from distribution archive: `opam-2.1 install --with-test .`. + 7. Activate opam environment: `eval $(opam env)`. + 8. Check version: `goblint --version`. + 9. Check that analysis works: `goblint -v tests/regression/04-mutex/01-simple_rc.c`. + 10. Exit Docker container. 12. Temporarily enable Zenodo GitHub webhook. From d46438a3c6b8b643db0d3a1edfe8894ac72fd7f0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 2 Aug 2024 14:57:22 +0300 Subject: [PATCH 462/689] Partially revert "Replace goblint-cil pin with published 2.0.4, remove pins for v2.4.0 release" This reverts commit cffe5c2e35fd1912a5c927bd1a5377035a4bee7e. --- goblint.opam | 7 +++---- goblint.opam.locked | 6 ++++++ goblint.opam.template | 7 +++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/goblint.opam b/goblint.opam index 85068b4114..37cd36bf6e 100644 --- a/goblint.opam +++ b/goblint.opam @@ -94,10 +94,9 @@ 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-family != "bsd" & os-distribution != "alpine" -# pin-depends: [ - # published goblint-cil 2.0.4 is currently up-to-date, so no pin needed - # [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] -# ] +pin-depends: [ + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" ] +] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] diff --git a/goblint.opam.locked b/goblint.opam.locked index ca03f318b4..7b23cc8a18 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -136,6 +136,12 @@ conflicts: [ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] +pin-depends: [ + [ + "goblint-cil.2.0.4" + "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" + ] +] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} description: """\ Goblint is a sound static analysis framework for C programs using abstract interpretation. diff --git a/goblint.opam.template b/goblint.opam.template index 605f07751c..3adc8e05c0 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,10 +1,9 @@ # 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-family != "bsd" & os-distribution != "alpine" -# pin-depends: [ - # published goblint-cil 2.0.4 is currently up-to-date, so no pin needed - # [ "goblint-cil.2.0.3" "git+https://github.com/goblint/cil.git#ae3a4949d478fad77e004c6fe15a7c83427df59f" ] -# ] +pin-depends: [ + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" ] +] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] From 3ad6b396681e0cb936eba09c4d7b6ebed882a0a2 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 4 Aug 2024 14:02:53 +0200 Subject: [PATCH 463/689] Typo --- 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 29fa74c5a9..4e523fe1ee 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2168,7 +2168,7 @@ struct 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. - But here we consider all non-ThreadCrate functions also unknown, so old-style LibraryFunctions access + But here we consider all non-ThreadCreate functions also unknown, so old-style LibraryFunctions access definitions using `Write would still spawn because they are not truly unknown functions (missing from LibraryFunctions). Need this to not have memmove spawn in SV-COMP. *) let shallow_args = LibraryDesc.Accesses.find desc.accs { kind = Spawn; deep = false } args in From 64d392de0ce64e2fee2b43ad42c0788856a7310b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 5 Aug 2024 11:13:43 +0300 Subject: [PATCH 464/689] Unvendor ppx_blob Version 0.8.0 includes the previously vendored fix for `(lang dune 3.0)`. --- dune-project | 1 + goblint.opam | 1 + goblint.opam.locked | 1 + src/vendor/ppx_blob/LICENSE.txt | 24 -------------------- src/vendor/ppx_blob/README.md | 1 - src/vendor/ppx_blob/src/dune | 5 ----- src/vendor/ppx_blob/src/ppx_blob.ml | 35 ----------------------------- 7 files changed, 3 insertions(+), 65 deletions(-) delete mode 100644 src/vendor/ppx_blob/LICENSE.txt delete mode 100644 src/vendor/ppx_blob/README.md delete mode 100644 src/vendor/ppx_blob/src/dune delete mode 100644 src/vendor/ppx_blob/src/ppx_blob.ml diff --git a/dune-project b/dune-project index f854518419..6ea0734887 100644 --- a/dune-project +++ b/dune-project @@ -45,6 +45,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e (ppx_deriving (>= 6.0.2)) (ppx_deriving_hash (>= 0.1.2)) (ppx_deriving_yojson (>= 3.7.0)) + (ppx_blob (>= 0.8.0)) (ounit2 :with-test) (qcheck-ounit :with-test) (odoc :with-doc) diff --git a/goblint.opam b/goblint.opam index 37cd36bf6e..6ea4183992 100644 --- a/goblint.opam +++ b/goblint.opam @@ -45,6 +45,7 @@ depends: [ "ppx_deriving" {>= "6.0.2"} "ppx_deriving_hash" {>= "0.1.2"} "ppx_deriving_yojson" {>= "3.7.0"} + "ppx_blob" {>= "0.8.0"} "ounit2" {with-test} "qcheck-ounit" {with-test} "odoc" {with-doc} diff --git a/goblint.opam.locked b/goblint.opam.locked index 7b23cc8a18..ed6424dbd3 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -85,6 +85,7 @@ depends: [ "ordering" {= "3.16.0"} "ounit2" {= "2.2.7" & with-test} "pp" {= "1.2.0"} + "ppx_blob" {= "0.9.0"} "ppx_derivers" {= "1.2.1"} "ppx_deriving" {= "6.0.2"} "ppx_deriving_hash" {= "0.1.2"} diff --git a/src/vendor/ppx_blob/LICENSE.txt b/src/vendor/ppx_blob/LICENSE.txt deleted file mode 100644 index 00d2e135a7..0000000000 --- a/src/vendor/ppx_blob/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to \ No newline at end of file diff --git a/src/vendor/ppx_blob/README.md b/src/vendor/ppx_blob/README.md deleted file mode 100644 index fdd7448a32..0000000000 --- a/src/vendor/ppx_blob/README.md +++ /dev/null @@ -1 +0,0 @@ -ppx_blob fix for `(lang dune 3.0)` vendored from . diff --git a/src/vendor/ppx_blob/src/dune b/src/vendor/ppx_blob/src/dune deleted file mode 100644 index 112b1d07c0..0000000000 --- a/src/vendor/ppx_blob/src/dune +++ /dev/null @@ -1,5 +0,0 @@ -(library - (name ppx_blob) - ; (public_name ppx_blob) - (kind ppx_rewriter) - (libraries ppxlib)) \ No newline at end of file diff --git a/src/vendor/ppx_blob/src/ppx_blob.ml b/src/vendor/ppx_blob/src/ppx_blob.ml deleted file mode 100644 index 622a99f8f6..0000000000 --- a/src/vendor/ppx_blob/src/ppx_blob.ml +++ /dev/null @@ -1,35 +0,0 @@ -open Ppxlib - -let location_errorf ~loc = - Format.ksprintf (fun err -> - raise (Ocaml_common.Location.Error (Ocaml_common.Location.error ~loc err)) - ) - -let find_file_path ~loc file_name = - let dirname = loc.Ocaml_common.Location.loc_start.pos_fname |> Filename.dirname in - let relative_path = Filename.concat dirname file_name in - List.find Sys.file_exists [relative_path; file_name] - -let get_blob ~loc file_name = - try - let file_path = find_file_path ~loc file_name in - let c = open_in_bin file_path in - let s = String.init (in_channel_length c) (fun _ -> input_char c) in - close_in c; - s - with _ -> - location_errorf ~loc "[%%blob] could not find or load file %s" file_name - -let expand ~ctxt file_name = - let loc = Expansion_context.Extension.extension_point_loc ctxt in - Ast_builder.Default.estring ~loc (get_blob ~loc file_name) - -let extension = - Extension.V3.declare "blob" Extension.Context.expression - Ast_pattern.(single_expr_payload (estring __)) - expand - -let rule = Ppxlib.Context_free.Rule.extension extension - -;; -Driver.register_transformation ~rules:[rule] "ppx_blob" \ No newline at end of file From 636e8ff1e1b8e9653f83704a3e0e2785ff5eabdc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 11:11:41 +0300 Subject: [PATCH 465/689] Upstream opam file from opam-repository for 2.4.0 --- goblint.opam | 6 +++++- goblint.opam.locked | 2 +- goblint.opam.template | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/goblint.opam b/goblint.opam index 37cd36bf6e..24845583f5 100644 --- a/goblint.opam +++ b/goblint.opam @@ -93,7 +93,7 @@ build: [ 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-family != "bsd" & os-distribution != "alpine" +available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" ] ] @@ -103,3 +103,7 @@ depexts: [ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] +x-ci-accept-failures: [ + "macos-homebrew" # newer MacOS headers cannot be parsed (https://github.com/ocaml/opam-repository/pull/26307#issuecomment-2258080206) + "opensuse-tumbleweed" # not GNU diff, so some cram tests fail (https://discuss.ocaml.org/t/opensuse-and-opam-tests/14641/2) +] diff --git a/goblint.opam.locked b/goblint.opam.locked index 7b23cc8a18..c629aa6755 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -128,7 +128,7 @@ build: [ ["dune" "install" "-p" name "--create-install-files" name] ] dev-repo: "git+https://github.com/goblint/analyzer.git" -available: os-family != "bsd" & os-distribution != "alpine" +available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") conflicts: [ "result" {< "1.5"} "ez-conf-lib" {= "1"} diff --git a/goblint.opam.template b/goblint.opam.template index 3adc8e05c0..bb70aa29e7 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,6 +1,6 @@ # 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-family != "bsd" & os-distribution != "alpine" +available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" ] ] @@ -10,3 +10,7 @@ depexts: [ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] +x-ci-accept-failures: [ + "macos-homebrew" # newer MacOS headers cannot be parsed (https://github.com/ocaml/opam-repository/pull/26307#issuecomment-2258080206) + "opensuse-tumbleweed" # not GNU diff, so some cram tests fail (https://discuss.ocaml.org/t/opensuse-and-opam-tests/14641/2) +] From b9caf634f7fcbe006b60d5dc4c5d7e28ca8f74a2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 11:31:12 +0300 Subject: [PATCH 466/689] Fix Ppx_deriving_printable comment indentation --- src/ppx/printable/ppx_deriving_printable.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ppx/printable/ppx_deriving_printable.ml b/src/ppx/printable/ppx_deriving_printable.ml index b8b80d6730..75fd5044fe 100644 --- a/src/ppx/printable/ppx_deriving_printable.ml +++ b/src/ppx/printable/ppx_deriving_printable.ml @@ -12,5 +12,5 @@ let relift_deriving = ReliftDeriver.register () (* TODO: needs https://github.com/ocaml-ppx/ppxlib/pull/124 to include eq, ord, hash *) (* let _ = Ppxlib.Deriving.add_alias "printable" [ - relift_deriving; - ] *) + relift_deriving; + ] *) From d937d68202ff9c4d43721f5439c64c3c4a1a3bbe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 11:53:06 +0300 Subject: [PATCH 467/689] Add options ana.base.invariant.local and ana.base.invariant.global --- src/analyses/base.ml | 42 ++++++++++++++++++++++++++-------- src/config/options.schema.json | 12 ++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index aa11584f53..f9267ba1d0 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1183,6 +1183,9 @@ struct not is_alloc || (is_alloc && not (ctx.ask (Queries.IsHeapVar v))) let query_invariant ctx context = + let keep_local = GobConfig.get_bool "ana.base.invariant.local" in + let keep_global = GobConfig.get_bool "ana.base.invariant.global" in + let cpa = ctx.local.BaseDomain.cpa in let ask = Analyses.ask_of_ctx ctx in @@ -1195,6 +1198,13 @@ struct in let module I = ValueDomain.ValueInvariant (Arg) in + let var_filter v = + if is_global ask v then + keep_global + else + keep_local + in + let var_invariant ?offset v = if not (InvariantCil.var_is_heap v) then I.key_invariant v ?offset (Arg.find v) @@ -1205,14 +1215,23 @@ struct if Lval.Set.is_top context.Invariant.lvals then ( if !earlyglobs || ThreadFlag.has_ever_been_multi ask then ( let cpa_invariant = - CPA.fold (fun k v a -> - if not (is_global ask k) then - Invariant.(a && var_invariant k) - else - a - ) cpa Invariant.none + if keep_local then ( + CPA.fold (fun k v a -> + if not (is_global ask k) then + Invariant.(a && var_invariant k) + else + a + ) cpa Invariant.none + ) + else + Invariant.none + in + let priv_vars = + if keep_global then + Priv.invariant_vars ask (priv_getg ctx.global) ctx.local + else + [] in - let priv_vars = Priv.invariant_vars ask (priv_getg ctx.global) ctx.local in let priv_invariant = List.fold_left (fun acc v -> Invariant.(var_invariant v && acc) @@ -1222,7 +1241,10 @@ struct ) else ( CPA.fold (fun k v a -> - Invariant.(a && var_invariant k) + if var_filter k then + Invariant.(a && var_invariant k) + else + a ) cpa Invariant.none ) ) @@ -1230,7 +1252,7 @@ struct Lval.Set.fold (fun k a -> let i = match k with - | (Var v, offset) when not (InvariantCil.var_is_heap v) -> + | (Var v, offset) when var_filter v && not (InvariantCil.var_is_heap v) -> (try I.key_invariant_lval v ~offset ~lval:k (Arg.find v) with Not_found -> Invariant.none) | _ -> Invariant.none in @@ -1245,7 +1267,7 @@ struct Invariant.none let query_invariant_global ctx g = - if GobConfig.get_bool "ana.base.invariant.enabled" then ( + if GobConfig.get_bool "ana.base.invariant.enabled" && GobConfig.get_bool "ana.base.invariant.global" then ( (* Currently these global invariants are only sound with earlyglobs enabled for both single- and multi-threaded programs. Otherwise, the values of globals in single-threaded mode are not accounted for. They are also made sound without earlyglobs using the multithreaded mode ghost variable. *) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 16c9d7e8ef..7121713c33 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -795,6 +795,18 @@ "type": "boolean", "default": true }, + "local": { + "title": "ana.base.invariant.local", + "description": "Keep local variables in invariants", + "type": "boolean", + "default": true + }, + "global": { + "title": "ana.base.invariant.global", + "description": "Keep global variables in invariants", + "type": "boolean", + "default": true + }, "blobs": { "title": "ana.base.invariant.blobs", "description": "Whether to dump assertions about all blobs. Enabling this option may lead to unsound asserts.", From fbc9e62c8c4ca209759fa2be86ba393c64b51cf4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 11:58:02 +0300 Subject: [PATCH 468/689] Add option ana.var_eq.invariant.enabled --- src/analyses/varEq.ml | 2 +- src/config/options.schema.json | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 8ece99d6e8..db1228a3dd 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -564,7 +564,7 @@ struct let r = eq_set_clos e ctx.local in if M.tracing then M.tracel "var_eq" "equalset %a = %a" d_plainexp e Queries.ES.pretty r; r - | Queries.Invariant context when GobConfig.get_bool "witness.invariant.exact" -> (* only exact equalities here *) + | Queries.Invariant context when GobConfig.get_bool "ana.var_eq.invariant.enabled" && GobConfig.get_bool "witness.invariant.exact" -> (* only exact equalities here *) let scope = Node.find_fundec ctx.node in D.invariant ~scope ctx.local | _ -> Queries.Result.top x diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 7121713c33..d9174b9aa1 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1154,6 +1154,26 @@ } }, "additionalProperties": false + }, + "var_eq": { + "title": "ana.var_eq", + "type": "object", + "properties": { + "invariant": { + "title": "ana.var_eq.invariant", + "type": "object", + "properties": { + "enabled": { + "title": "ana.var_eq.invariant.enabled", + "description": "Generate var_eq analysis invariants", + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } }, "additionalProperties": false From 58aaf53abd7f0d73cd525648256670da1caf2c9e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 12:10:11 +0300 Subject: [PATCH 469/689] Update svcomp-ghost conf --- conf/svcomp-ghost.json | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 108b261322..dc611695dc 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -71,6 +71,27 @@ "base": { "arrays": { "domain": "partitioned" + }, + "invariant": { + "local": false, + "global": true + } + }, + "relation": { + "invariant": { + "local": false, + "global": true, + "one-var": false + } + }, + "apron": { + "invariant": { + "diff-box": true + } + }, + "var_eq": { + "invariant": { + "enabled": false } }, "race": { @@ -123,10 +144,10 @@ ] }, "invariant": { - "loop-head": true, + "loop-head": false, "after-lock": true, - "other": true, - "accessed": true, + "other": false, + "accessed": false, "exact": true, "all-locals": false, "flow_insensitive-as-location": true, From f20ed620a1db2acd88b002b096294d8836ed4c55 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 8 Aug 2024 10:58:13 +0300 Subject: [PATCH 470/689] Re-enable witness.invariant.{loop-head,other} in svcomp-ghost conf for flow-insensitive location invariants to work --- conf/svcomp-ghost.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index dc611695dc..ce308c5e52 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -144,9 +144,9 @@ ] }, "invariant": { - "loop-head": false, + "loop-head": true, "after-lock": true, - "other": false, + "other": true, "accessed": false, "exact": true, "all-locals": false, From e630b744c71f370a746ef1b9955f11efa654523a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 12 Aug 2024 14:20:48 +0300 Subject: [PATCH 471/689] Add backtrace markers around LibraryFunctions special calls (issue #1541) --- src/autoTune.ml | 3 +++ src/cdomain/value/util/wideningThresholds.ml | 1 + src/common/dune | 1 + src/common/util/cilfacade.ml | 8 ++++++++ src/transform/evalAssert.ml | 1 + src/util/loopUnrolling.ml | 1 + src/witness/witnessUtil.ml | 1 + 7 files changed, 16 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index 8ec77739e7..43067b8bbc 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -68,6 +68,7 @@ let functionArgs fd = (ResettableLazy.force functionCallMaps).argLists |> Functi let findMallocWrappers () = let isMalloc f = + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo f) ~finally:Fun.id @@ fun () -> if LibraryFunctions.is_special f then ( let desc = LibraryFunctions.find f in match functionArgs f with @@ -153,6 +154,7 @@ let disableIntervalContextsInRecursiveFunctions () = let hasFunction pred = let relevant_static var = + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo var) ~finally:Fun.id @@ fun () -> if LibraryFunctions.is_special var then let desc = LibraryFunctions.find var in GobOption.exists (fun args -> pred (desc.special args)) (functionArgs var) @@ -160,6 +162,7 @@ let hasFunction pred = false in let relevant_dynamic var = + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo var) ~finally:Fun.id @@ fun () -> if LibraryFunctions.is_special var then let desc = LibraryFunctions.find var in (* We don't really have arguments at hand, so we cheat and just feed it a list of MyCFG.unknown_exp of appropriate length *) diff --git a/src/cdomain/value/util/wideningThresholds.ml b/src/cdomain/value/util/wideningThresholds.ml index 0d93be76ff..42dff238ef 100644 --- a/src/cdomain/value/util/wideningThresholds.ml +++ b/src/cdomain/value/util/wideningThresholds.ml @@ -121,6 +121,7 @@ class extractInvariantsVisitor (exps) = object method! vinst (i: instr) = match i with | Call (_, Lval (Var f, NoOffset), args, _, _) when LibraryFunctions.is_special f -> + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo f) ~finally:Fun.id @@ fun () -> let desc = LibraryFunctions.find f in begin match desc.special args with | Assert { exp; _ } -> diff --git a/src/common/dune b/src/common/dune index 2d6816a00f..e5aeddde7f 100644 --- a/src/common/dune +++ b/src/common/dune @@ -11,6 +11,7 @@ goblint_logs goblint_config goblint_tracing + goblint_backtrace goblint-cil fpath yojson diff --git a/src/common/util/cilfacade.ml b/src/common/util/cilfacade.ml index 99430ee8b6..8cd8c2c53f 100644 --- a/src/common/util/cilfacade.ml +++ b/src/common/util/cilfacade.ml @@ -6,6 +6,14 @@ module E = Errormsg include Cilfacade0 +type Goblint_backtrace.mark += FunVarinfo of varinfo + +let () = Goblint_backtrace.register_mark_printer (function + | FunVarinfo var -> + Some ("function " ^ CilType.Varinfo.show var) + | _ -> None (* for other marks *) + ) + (** Command for assigning an id to a varinfo. All varinfos directly created by Goblint should be modified by this method *) let create_var (var: varinfo) = (* Hack: using negative integers should preempt conflicts with ids generated by CIL *) diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index 0fee26355b..90da794a93 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -44,6 +44,7 @@ struct let is_lock exp args = match exp with | Lval(Var v,_) when LibraryFunctions.is_special v -> + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo v) ~finally:Fun.id @@ fun () -> let desc = LibraryFunctions.find v in (match desc.special args with | Lock _ -> true diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index e433c34b4a..42518708e9 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -311,6 +311,7 @@ class loopUnrollingCallVisitor = object method! vinst = function | Call (_,Lval ((Var info), NoOffset),args,_,_) when LibraryFunctions.is_special info -> ( + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo info) ~finally:Fun.id @@ fun () -> let desc = LibraryFunctions.find info in match desc.special args with | Malloc _ diff --git a/src/witness/witnessUtil.ml b/src/witness/witnessUtil.ml index 5d22fd1e83..c585b21abc 100644 --- a/src/witness/witnessUtil.ml +++ b/src/witness/witnessUtil.ml @@ -63,6 +63,7 @@ struct List.exists (fun (_, edge) -> match edge with | Proc (_, Lval (Var fv, NoOffset), args) when LibraryFunctions.is_special fv -> + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo fv) ~finally:Fun.id @@ fun () -> let desc = LibraryFunctions.find fv in begin match desc.special args with | Lock _ -> true From 476f20be1ad83c0857cd975741683d8e66e2608c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 12 Aug 2024 14:23:59 +0300 Subject: [PATCH 472/689] Fix __printf_chk library function specification (closes #1541) --- src/util/library/libraryFunctions.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index e7ff2a4d04..25a90da2d3 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -712,7 +712,7 @@ let linux_userspace_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__errno", unknown []); ("__errno_location", unknown []); ("__h_errno_location", unknown []); - ("__printf_chk", unknown [drop "flag" []; drop "format" [r]]); + ("__printf_chk", unknown (drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); ("__fprintf_chk", unknown (drop "stream" [r_deep; w_deep] :: drop "flag" [] :: drop "format" [r] :: VarArgs (drop' [r]))); ("__vfprintf_chk", unknown [drop "stream" [r_deep; w_deep]; drop "flag" []; drop "format" [r]; drop "ap" [r_deep]]); ("sysinfo", unknown [drop "info" [w_deep]]); From 4eb58d6be1462f75b113cf87fe63beddb4cce770 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 12 Aug 2024 14:30:38 +0300 Subject: [PATCH 473/689] Add Goblint_backtrace.wrap_val --- src/autoTune.ml | 6 +++--- src/cdomain/value/util/wideningThresholds.ml | 2 +- src/transform/evalAssert.ml | 2 +- src/util/backtrace/goblint_backtrace.ml | 9 +++++++++ src/util/backtrace/goblint_backtrace.mli | 3 +++ src/util/loopUnrolling.ml | 2 +- src/witness/witnessUtil.ml | 2 +- 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 43067b8bbc..a0b57c34e4 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -68,7 +68,7 @@ let functionArgs fd = (ResettableLazy.force functionCallMaps).argLists |> Functi let findMallocWrappers () = let isMalloc f = - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo f) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo f) @@ fun () -> if LibraryFunctions.is_special f then ( let desc = LibraryFunctions.find f in match functionArgs f with @@ -154,7 +154,7 @@ let disableIntervalContextsInRecursiveFunctions () = let hasFunction pred = let relevant_static var = - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo var) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo var) @@ fun () -> if LibraryFunctions.is_special var then let desc = LibraryFunctions.find var in GobOption.exists (fun args -> pred (desc.special args)) (functionArgs var) @@ -162,7 +162,7 @@ let hasFunction pred = false in let relevant_dynamic var = - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo var) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo var) @@ fun () -> if LibraryFunctions.is_special var then let desc = LibraryFunctions.find var in (* We don't really have arguments at hand, so we cheat and just feed it a list of MyCFG.unknown_exp of appropriate length *) diff --git a/src/cdomain/value/util/wideningThresholds.ml b/src/cdomain/value/util/wideningThresholds.ml index 42dff238ef..939ed9482f 100644 --- a/src/cdomain/value/util/wideningThresholds.ml +++ b/src/cdomain/value/util/wideningThresholds.ml @@ -121,7 +121,7 @@ class extractInvariantsVisitor (exps) = object method! vinst (i: instr) = match i with | Call (_, Lval (Var f, NoOffset), args, _, _) when LibraryFunctions.is_special f -> - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo f) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo f) @@ fun () -> let desc = LibraryFunctions.find f in begin match desc.special args with | Assert { exp; _ } -> diff --git a/src/transform/evalAssert.ml b/src/transform/evalAssert.ml index 90da794a93..8f858d09df 100644 --- a/src/transform/evalAssert.ml +++ b/src/transform/evalAssert.ml @@ -44,7 +44,7 @@ struct let is_lock exp args = match exp with | Lval(Var v,_) when LibraryFunctions.is_special v -> - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo v) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo v) @@ fun () -> let desc = LibraryFunctions.find v in (match desc.special args with | Lock _ -> true diff --git a/src/util/backtrace/goblint_backtrace.ml b/src/util/backtrace/goblint_backtrace.ml index 29198c27ea..513753bddb 100644 --- a/src/util/backtrace/goblint_backtrace.ml +++ b/src/util/backtrace/goblint_backtrace.ml @@ -36,6 +36,15 @@ let protect ~(mark: unit -> mark) ~(finally: unit -> unit) work = add_mark work_exn (mark ()); Printexc.raise_with_backtrace work_exn work_bt +(* Copied & modified from protect. *) +let wrap_val ~(mark:mark) work = + try + work () + with work_exn -> + let work_bt = Printexc.get_raw_backtrace () in + add_mark work_exn mark; + Printexc.raise_with_backtrace work_exn work_bt + let mark_printers: (mark -> string option) list ref = ref [] diff --git a/src/util/backtrace/goblint_backtrace.mli b/src/util/backtrace/goblint_backtrace.mli index e2b6ed2913..e53bfd826a 100644 --- a/src/util/backtrace/goblint_backtrace.mli +++ b/src/util/backtrace/goblint_backtrace.mli @@ -24,6 +24,9 @@ val add_mark: exn -> mark -> unit val protect: mark:(unit -> mark) -> finally:(unit -> unit) -> (unit -> 'a) -> 'a (** {!Fun.protect} with additional [~mark] addition to all exceptions. *) +val wrap_val: mark:mark -> (unit -> 'a) -> 'a +(** {!protect} with [~mark] value and without [~finally]. *) + val print_marktrace: out_channel -> exn -> unit (** Print trace of marks of an exception. diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 42518708e9..07c20cb574 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -311,7 +311,7 @@ class loopUnrollingCallVisitor = object method! vinst = function | Call (_,Lval ((Var info), NoOffset),args,_,_) when LibraryFunctions.is_special info -> ( - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo info) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo info) @@ fun () -> let desc = LibraryFunctions.find info in match desc.special args with | Malloc _ diff --git a/src/witness/witnessUtil.ml b/src/witness/witnessUtil.ml index c585b21abc..1526b6f95c 100644 --- a/src/witness/witnessUtil.ml +++ b/src/witness/witnessUtil.ml @@ -63,7 +63,7 @@ struct List.exists (fun (_, edge) -> match edge with | Proc (_, Lval (Var fv, NoOffset), args) when LibraryFunctions.is_special fv -> - Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo fv) ~finally:Fun.id @@ fun () -> + Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo fv) @@ fun () -> let desc = LibraryFunctions.find fv in begin match desc.special args with | Lock _ -> true From 0d6d3a8e5911476875464b7b6c402908453d8323 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 16 Aug 2024 10:19:51 +0300 Subject: [PATCH 474/689] Pin CIL with attr-enumerator fix for MacOS --- goblint.opam | 2 +- goblint.opam.locked | 2 +- goblint.opam.template | 2 +- src/cdomain/value/cdomains/mutexAttrDomain.ml | 2 +- src/incremental/compareAST.ml | 4 ++-- src/witness/witnessUtil.ml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/goblint.opam b/goblint.opam index b73d2c0329..2ed13448f5 100644 --- a/goblint.opam +++ b/goblint.opam @@ -96,7 +96,7 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" ] + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#04b8a45a7d20425c7b6c8abe1ad094abc063922b" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index c629aa6755..a4b9cf6677 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -139,7 +139,7 @@ post-messages: [ pin-depends: [ [ "goblint-cil.2.0.4" - "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" + "git+https://github.com/goblint/cil.git#04b8a45a7d20425c7b6c8abe1ad094abc063922b" ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.template b/goblint.opam.template index bb70aa29e7..9f29ceb7a5 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -2,7 +2,7 @@ # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#317e26d48b06d5cdc4acff3df1a6824587052b53" ] + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#04b8a45a7d20425c7b6c8abe1ad094abc063922b" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/src/cdomain/value/cdomains/mutexAttrDomain.ml b/src/cdomain/value/cdomains/mutexAttrDomain.ml index ea9696d26f..e12818c2c1 100644 --- a/src/cdomain/value/cdomains/mutexAttrDomain.ml +++ b/src/cdomain/value/cdomains/mutexAttrDomain.ml @@ -25,7 +25,7 @@ let recursive_int = lazy ( let res = ref (Z.of_int 2) in (* Use OS X as the default, it doesn't have the enum *) GoblintCil.iterGlobals !Cilfacade.current_file (function | GEnumTag (einfo, _) -> - List.iter (fun (name, exp, _) -> + List.iter (fun (name, _, exp, _) -> if name = "PTHREAD_MUTEX_RECURSIVE" then res := Option.get @@ GoblintCil.getInteger exp ) einfo.eitems diff --git a/src/incremental/compareAST.ml b/src/incremental/compareAST.ml index 2449cdac47..b62cf28f2f 100644 --- a/src/incremental/compareAST.ml +++ b/src/incremental/compareAST.ml @@ -178,8 +178,8 @@ and eq_typ_acc ?(fun_parameter_name_comparison_enabled: bool = true) (a: typ) (b if Messages.tracing then Messages.traceu "compareast" "eq_typ_acc %a vs %a" d_type a d_type b; (r, updated_rename_mapping) -and eq_eitems (a: string * exp * location) (b: string * exp * location) ~(rename_mapping: rename_mapping) ~(acc: (typ * typ) list) = match a, b with - (name1, exp1, _l1), (name2, exp2, _l2) -> (name1 = name2, rename_mapping) &&>> eq_exp exp1 exp2 ~acc +and eq_eitems (a: string * attributes * exp * location) (b: string * attributes * exp * location) ~(rename_mapping: rename_mapping) ~(acc: (typ * typ) list) = match a, b with + (name1, attr1, exp1, _l1), (name2, attr2, exp2, _l2) -> (name1 = name2, rename_mapping) &&>> forward_list_equal (eq_attribute ~acc) attr1 attr2 &&>> eq_exp exp1 exp2 ~acc (* Ignore location *) and eq_enuminfo (a: enuminfo) (b: enuminfo) ~(rename_mapping: rename_mapping) ~(acc: (typ * typ) list) = diff --git a/src/witness/witnessUtil.ml b/src/witness/witnessUtil.ml index 5d22fd1e83..ffadaf14e5 100644 --- a/src/witness/witnessUtil.ml +++ b/src/witness/witnessUtil.ml @@ -209,7 +209,7 @@ struct let typ = TEnum (e, []) in let name = "enum " ^ ename in Hashtbl.replace genv name (Cabs2cil.EnvTyp typ, loc); - List.iter (fun (name, exp, loc) -> + List.iter (fun (name, _, exp, loc) -> Hashtbl.replace genv name (Cabs2cil.EnvEnum (exp, typ), loc) ) eitems | Cil.GVar (v, _, loc) From cf9d190c78d9ebac984ca068cc2c5acbb0ce75cd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 16 Aug 2024 15:44:10 +0300 Subject: [PATCH 475/689] Fix base must-writing all invalidated variables set_many writes one after another, so they all end up in protection privatization's P set for example (although it cannot be observed by precision). Nevertheless, this is the morally correct thing to do: an unknown function may or may not write each argument. --- src/analyses/base.ml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 4e523fe1ee..a69b3a2b23 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2045,7 +2045,7 @@ struct List.map mpt exps ) - let invalidate ?(deep=true) ~ctx (st:store) (exps: exp list): store = + let invalidate ~(must: bool) ?(deep=true) ~ctx (st:store) (exps: exp list): store = if M.tracing && exps <> [] then M.tracel "invalidate" "Will invalidate expressions [%a]" (d_list ", " d_plainexp) exps; if exps <> [] then M.info ~category:Imprecise "Invalidating expressions: %a" (d_list ", " d_exp) exps; (* To invalidate a single address, we create a pair with its corresponding @@ -2072,7 +2072,15 @@ struct let vs = List.map (Tuple3.third) invalids' in M.tracel "invalidate" "Setting addresses [%a] to values [%a]" (d_list ", " AD.pretty) addrs (d_list ", " VD.pretty) vs ); - set_many ~ctx st invalids' + (* copied from set_many *) + let f (acc: store) ((lval:AD.t),(typ:Cil.typ),(value:value)): store = + let acc' = set ~ctx acc lval typ value in + if must then + acc' + else + D.join acc acc' + in + List.fold_left f st invalids' let make_entry ?(thread=false) (ctx:(D.t, G.t, C.t, V.t) Analyses.ctx) fundec args: D.t = @@ -2211,8 +2219,8 @@ struct in (* TODO: what about escaped local variables? *) (* invalidate arguments and non-static globals for unknown functions *) - let st' = invalidate ~deep:false ~ctx ctx.local shallow_addrs in - invalidate ~deep:true ~ctx st' deep_addrs + let st' = invalidate ~must:false ~deep:false ~ctx ctx.local shallow_addrs in + invalidate ~must:false ~deep:true ~ctx st' deep_addrs let check_invalid_mem_dealloc ctx special_fn ptr = let has_non_heap_var = AD.exists (function @@ -2302,7 +2310,7 @@ struct let invalidate_ret_lv st = match lv with | Some lv -> if M.tracing then M.tracel "invalidate" "Invalidating lhs %a for function call %s" d_plainlval lv f.vname; - invalidate ~deep:false ~ctx st [Cil.mkAddrOrStartOf lv] + invalidate ~must:true ~deep:false ~ctx st [Cil.mkAddrOrStartOf lv] | None -> st in let addr_type_of_exp exp = @@ -2636,14 +2644,14 @@ struct | Int n when GobOption.exists (Z.equal Z.zero) (ID.to_int n) -> st | Address ret_a -> begin match eval_rv ~ctx st id with - | Thread a when ValueDomain.Threads.is_top a -> invalidate ~ctx st [ret_var] + | Thread a when ValueDomain.Threads.is_top a -> invalidate ~must:true ~ctx st [ret_var] | Thread a -> let v = List.fold VD.join (VD.bot ()) (List.map (fun x -> G.thread (ctx.global (V.thread x))) (ValueDomain.Threads.elements a)) in (* TODO: is this type right? *) set ~ctx st ret_a (Cilfacade.typeOf ret_var) v - | _ -> invalidate ~ctx st [ret_var] + | _ -> invalidate ~must:true ~ctx st [ret_var] end - | _ -> invalidate ~ctx st [ret_var] + | _ -> invalidate ~must:true ~ctx st [ret_var] in let st' = invalidate_ret_lv st' in Priv.thread_join (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) id st' From 9c604183f6bd7765fba521dbb7da7efcb9cdf129 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 11:37:34 +0300 Subject: [PATCH 476/689] Add YAML witness ghost_instrumentation entry type --- src/config/options.schema.json | 3 +- src/witness/yamlWitness.ml | 25 +++++++++ src/witness/yamlWitnessType.ml | 99 ++++++++++++++++++++++++++++++++++ tests/util/yamlWitnessStrip.ml | 5 ++ 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 424992c3de..06b6f26359 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2648,7 +2648,8 @@ "precondition_loop_invariant_certificate", "invariant_set", "ghost_variable", - "ghost_update" + "ghost_update", + "ghost_instrumentation" ] }, "default": [ diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index d3988f8edb..cc435a38ac 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -160,6 +160,31 @@ struct }; metadata = metadata ~task (); } + + let ghost_variable' ~variable ~type_ ~(initial): GhostInstrumentation.Variable.t = { + name = variable; + scope = "global"; + type_; + initial; + } + + let ghost_update' ~variable ~(expression): GhostInstrumentation.Update.t = { + ghost_variable = variable; + expression; + } + + let ghost_location_update' ~location ~(updates): GhostInstrumentation.LocationUpdate.t = { + location; + updates; + } + + let ghost_instrumentation ~task ~variables ~(location_updates): Entry.t = { + entry_type = GhostInstrumentation { + ghost_variables = variables; + ghost_updates = location_updates; + }; + metadata = metadata ~task (); + } end let yaml_entries_to_file yaml_entries file = diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 4bdb730b82..72afbf432b 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -485,6 +485,99 @@ struct {variable; expression; location} end +module GhostInstrumentation = +struct + + module Variable = + struct + type t = { + name: string; + scope: string; + type_: string; + initial: string; + } + [@@deriving eq, ord, hash] + + let to_yaml {name; scope; type_; initial} = + `O [ + ("name", `String name); + ("scope", `String scope); + ("type", `String type_); + ("initial", `String initial); + ] + + let of_yaml y = + let open GobYaml in + let+ name = y |> find "name" >>= to_string + and+ scope = y |> find "scope" >>= to_string + and+ type_ = y |> find "type" >>= to_string + and+ initial = y |> find "initial" >>= to_string in + {name; scope; type_; initial} + end + + module Update = + struct + type t = { + ghost_variable: string; + expression: string; + } + [@@deriving eq, ord, hash] + + let to_yaml {ghost_variable; expression} = + `O [ + ("ghost_variable", `String ghost_variable); + ("expression", `String expression); + ] + + let of_yaml y = + let open GobYaml in + let+ ghost_variable = y |> find "ghost_variable" >>= to_string + and+ expression = y |> find "expression" >>= to_string in + {ghost_variable; expression} + end + + module LocationUpdate = + struct + type t = { + location: Location.t; + updates: Update.t list; + } + [@@deriving eq, ord, hash] + + let to_yaml {location; updates} = + `O [ + ("location", Location.to_yaml location); + ("updates", `A (List.map Update.to_yaml updates)); + ] + + let of_yaml y = + let open GobYaml in + let+ location = y |> find "location" >>= Location.of_yaml + and+ updates = y |> find "updates" >>= list >>= list_map Update.of_yaml in + {location; updates} + end + + type t = { + ghost_variables: Variable.t list; + ghost_updates: LocationUpdate.t list; + } + [@@deriving eq, ord, hash] + + let entry_type = "ghost_instrumentation" + + let to_yaml' {ghost_variables; ghost_updates} = + [ + ("ghost_variables", `A (List.map Variable.to_yaml ghost_variables)); + ("ghost_updates", `A (List.map LocationUpdate.to_yaml ghost_updates)); + ] + + let of_yaml y = + let open GobYaml in + let+ ghost_variables = y |> find "ghost_variables" >>= list >>= list_map Variable.of_yaml + and+ ghost_updates = y |> find "ghost_updates" >>= list >>= list_map LocationUpdate.of_yaml in + {ghost_variables; ghost_updates} +end + (* TODO: could maybe use GADT, but adds ugly existential layer to entry type pattern matching *) module EntryType = struct @@ -498,6 +591,7 @@ struct | InvariantSet of InvariantSet.t | GhostVariable of GhostVariable.t | GhostUpdate of GhostUpdate.t + | GhostInstrumentation of GhostInstrumentation.t [@@deriving eq, ord, hash] let entry_type = function @@ -510,6 +604,7 @@ struct | InvariantSet _ -> InvariantSet.entry_type | GhostVariable _ -> GhostVariable.entry_type | GhostUpdate _ -> GhostUpdate.entry_type + | GhostInstrumentation _ -> GhostInstrumentation.entry_type let to_yaml' = function | LocationInvariant x -> LocationInvariant.to_yaml' x @@ -521,6 +616,7 @@ struct | InvariantSet x -> InvariantSet.to_yaml' x | GhostVariable x -> GhostVariable.to_yaml' x | GhostUpdate x -> GhostUpdate.to_yaml' x + | GhostInstrumentation x -> GhostInstrumentation.to_yaml' x let of_yaml y = let open GobYaml in @@ -552,6 +648,9 @@ struct else if entry_type = GhostUpdate.entry_type then let+ x = y |> GhostUpdate.of_yaml in GhostUpdate x + else if entry_type = GhostInstrumentation.entry_type then + let+ x = y |> GhostInstrumentation.of_yaml in + GhostInstrumentation x else Error (`Msg ("entry_type " ^ entry_type)) end diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 211a8a0e1a..4d7b446bab 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -26,6 +26,9 @@ struct in {invariant_type} in + let ghost_location_update_strip_file_hash (x: GhostInstrumentation.LocationUpdate.t): GhostInstrumentation.LocationUpdate.t = + {x with location = location_strip_file_hash x.location} + in let entry_type: EntryType.t = match entry_type with | LocationInvariant x -> @@ -46,6 +49,8 @@ struct GhostVariable x (* no location to strip *) | GhostUpdate x -> GhostUpdate {x with location = location_strip_file_hash x.location} + | GhostInstrumentation x -> + GhostInstrumentation {x with ghost_updates = List.map ghost_location_update_strip_file_hash x.ghost_updates} in {entry_type} From d22065396f057689adf10ee950d623fb999bc4b7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 12:27:58 +0300 Subject: [PATCH 477/689] Add ghost_instrumentation support to mutexGhosts --- src/analyses/mutexGhosts.ml | 84 ++++++++++++++++++++-- src/witness/witnessGhost.ml | 22 +++++- tests/regression/13-privatized/74-mutex.t | 87 +++++++++++++++++++++++ 3 files changed, 186 insertions(+), 7 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 7bc4423f04..09afc41baa 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -10,17 +10,19 @@ struct include UnitAnalysis.Spec let name () = "mutexGhosts" - module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) + (* module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) *) module V = struct - include Printable.Either3 (Node) (LockDomain.MustLock) (ThreadCreate) + include Printable.Either3 (Node) (LockDomain.MustLock) (BoolDomain.Bool) let node x = `Left x let lock x = `Middle x - let threadcreate = `Right () + let threadcreate = `Right false + let update = `Right true let is_write_only = function | `Left _ -> false | `Middle _ -> true - | `Right _ -> false + | `Right false -> false + | `Right true -> true end module Locked = @@ -53,9 +55,11 @@ struct | `Bot -> NodeSet.bot () | `Lifted2 (`Lifted2 x) -> x | _ -> failwith "MutexGhosts.threadcreate" + let update = threadcreate let create_node node = `Lifted1 node let create_lock lock = `Lifted2 (`Lifted1 lock) let create_threadcreate threadcreate = `Lifted2 (`Lifted2 threadcreate) + let create_update = create_threadcreate end let mustlock_of_addr (addr: LockDomain.Addr.t): LockDomain.MustLock.t option = @@ -69,6 +73,7 @@ struct | Events.Lock (l, _) when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); if !AnalysisState.postsolving then ( + ctx.sideg V.update (G.create_update (NodeSet.singleton ctx.prev_node)); let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal locked > 1 then ( Locked.iter (fun lock -> @@ -81,6 +86,7 @@ struct | Events.Unlock l when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); if !AnalysisState.postsolving then ( + ctx.sideg V.update (G.create_update (NodeSet.singleton ctx.prev_node)); let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal unlocked > 1 then ( Locked.iter (fun lock -> @@ -91,7 +97,9 @@ struct ); ) | Events.EnterMultiThreaded -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)); + if !AnalysisState.postsolving then + ctx.sideg V.update (G.create_update (NodeSet.singleton ctx.prev_node)); | _ -> () end; ctx.local @@ -113,7 +121,7 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with - | `Left g' -> + | `Left g' when YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type -> let (locked, unlocked, multithread) = G.node (ctx.global g) in let g = g' in let entries = @@ -161,6 +169,70 @@ struct entries in entries + | `Right true when YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type -> + let nodes = G.update (ctx.global g) in + let (variables, location_updates) = NodeSet.fold (fun node (variables, location_updates) -> + let (locked, unlocked, multithread) = G.node (ctx.global (V.node node)) in + let variables' = + (* TODO: do variable_entry-s only once *) + Locked.fold (fun l acc -> + match mustlock_of_addr l with + | Some l when ghost_var_available ctx (Locked l) -> + let variable = WitnessGhost.variable' (Locked l) in + if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable acc then (* TODO: be efficient *) + acc + else + variable :: acc + | _ -> + acc + ) (Locked.union locked unlocked) variables + in + let updates = + Locked.fold (fun l acc -> + match mustlock_of_addr l with + | Some l when ghost_var_available ctx (Locked l) -> + let update = WitnessGhost.update' (Locked l) GoblintCil.one in + update :: acc + | _ -> + acc + ) locked [] + in + let updates = + Unlocked.fold (fun l acc -> + match mustlock_of_addr l with + | Some l when ghost_var_available ctx (Locked l) -> + let update = WitnessGhost.update' (Locked l) GoblintCil.zero in + update :: acc + | _ -> + acc + ) unlocked updates + in + let (variables', updates) = + if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( + if ghost_var_available ctx Multithreaded then ( + let variable = WitnessGhost.variable' Multithreaded in + let update = WitnessGhost.update' Multithreaded GoblintCil.one in + let variables' = + if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable variables' then (* TODO: be efficient *) + variables' + else + variable :: variables' + in + (variables', update :: updates) + ) + else + (variables', updates) + ) + else + (variables', updates) + in + let location_update = WitnessGhost.location_update' ~node ~updates in + (variables', location_update :: location_updates) + ) nodes ([], []) + in + let entry = WitnessGhost.instrumentation_entry ~task ~variables ~location_updates in + Queries.YS.singleton entry + | `Left _ -> Queries.Result.top q | `Middle _ -> Queries.Result.top q | `Right _ -> Queries.Result.top q end diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 91d513ceae..3535e8a347 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,7 +1,7 @@ (** Ghost variables for YAML witnesses. *) let enabled () = - YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type + (YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type module Var = WitnessGhostVar @@ -24,3 +24,23 @@ let update_entry ~task ~node x e = let variable = name_varinfo x in let expression = CilType.Exp.show e in YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression + +let variable' x = + let variable = name_varinfo x in + let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) + let initial = CilType.Exp.show (initial x) in + YamlWitness.Entry.ghost_variable' ~variable ~type_ ~initial + +let update' x e = + let variable = name_varinfo x in + let expression = CilType.Exp.show e in + YamlWitness.Entry.ghost_update' ~variable ~expression + +let location_update' ~node ~updates = + let loc = Node.location node in + let location_function = (Node.find_fundec node).svar.vname in + let location = YamlWitness.Entry.location ~location:loc ~location_function in + YamlWitness.Entry.ghost_location_update' ~location ~updates + +let instrumentation_entry ~task ~variables ~location_updates = + YamlWitness.Entry.ghost_instrumentation ~task ~variables ~location_updates diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 8999d394ec..eec046bcb6 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -148,6 +148,93 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm unsafe: 0 total memory locations: 1 +Same with ghost_instrumentation entry. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 3 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_instrumentation + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: "0" + - name: m_locked + scope: global + type: int + initial: "0" + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - ghost_variable: m_locked + expression: "0" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - ghost_variable: m_locked + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - ghost_variable: multithreaded + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - ghost_variable: m_locked + expression: "0" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - ghost_variable: m_locked + expression: "1" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_locked || used == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= used && used <= 1)' + type: assertion + format: C + Same with mutex-meet. $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c From f79ad180cc9bb3ff2b00b73fcda4368718b8f307 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 12:53:28 +0300 Subject: [PATCH 478/689] Add option for emitting flow_insensitive_invariant-s as invariant_set location_invariant-s in YAML witnesses --- conf/svcomp-ghost.json | 2 +- src/config/options.schema.json | 9 ++-- src/witness/yamlWitness.ml | 52 ++++++++++++++++--- .../regression/13-privatized/04-priv_multi.t | 2 +- tests/regression/13-privatized/74-mutex.t | 40 +++++++++----- 5 files changed, 77 insertions(+), 28 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index ce308c5e52..c4f165960d 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -150,7 +150,7 @@ "accessed": false, "exact": true, "all-locals": false, - "flow_insensitive-as-location": true, + "flow_insensitive-as": "location_invariant", "exclude-vars": [ "tmp\\(___[0-9]+\\)?", "cond", diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 06b6f26359..11df177cd3 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2604,11 +2604,12 @@ "type": "boolean", "default": true }, - "flow_insensitive-as-location": { - "title": "witness.invariant.flow_insensitive-as-location", + "flow_insensitive-as": { + "title": "witness.invariant.flow_insensitive-as", "description": "Emit flow-insensitive invariants as location invariants at certain locations.", - "type": "boolean", - "default": false + "type": "string", + "enum": ["flow_insensitive_invariant", "location_invariant", "invariant_set-location_invariant"], + "default": "flow_insensitive_invariant" } }, "additionalProperties": false diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index cc435a38ac..c8217bde19 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -347,22 +347,23 @@ struct entries in + let invariant_global_nodes = lazy (R.ask_global InvariantGlobalNodes) in + (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( - let ns = lazy (R.ask_global InvariantGlobalNodes) in GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) - begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_bool "witness.invariant.flow_insensitive-as-location" with - | `Lifted inv, false -> + begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_string "witness.invariant.flow_insensitive-as" with + | `Lifted inv, "flow_insensitive_invariant" -> let invs = WitnessUtil.InvariantExp.process_exp inv in List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.flow_insensitive_invariant ~task ~invariant in entry :: acc ) acc invs - | `Lifted inv, true -> + | `Lifted inv, "location_invariant" -> (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) let invs = WitnessUtil.InvariantExp.process_exp inv in Queries.NS.fold (fun n acc -> @@ -377,7 +378,8 @@ struct entry :: acc ) acc invs | None -> acc - ) (Lazy.force ns) acc + ) (Lazy.force invariant_global_nodes) acc + | `Lifted _, _ | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end @@ -516,12 +518,12 @@ struct (* Generate invariant set *) let entries = - if entry_type_enabled YamlWitnessType.InvariantSet.entry_type then ( + if entry_type_enabled YamlWitnessType.InvariantSet.entry_type || entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type && GobConfig.get_string "witness.invariant.flow_insensitive-as" = "invariant_set-location_invariant" then ( let invariants = [] in (* Generate location invariants *) let invariants = - if invariant_type_enabled YamlWitnessType.InvariantSet.LocationInvariant.invariant_type then ( + if entry_type_enabled YamlWitnessType.InvariantSet.entry_type && invariant_type_enabled YamlWitnessType.InvariantSet.LocationInvariant.invariant_type then ( LH.fold (fun loc ns acc -> let inv = List.fold_left (fun acc n -> let local = try NH.find (Lazy.force nh) n with Not_found -> Spec.D.bot () in @@ -550,7 +552,7 @@ struct (* Generate loop invariants *) let invariants = - if invariant_type_enabled YamlWitnessType.InvariantSet.LoopInvariant.invariant_type then ( + if entry_type_enabled YamlWitnessType.InvariantSet.entry_type && invariant_type_enabled YamlWitnessType.InvariantSet.LoopInvariant.invariant_type then ( LH.fold (fun loc ns acc -> if WitnessInvariant.emit_loop_head then ( (* TODO: remove double condition? *) let inv = List.fold_left (fun acc n -> @@ -580,6 +582,40 @@ struct invariants in + (* Generate flow-insensitive invariants as location invariants *) + let invariants = + if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type && GobConfig.get_string "witness.invariant.flow_insensitive-as" = "invariant_set-location_invariant" then ( + GHT.fold (fun g v acc -> + match g with + | `Left g -> (* Spec global *) + begin match R.ask_global (InvariantGlobal (Obj.repr g)) with + | `Lifted inv -> + (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + let invs = WitnessUtil.InvariantExp.process_exp inv in + Queries.NS.fold (fun n acc -> + let fundec = Node.find_fundec n in + match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + | Some loc -> + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + let invariant = CilType.Exp.show inv in + let invariant = Entry.location_invariant' ~location ~invariant in + invariant :: acc + ) acc invs + | None -> acc + ) (Lazy.force invariant_global_nodes) acc + | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) + acc + end + | `Right _ -> (* contexts global *) + acc + ) gh invariants + ) + else + invariants + in + let invariants = List.rev invariants in let entry = Entry.invariant_set ~task ~invariants in entry :: entries diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index b1a45dd917..fd0dad6a39 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -174,7 +174,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index eec046bcb6..c99cdb6ff9 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -84,7 +84,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -148,9 +148,9 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm unsafe: 0 total memory locations: 1 -Same with ghost_instrumentation entry. +Same with ghost_instrumentation and invariant_set entries. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' --set witness.invariant.flow_insensitive-as invariant_set-location_invariant 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -160,7 +160,7 @@ Same with ghost_instrumentation entry. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -224,16 +224,28 @@ Same with ghost_instrumentation entry. updates: - ghost_variable: m_locked expression: "1" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m_locked || used == 0)' - type: assertion - format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (0 <= used && used <= 1)' - type: assertion - format: C + - entry_type: invariant_set + content: + - invariant: + type: location_invariant + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + value: '! multithreaded || (m_locked || used == 0)' + format: c_expression + - invariant: + type: location_invariant + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + value: '! multithreaded || (0 <= used && used <= 1)' + format: c_expression Same with mutex-meet. From e9e652d86cac07bdff43780fbe5467fe46870265 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 12:56:26 +0300 Subject: [PATCH 479/689] Use invariant_set in svcomp-ghost conf --- conf/svcomp-ghost.json | 7 +++---- src/config/options.schema.json | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index c4f165960d..cb4d8f1384 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -136,11 +136,10 @@ }, "yaml": { "enabled": true, - "format-version": "0.1", + "format-version": "2.1", "entry-types": [ "flow_insensitive_invariant", - "ghost_variable", - "ghost_update" + "ghost_instrumentation" ] }, "invariant": { @@ -150,7 +149,7 @@ "accessed": false, "exact": true, "all-locals": false, - "flow_insensitive-as": "location_invariant", + "flow_insensitive-as": "invariant_set-location_invariant", "exclude-vars": [ "tmp\\(___[0-9]+\\)?", "cond", diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 11df177cd3..1101e04ace 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2630,7 +2630,8 @@ "type": "string", "enum": [ "0.1", - "2.0" + "2.0", + "2.1" ], "default": "0.1" }, From 431b34d18d12ef588c67a170f4a139665e73720c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 15:02:07 +0300 Subject: [PATCH 480/689] Make invariant_set and ghost_instrumentation deterministic in tests --- tests/regression/13-privatized/74-mutex.t | 40 +++++++++++------------ tests/util/yamlWitnessStrip.ml | 12 +++++-- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index c99cdb6ff9..0c2947ab37 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -170,11 +170,11 @@ Same with ghost_instrumentation and invariant_set entries. $ yamlWitnessStrip < witness.yml - entry_type: ghost_instrumentation ghost_variables: - - name: multithreaded + - name: m_locked scope: global type: int initial: "0" - - name: m_locked + - name: multithreaded scope: global type: int initial: "0" @@ -182,21 +182,21 @@ Same with ghost_instrumentation and invariant_set entries. - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 38 - column: 3 - function: main + line: 20 + column: 5 + function: producer updates: - ghost_variable: m_locked - expression: "0" + expression: "1" - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 36 - column: 3 - function: main + line: 23 + column: 5 + function: producer updates: - ghost_variable: m_locked - expression: "1" + expression: "0" - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -209,21 +209,21 @@ Same with ghost_instrumentation and invariant_set entries. - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer + line: 36 + column: 3 + function: main updates: - ghost_variable: m_locked - expression: "0" + expression: "1" - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer + line: 38 + column: 3 + function: main updates: - ghost_variable: m_locked - expression: "1" + expression: "0" - entry_type: invariant_set content: - invariant: @@ -234,7 +234,7 @@ Same with ghost_instrumentation and invariant_set entries. line: 36 column: 3 function: main - value: '! multithreaded || (m_locked || used == 0)' + value: '! multithreaded || (0 <= used && used <= 1)' format: c_expression - invariant: type: location_invariant @@ -244,7 +244,7 @@ Same with ghost_instrumentation and invariant_set entries. line: 36 column: 3 function: main - value: '! multithreaded || (0 <= used && used <= 1)' + value: '! multithreaded || (m_locked || used == 0)' format: c_expression Same with mutex-meet. diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 4d7b446bab..dff8bfb0cf 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -27,7 +27,10 @@ struct {invariant_type} in let ghost_location_update_strip_file_hash (x: GhostInstrumentation.LocationUpdate.t): GhostInstrumentation.LocationUpdate.t = - {x with location = location_strip_file_hash x.location} + { + location = location_strip_file_hash x.location; + updates = List.sort GhostInstrumentation.Update.compare x.updates + } in let entry_type: EntryType.t = match entry_type with @@ -44,13 +47,16 @@ struct | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate {x with target = target_strip_file_hash x.target} | InvariantSet x -> - InvariantSet {content = List.map invariant_strip_file_hash x.content} + InvariantSet {content = List.sort InvariantSet.Invariant.compare (List.map invariant_strip_file_hash x.content)} (* Sort, so order is deterministic regardless of Goblint. *) | GhostVariable x -> GhostVariable x (* no location to strip *) | GhostUpdate x -> GhostUpdate {x with location = location_strip_file_hash x.location} | GhostInstrumentation x -> - GhostInstrumentation {x with ghost_updates = List.map ghost_location_update_strip_file_hash x.ghost_updates} + GhostInstrumentation { (* Sort, so order is deterministic regardless of Goblint. *) + ghost_variables = List.sort GhostInstrumentation.Variable.compare x.ghost_variables; + ghost_updates = List.sort GhostInstrumentation.LocationUpdate.compare (List.map ghost_location_update_strip_file_hash x.ghost_updates); + } in {entry_type} From 3c54188f07c43816d016e95da96255a57e135e39 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 22 Aug 2024 16:15:29 +0300 Subject: [PATCH 481/689] Default location.byte to -1 if missing in JSON --- src/common/util/cilType.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/util/cilType.ml b/src/common/util/cilType.ml index 5a473b7d60..91368052b3 100644 --- a/src/common/util/cilType.ml +++ b/src/common/util/cilType.ml @@ -79,8 +79,8 @@ struct let of_yojson = function | `Assoc l -> - begin match List.assoc_opt "file" l, List.assoc_opt "line" l, List.assoc_opt "column" l, List.assoc_opt "byte" l with - | Some (`String file), Some (`Int line), Some (`Int column), Some (`Int byte) -> + begin match List.assoc_opt "file" l, List.assoc_opt "line" l, List.assoc_opt "column" l, Option.value ~default:(`Int (-1)) (List.assoc_opt "byte" l) with + | Some (`String file), Some (`Int line), Some (`Int column), `Int byte -> let loc = {file; line; column; byte; endLine = -1; endColumn = -1; endByte = -1; synthetic = false} in begin match List.assoc_opt "endLine" l, List.assoc_opt "endColumn" l, List.assoc_opt "endByte" l with | Some (`Int endLine), Some (`Int endColumn), Some (`Int endByte) -> From 2c9955048a13c162fcf74f7ccd67d614c73e3ee5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Aug 2024 17:25:23 +0300 Subject: [PATCH 482/689] Remove ghost_ prefix from ghost_instrumentation update entries --- src/witness/yamlWitness.ml | 2 +- src/witness/yamlWitnessType.ml | 10 +++++----- tests/regression/13-privatized/74-mutex.t | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index c8217bde19..c917361d9b 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -169,7 +169,7 @@ struct } let ghost_update' ~variable ~(expression): GhostInstrumentation.Update.t = { - ghost_variable = variable; + variable; expression; } diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 72afbf432b..cefb0866f3 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -518,22 +518,22 @@ struct module Update = struct type t = { - ghost_variable: string; + variable: string; expression: string; } [@@deriving eq, ord, hash] - let to_yaml {ghost_variable; expression} = + let to_yaml {variable; expression} = `O [ - ("ghost_variable", `String ghost_variable); + ("variable", `String variable); ("expression", `String expression); ] let of_yaml y = let open GobYaml in - let+ ghost_variable = y |> find "ghost_variable" >>= to_string + let+ variable = y |> find "variable" >>= to_string and+ expression = y |> find "expression" >>= to_string in - {ghost_variable; expression} + {variable; expression} end module LocationUpdate = diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 0c2947ab37..9a11b6846f 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -186,7 +186,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 5 function: producer updates: - - ghost_variable: m_locked + - variable: m_locked expression: "1" - location: file_name: 74-mutex.c @@ -195,7 +195,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 5 function: producer updates: - - ghost_variable: m_locked + - variable: m_locked expression: "0" - location: file_name: 74-mutex.c @@ -204,7 +204,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 3 function: main updates: - - ghost_variable: multithreaded + - variable: multithreaded expression: "1" - location: file_name: 74-mutex.c @@ -213,7 +213,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 3 function: main updates: - - ghost_variable: m_locked + - variable: m_locked expression: "1" - location: file_name: 74-mutex.c @@ -222,7 +222,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 3 function: main updates: - - ghost_variable: m_locked + - variable: m_locked expression: "0" - entry_type: invariant_set content: From 12dadf4f03c8ff9d3e4a1546235722066018fd40 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 2 Sep 2024 11:03:57 +0300 Subject: [PATCH 483/689] Wrap ghost_instrumentation in content --- src/witness/yamlWitnessType.ml | 13 ++- tests/regression/13-privatized/74-mutex.t | 111 +++++++++++----------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index cefb0866f3..b04a2c35bf 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -566,15 +566,18 @@ struct let entry_type = "ghost_instrumentation" let to_yaml' {ghost_variables; ghost_updates} = - [ - ("ghost_variables", `A (List.map Variable.to_yaml ghost_variables)); - ("ghost_updates", `A (List.map LocationUpdate.to_yaml ghost_updates)); + [("content", + `O [ + ("ghost_variables", `A (List.map Variable.to_yaml ghost_variables)); + ("ghost_updates", `A (List.map LocationUpdate.to_yaml ghost_updates)); + ]) ] let of_yaml y = let open GobYaml in - let+ ghost_variables = y |> find "ghost_variables" >>= list >>= list_map Variable.of_yaml - and+ ghost_updates = y |> find "ghost_updates" >>= list >>= list_map LocationUpdate.of_yaml in + let* content = y |> find "content" in + let+ ghost_variables = content |> find "ghost_variables" >>= list >>= list_map Variable.of_yaml + and+ ghost_updates = content |> find "ghost_updates" >>= list >>= list_map LocationUpdate.of_yaml in {ghost_variables; ghost_updates} end diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 9a11b6846f..478921155e 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -169,61 +169,62 @@ Same with ghost_instrumentation and invariant_set entries. $ yamlWitnessStrip < witness.yml - entry_type: ghost_instrumentation - ghost_variables: - - name: m_locked - scope: global - type: int - initial: "0" - - name: multithreaded - scope: global - type: int - initial: "0" - ghost_updates: - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer - updates: - - variable: m_locked - expression: "1" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer - updates: - - variable: m_locked - expression: "0" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 34 - column: 3 - function: main - updates: - - variable: multithreaded - expression: "1" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 36 - column: 3 - function: main - updates: - - variable: m_locked - expression: "1" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 38 - column: 3 - function: main - updates: - - variable: m_locked - expression: "0" + content: + ghost_variables: + - name: m_locked + scope: global + type: int + initial: "0" + - name: multithreaded + scope: global + type: int + initial: "0" + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - variable: m_locked + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - variable: m_locked + expression: "0" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - variable: multithreaded + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - variable: m_locked + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - variable: m_locked + expression: "0" - entry_type: invariant_set content: - invariant: From 852297b68abbcb05c3f3700098e2bc2f22c93333 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 2 Sep 2024 11:10:31 +0300 Subject: [PATCH 484/689] Add value and format to ghost_instrumentation --- src/witness/yamlWitness.ml | 8 +++-- src/witness/yamlWitnessType.ml | 40 ++++++++++++++++++----- tests/regression/13-privatized/74-mutex.t | 23 +++++++++---- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index c917361d9b..f8890d8eaa 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -165,12 +165,16 @@ struct name = variable; scope = "global"; type_; - initial; + initial = { + value = initial; + format = "c_expression"; + }; } let ghost_update' ~variable ~(expression): GhostInstrumentation.Update.t = { variable; - expression; + value = expression; + format = "c_expression"; } let ghost_location_update' ~location ~(updates): GhostInstrumentation.LocationUpdate.t = { diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index b04a2c35bf..7834951892 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -488,13 +488,34 @@ end module GhostInstrumentation = struct + module Initial = + struct + type t = { + value: string; + format: string; + } + [@@deriving eq, ord, hash] + + let to_yaml {value; format} = + `O [ + ("value", `String value); + ("format", `String format); + ] + + let of_yaml y = + let open GobYaml in + let+ value = y |> find "value" >>= to_string + and+ format = y |> find "format" >>= to_string in + {value; format} + end + module Variable = struct type t = { name: string; scope: string; type_: string; - initial: string; + initial: Initial.t; } [@@deriving eq, ord, hash] @@ -503,7 +524,7 @@ struct ("name", `String name); ("scope", `String scope); ("type", `String type_); - ("initial", `String initial); + ("initial", Initial.to_yaml initial); ] let of_yaml y = @@ -511,7 +532,7 @@ struct let+ name = y |> find "name" >>= to_string and+ scope = y |> find "scope" >>= to_string and+ type_ = y |> find "type" >>= to_string - and+ initial = y |> find "initial" >>= to_string in + and+ initial = y |> find "initial" >>= Initial.of_yaml in {name; scope; type_; initial} end @@ -519,21 +540,24 @@ struct struct type t = { variable: string; - expression: string; + value: string; + format: string; } [@@deriving eq, ord, hash] - let to_yaml {variable; expression} = + let to_yaml {variable; value; format} = `O [ ("variable", `String variable); - ("expression", `String expression); + ("value", `String value); + ("format", `String format); ] let of_yaml y = let open GobYaml in let+ variable = y |> find "variable" >>= to_string - and+ expression = y |> find "expression" >>= to_string in - {variable; expression} + and+ value = y |> find "value" >>= to_string + and+ format = y |> find "format" >>= to_string in + {variable; value; format} end module LocationUpdate = diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 478921155e..8a1a7fee5f 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -174,11 +174,15 @@ Same with ghost_instrumentation and invariant_set entries. - name: m_locked scope: global type: int - initial: "0" + initial: + value: "0" + format: c_expression - name: multithreaded scope: global type: int - initial: "0" + initial: + value: "0" + format: c_expression ghost_updates: - location: file_name: 74-mutex.c @@ -188,7 +192,8 @@ Same with ghost_instrumentation and invariant_set entries. function: producer updates: - variable: m_locked - expression: "1" + value: "1" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -197,7 +202,8 @@ Same with ghost_instrumentation and invariant_set entries. function: producer updates: - variable: m_locked - expression: "0" + value: "0" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -206,7 +212,8 @@ Same with ghost_instrumentation and invariant_set entries. function: main updates: - variable: multithreaded - expression: "1" + value: "1" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -215,7 +222,8 @@ Same with ghost_instrumentation and invariant_set entries. function: main updates: - variable: m_locked - expression: "1" + value: "1" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -224,7 +232,8 @@ Same with ghost_instrumentation and invariant_set entries. function: main updates: - variable: m_locked - expression: "0" + value: "0" + format: c_expression - entry_type: invariant_set content: - invariant: From b148e207ed7df3b65727ec504db3cf1e90442258 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 20 Sep 2024 17:11:37 +0200 Subject: [PATCH 485/689] Modularize out details of the current approach --- src/framework/constraints.ml | 64 ++++++++++++++++++++++++++---------- src/framework/control.ml | 2 +- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 7df4167acd..ef84326be4 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -513,10 +513,41 @@ struct let names x = Format.asprintf "%d" x end +module type Gas = sig + module M:Lattice.S + val startgas: unit -> M.t + val is_exhausted: fundec -> M.t -> bool + val is_any_exhausted: M.t -> bool + val callee_gas: fundec -> M.t -> M.t + val thread_gas: varinfo -> M.t -> M.t +end + +module GlobalGas:Gas = struct + module M = Lattice.Chain (IntConf) + let startgas () = get_int "ana.context.gas_value" + + let is_any_exhausted v = v <= 0 + let is_exhausted _ = is_any_exhausted + + (* callee gas = caller gas - 1 *) + let callee_gas f v = max 0 (v - 1) + let thread_gas f v = max 0 (v - 1) +end + +module PerFunctionGas:Gas = struct + module M = Lattice.Chain (IntConf) + let startgas () = get_int "ana.context.gas_value" + let is_exhausted f v = v <= 0 + let is_any_exhausted v = v <= 0 + let callee_gas f v = max 0 (v - 1) + let thread_gas f v = max 0 (v - 1) +end + + (** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) -module ContextGasLifter (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Lattice.Chain (IntConf)) +module ContextGasLifter (Gas:Gas) (S:Spec) + : Spec with module D = Lattice.Prod (S.D) (Gas.M) and module C = Printable.Option (S.C) (NoContext) and module G = S.G = @@ -529,7 +560,7 @@ struct let printXml f (x,y) = BatPrintf.fprintf f "\n%a\n%a\n" Base1.printXml x Base2.printXml y end - module D = Context_Gas_Prod (S.D) (Lattice.Chain (IntConf)) (* Product of S.D and an integer, tracking the context gas value *) + module D = Context_Gas_Prod (S.D) (Gas.M) (* Product of S.D and an integer, tracking the context gas value *) module C = Printable.Option (S.C) (NoContext) module G = S.G module V = S.V @@ -549,37 +580,36 @@ struct let startcontext () = Some (S.startcontext ()) let name () = S.name ()^" with context gas" - let startstate v = S.startstate v, get_int "ana.context.gas_value" - let exitstate v = S.exitstate v, get_int "ana.context.gas_value" + let startstate v = S.startstate v, Gas.startgas () + let exitstate v = S.exitstate v, Gas.startgas () let morphstate v (d,i) = S.morphstate v d, i let conv (ctx:(D.t,G.t,C.t,V.t) ctx): (S.D.t,G.t,S.C.t,V.t)ctx = - if (cg_val ctx <= 0) - then {ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, cg_val ctx) es) - ; context = (fun () -> ctx_failwith "no context (contextGas = 0)")} - else {ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, cg_val ctx) es) - ; context = (fun () -> Option.get (ctx.context ()))} + {ctx with local = fst ctx.local + ; split = (fun d es -> ctx.split (d, cg_val ctx) es) + ; context = (fun () -> match ctx.context () with Some c -> c | None -> ctx_failwith "no context (contextGas = 0)")} let context ctx fd (d,i) = (* only keep context if the context gas is greater zero *) - if i <= 0 then None else Some (S.context (conv ctx) fd d) + if Gas.is_exhausted fd i then + None + else + Some (S.context (conv ctx) fd d) let enter ctx r f args = - (* callee gas = caller gas - 1 *) - let liftmap_tup = List.map (fun (x,y) -> (x, cg_val ctx), (y, max 0 (cg_val ctx - 1))) in + let liftmap_tup = List.map (fun (x,y) -> (x, cg_val ctx), (y, Gas.callee_gas f (cg_val ctx))) in liftmap_tup (S.enter (conv ctx) r f args) let threadenter ctx ~multiple lval f args = - let liftmap f = List.map (fun (x) -> (x, max 0 (cg_val ctx - 1))) f in + let liftmap d = List.map (fun (x) -> (x, Gas.thread_gas f (cg_val ctx))) d in liftmap (S.threadenter (conv ctx) ~multiple lval f args) let query ctx (type a) (q: a Queries.t):a Queries.result = match q with | Queries.GasExhausted -> + (* The query is only used in a way where overapproximating gas exhaustion is not harmful *) let (d,i) = ctx.local in - (i <= 0) + Gas.is_any_exhausted i | _ -> S.query (conv ctx) q let sync ctx reason = S.sync (conv ctx) reason, cg_val ctx diff --git a/src/framework/control.ml b/src/framework/control.ml index 5e92282210..f28feb6a1e 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -23,7 +23,7 @@ let spec_module: (module Spec) Lazy.t = lazy ( let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter) + |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter(GlobalGas)) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) From 05520ec9db47b3cc4706bf9eab3ff90c78667b8a Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 20 Sep 2024 17:59:46 +0200 Subject: [PATCH 486/689] Actually rely on lattice structure for gas --- src/framework/constraints.ml | 28 ++++++++++++++-------------- src/framework/control.ml | 7 ++++++- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index ef84326be4..b257d529d8 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -507,10 +507,9 @@ struct end module NoContext = struct let name = "no context" end -module IntConf = -struct - let n () = max_int - let names x = Format.asprintf "%d" x + +module type GasVal = sig + val n: unit -> int end module type Gas = sig @@ -522,9 +521,9 @@ module type Gas = sig val thread_gas: varinfo -> M.t -> M.t end -module GlobalGas:Gas = struct - module M = Lattice.Chain (IntConf) - let startgas () = get_int "ana.context.gas_value" +module GlobalGas(GasVal:GasVal):Gas = struct + module M = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) + let startgas () = M.top () (* get_int "ana.context.gas_value" *) let is_any_exhausted v = v <= 0 let is_exhausted _ = is_any_exhausted @@ -534,13 +533,14 @@ module GlobalGas:Gas = struct let thread_gas f v = max 0 (v - 1) end -module PerFunctionGas:Gas = struct - module M = Lattice.Chain (IntConf) - let startgas () = get_int "ana.context.gas_value" - let is_exhausted f v = v <= 0 - let is_any_exhausted v = v <= 0 - let callee_gas f v = max 0 (v - 1) - let thread_gas f v = max 0 (v - 1) +module PerFunctionGas(GasVal:GasVal):Gas = struct + module V = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) + module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(V) + let startgas () = M.empty () (* get_int "ana.context.gas_value" *) + let is_exhausted f v = (* v <= 0 *) true + let is_any_exhausted v = (* v <= 0 *) true + let callee_gas f v = v (* max 0 (v - 1) *) + let thread_gas f v = v (* max 0 (v - 1) *) end diff --git a/src/framework/control.ml b/src/framework/control.ml index f28feb6a1e..68c31768c6 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -20,10 +20,15 @@ let spec_module: (module Spec) Lazy.t = lazy ( 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 + let module GasVal = struct + (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) + let n () = get_int "ana.context.gas_value" + 1 + end + in let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter(GlobalGas)) + |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter(GlobalGas(GasVal))) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) From dc84b4a533100bac8c1390e61f03a5e35fe931bb Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 20 Sep 2024 18:09:39 +0200 Subject: [PATCH 487/689] Add PerFunctionGas module --- src/framework/constraints.ml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index b257d529d8..5bc83fbe13 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -530,16 +530,18 @@ module GlobalGas(GasVal:GasVal):Gas = struct (* callee gas = caller gas - 1 *) let callee_gas f v = max 0 (v - 1) - let thread_gas f v = max 0 (v - 1) + let thread_gas f v = max 0 (v - 1) end module PerFunctionGas(GasVal:GasVal):Gas = struct - module V = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) - module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(V) - let startgas () = M.empty () (* get_int "ana.context.gas_value" *) - let is_exhausted f v = (* v <= 0 *) true - let is_any_exhausted v = (* v <= 0 *) true - let callee_gas f v = v (* max 0 (v - 1) *) + module G = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) + module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) + let startgas () = M.empty () + let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) + let is_any_exhausted v = M.exists (fun _ g -> g <=0) v + let callee_gas f v = + let c = Option.default (G.top ()) (M.find_opt f v) in + M.add f (max 0 c-1) v let thread_gas f v = v (* max 0 (v - 1) *) end From 300a195840ef9d4db014aaef9de6f3c1224fb563 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 20 Sep 2024 18:13:18 +0200 Subject: [PATCH 488/689] Complete `thread_gas` --- src/framework/constraints.ml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 5bc83fbe13..ce10393d06 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -542,7 +542,12 @@ module PerFunctionGas(GasVal:GasVal):Gas = struct let callee_gas f v = let c = Option.default (G.top ()) (M.find_opt f v) in M.add f (max 0 c-1) v - let thread_gas f v = v (* max 0 (v - 1) *) + let thread_gas f v = + match Cilfacade.find_varinfo_fundec f with + | fd -> + callee_gas fd v + | exception Not_found -> + callee_gas Cil.dummyFunDec v end From 33aee5adde94fe4af03d0f39cb7a819f83d43bad Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 20 Sep 2024 18:25:07 +0200 Subject: [PATCH 489/689] Expose context gas scope via option --- src/config/options.schema.json | 8 ++++++++ src/framework/control.ml | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 7b07c3ca35..03b3d28fa8 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -998,6 +998,14 @@ "type": "integer", "default": -1 }, + "gas_scope": { + "title": "ana.context.gas_scope", + "description": + "Whether the gas should be 'global' (default) or per 'function'", + "type": "string", + "enum": ["global","function"], + "default": "global" + }, "callString_length": { "title": "ana.context.callString_length", "description": "Length of the call string that should be used as context for the call_string and/or call_site analyses. In case the value is zero, the analysis is context-insensitive. For a negative value, an infinite call string is used! For this option to have an effect, one of the analyses in `callstring.ml` must be activated.", diff --git a/src/framework/control.ml b/src/framework/control.ml index 68c31768c6..df57878035 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -28,7 +28,8 @@ let spec_module: (module Spec) Lazy.t = lazy ( let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0) (module ContextGasLifter(GlobalGas(GasVal))) + |> lift (get_int "ana.context.gas_value" >= 0 && get_string "ana.context.gas_scope" = "global") (module ContextGasLifter(GlobalGas(GasVal))) + |> lift (get_int "ana.context.gas_value" >= 0 && get_string "ana.context.gas_scope" = "function") (module ContextGasLifter(PerFunctionGas(GasVal))) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) From 3c0ff8c927558a574c7454c6d08d9e8b445d1ebe Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Fri, 20 Sep 2024 18:38:07 +0200 Subject: [PATCH 490/689] Two regresion tests --- tests/regression/80-context_gas/23-per-fun.c | 29 ++++++++++++ .../regression/80-context_gas/24-per-fun-ex.c | 44 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/regression/80-context_gas/23-per-fun.c create mode 100644 tests/regression/80-context_gas/24-per-fun-ex.c diff --git a/tests/regression/80-context_gas/23-per-fun.c b/tests/regression/80-context_gas/23-per-fun.c new file mode 100644 index 0000000000..1f64317b0f --- /dev/null +++ b/tests/regression/80-context_gas/23-per-fun.c @@ -0,0 +1,29 @@ +// PARAM: --enable ana.int.interval_set --set ana.context.gas_value 3 --set ana.context.gas_scope function +int nr(int x, int y) { + // Non-recursive, but would fail with global scope as gas for f is exhausted + __goblint_check(x==y); +} + +int f(int x, int y) +{ + int top; + if (x == 0) + { + return y; + } + + if(top) { + nr(5,5); + } else { + nr(6,6); + } + + return f(x - 1, y - 1); +} + +int main() +{ + // main -> f(3,3) -> f(2,2) -> f(1,1) -> f(0,0) -> return 0 + // 4 recursive calls -> boundary (excluded) + __goblint_check(f(3, 3) == 0); // UNKNOWN +} diff --git a/tests/regression/80-context_gas/24-per-fun-ex.c b/tests/regression/80-context_gas/24-per-fun-ex.c new file mode 100644 index 0000000000..ab5d203c45 --- /dev/null +++ b/tests/regression/80-context_gas/24-per-fun-ex.c @@ -0,0 +1,44 @@ +// PARAM: --enable ana.int.interval_set --set ana.context.gas_value 3 --set ana.context.gas_scope function +int nr(int x, int y) { + // Non-recursive, but would fail with global scope as gas for f is exhausted + __goblint_check(x==y); +} + +// Checks that gas is also applied to further functions +int g(int x, int y) +{ + int top; + if (x < -100000) + { + return y; + } + + if(top) { + nr(5,5); + } else { + nr(6,6); + } + + return g(x - 1, y - 1); +} + +int f(int x, int y) +{ + int top; + + if (x == 0) + { + return y; + } + + g(x,y); + + return f(x - 1, y - 1); +} + +int main() +{ + // main -> f(3,3) -> f(2,2) -> f(1,1) -> f(0,0) -> return 0 + // 4 recursive calls -> boundary (excluded) + __goblint_check(f(3, 3) == 0); // UNKNOWN +} From a70c17295e19e8b1568e402ca953fe4bea445087 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 13:46:47 +0200 Subject: [PATCH 491/689] Give JoinCall `f` as an argument to avoid having to overaproxximate gas status --- src/analyses/apron/relationAnalysis.apron.ml | 2 +- src/analyses/apron/relationPriv.apron.ml | 18 +++++++------- src/analyses/base.ml | 2 +- src/analyses/basePriv.ml | 26 ++++++++++---------- src/analyses/basePriv.mli | 2 +- src/analyses/commonPriv.ml | 4 +-- src/analyses/mCP.ml | 4 +-- src/domains/queries.ml | 14 ++++++----- src/framework/analyses.ml | 2 +- src/framework/constraints.ml | 11 +++------ 10 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index cb8e8731d9..da14dfff1d 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -772,7 +772,7 @@ struct PCU.RH.replace results ctx.node new_value; end; WideningTokens.with_local_side_tokens (fun () -> - Priv.sync (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg ctx.local (reason :> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread]) + Priv.sync (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg ctx.local (reason :> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return | `Init | `Thread]) ) let init marshal = diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index ff771e692e..15df394d54 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -36,7 +36,7 @@ module type S = val lock: Q.ask -> (V.t -> G.t) -> relation_components_t -> LockDomain.MustLock.t -> relation_components_t val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> LockDomain.MustLock.t -> relation_components_t - val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread] -> relation_components_t + val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return | `Init | `Thread] -> relation_components_t val escape: Node.t -> Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> EscapeDomain.EscapedVars.t -> relation_components_t val enter_multithreaded: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> relation_components_t -> relation_components_t @@ -113,10 +113,10 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation () -> + | `JoinCall _ when ConfCheck.branched_thread_creation () -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Normal | `Init | `Thread @@ -385,10 +385,10 @@ struct end | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> + | `JoinCall f when ConfCheck.branched_thread_creation_at_call ask f -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Normal | `Init | `Thread -> @@ -674,10 +674,10 @@ struct end | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> + | `JoinCall f when ConfCheck.branched_thread_creation_at_call ask f -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Normal | `Init | `Thread -> @@ -1230,10 +1230,10 @@ struct | `Return -> st (* TODO: implement? *) | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> + | `JoinCall f when ConfCheck.branched_thread_creation_at_call ask f -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Normal | `Init | `Thread -> diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a69b3a2b23..a1f0b3b08f 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -453,7 +453,7 @@ struct else ctx.local - let sync ctx reason = sync' (reason :> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread]) ctx + let sync ctx reason = sync' (reason :> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return | `Init | `Thread]) ctx let publish_all ctx reason = ignore (sync' reason ctx) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 08413d54b1..946b8f8cc5 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -31,7 +31,7 @@ sig val lock: Q.ask -> (V.t -> G.t) -> BaseComponents (D).t -> LockDomain.MustLock.t -> BaseComponents (D).t val unlock: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> LockDomain.MustLock.t -> BaseComponents (D).t - val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread] -> BaseComponents (D).t + val sync: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return | `Init | `Thread] -> BaseComponents (D).t val escape: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseComponents (D).t val enter_multithreaded: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseComponents (D).t -> BaseComponents (D).t @@ -322,10 +322,10 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> + | `JoinCall f when ConfCheck.branched_thread_creation_at_call ask f -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Return | `Normal | `Init @@ -433,10 +433,10 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> + | `JoinCall f when ConfCheck.branched_thread_creation_at_call ask f -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Return | `Normal | `Init @@ -802,10 +802,10 @@ struct match reason with | `Join when ConfCheck.branched_thread_creation () -> branched_sync () - | `JoinCall when ConfCheck.branched_thread_creation_at_call ask -> + | `JoinCall f when ConfCheck.branched_thread_creation_at_call ask f -> branched_sync () | `Join - | `JoinCall + | `JoinCall _ | `Return | `Normal | `Init @@ -1055,7 +1055,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) - | `JoinCall + | `JoinCall _ | `Init | `Thread -> st @@ -1111,7 +1111,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) - | `JoinCall + | `JoinCall _ | `Init | `Thread -> st @@ -1183,7 +1183,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) - | `JoinCall + | `JoinCall _ | `Init | `Thread -> st @@ -1342,7 +1342,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) - | `JoinCall + | `JoinCall _ | `Init | `Thread -> st @@ -1521,7 +1521,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) - | `JoinCall + | `JoinCall _ | `Init | `Thread -> st @@ -1704,7 +1704,7 @@ struct | `Return | `Normal | `Join (* TODO: no problem with branched thread creation here? *) - | `JoinCall + | `JoinCall _ | `Init | `Thread -> st diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index 40e50c2a69..edcf70ec98 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -20,7 +20,7 @@ sig val lock: Queries.ask -> (V.t -> G.t) -> BaseDomain.BaseComponents (D).t -> LockDomain.MustLock.t -> BaseDomain.BaseComponents (D).t val unlock: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> LockDomain.MustLock.t -> BaseDomain.BaseComponents (D).t - val sync: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> [`Normal | `Join | `JoinCall | `Return | `Init | `Thread] -> BaseDomain.BaseComponents (D).t + val sync: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return | `Init | `Thread] -> BaseDomain.BaseComponents (D).t val escape: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> EscapeDomain.EscapedVars.t -> BaseDomain.BaseComponents (D).t val enter_multithreaded: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t diff --git a/src/analyses/commonPriv.ml b/src/analyses/commonPriv.ml index 003cdfa96c..915b3da063 100644 --- a/src/analyses/commonPriv.ml +++ b/src/analyses/commonPriv.ml @@ -61,7 +61,7 @@ struct true (** Whether branched thread creation at start nodes of procedures needs to be handled by [sync `JoinCall] of privatization. *) - let branched_thread_creation_at_call (ask:Queries.ask) = + let branched_thread_creation_at_call (ask:Queries.ask) f = let threadflag_active = List.mem "threadflag" (GobConfig.get_string_list "ana.activated") in if threadflag_active then let sens = GobConfig.get_string_list "ana.ctx_sens" in @@ -74,7 +74,7 @@ struct if not threadflag_ctx_sens then true else - ask.f (Queries.GasExhausted) + ask.f (Queries.GasExhausted f) else true end diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index e4c0e261e4..6212b6de90 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -318,10 +318,10 @@ struct f (Result.top ()) (!base_id, spec !base_id, assoc !base_id ctx.local) *) | Queries.DYojson -> `Lifted (D.to_yojson ctx.local) - | Queries.GasExhausted -> + | Queries.GasExhausted f -> if (get_int "ana.context.gas_value" >= 0) then (* There is a lifter above this that will answer it, save to ask *) - ctx.ask (Queries.GasExhausted) + ctx.ask (Queries.GasExhausted f) else (* Abort to avoid infinite recursion *) false diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 5fbb244874..b0ede0cfbf 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -124,9 +124,9 @@ type _ t = | MustTermLoop: stmt -> MustBool.t t | MustTermAllLoops: MustBool.t t | IsEverMultiThreaded: MayBool.t t - | TmpSpecial: Mval.Exp.t -> ML.t t + | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t - | GasExhausted: MustBool.t t + | GasExhausted: CilType.Fundec.t -> MustBool.t t type 'a result = 'a @@ -197,7 +197,7 @@ struct | IsEverMultiThreaded -> (module MayBool) | TmpSpecial _ -> (module ML) | MaySignedOverflow _ -> (module MayBool) - | GasExhausted -> (module MustBool) + | GasExhausted _ -> (module MustBool) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -267,7 +267,7 @@ struct | IsEverMultiThreaded -> MayBool.top () | TmpSpecial _ -> ML.top () | MaySignedOverflow _ -> MayBool.top () - | GasExhausted -> MustBool.top () + | GasExhausted _ -> MustBool.top () end (* The type any_query can't be directly defined in Any as t, @@ -334,7 +334,7 @@ struct | Any (TmpSpecial _) -> 56 | Any (IsAllocVar _) -> 57 | Any (MaySignedOverflow _) -> 58 - | Any GasExhausted -> 59 + | Any (GasExhausted _) -> 59 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -389,6 +389,7 @@ struct | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 | Any (MaySignedOverflow e1), Any (MaySignedOverflow e2) -> CilType.Exp.compare e1 e2 + | Any (GasExhausted f1), Any (GasExhausted f2) -> CilType.Fundec.compare f1 f2 (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) @@ -431,6 +432,7 @@ struct | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv | Any (MaySignedOverflow e) -> CilType.Exp.hash e + | Any (GasExhausted f) -> CilType.Fundec.hash f (* IterSysVars: *) (* - argument is a function and functions cannot be compared in any meaningful way. *) (* - doesn't matter because IterSysVars is always queried from outside of the analysis, so MCP's query caching is not done for it. *) @@ -494,7 +496,7 @@ struct | Any IsEverMultiThreaded -> Pretty.dprintf "IsEverMultiThreaded" | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e - | Any GasExhausted -> Pretty.dprintf "GasExhausted" + | Any (GasExhausted f) -> Pretty.dprintf "GasExhausted %a" CilType.Fundec.pretty f end let to_value_domain_ask (ask: ask) = diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index 717507802f..bb494382d7 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -208,7 +208,7 @@ sig val context: (D.t, G.t, C.t, V.t) ctx -> fundec -> D.t -> C.t val startcontext: unit -> C.t - val sync : (D.t, G.t, C.t, V.t) ctx -> [`Normal | `Join | `JoinCall | `Return] -> D.t + val sync : (D.t, G.t, C.t, V.t) ctx -> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return] -> D.t val query : (D.t, G.t, C.t, V.t) ctx -> 'a Queries.t -> 'a Queries.result (** A transfer function which handles the assignment of a rval to a lval, i.e., diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index ce10393d06..b1c3919bd4 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -516,7 +516,6 @@ module type Gas = sig module M:Lattice.S val startgas: unit -> M.t val is_exhausted: fundec -> M.t -> bool - val is_any_exhausted: M.t -> bool val callee_gas: fundec -> M.t -> M.t val thread_gas: varinfo -> M.t -> M.t end @@ -525,7 +524,6 @@ module GlobalGas(GasVal:GasVal):Gas = struct module M = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) let startgas () = M.top () (* get_int "ana.context.gas_value" *) - let is_any_exhausted v = v <= 0 let is_exhausted _ = is_any_exhausted (* callee gas = caller gas - 1 *) @@ -538,7 +536,6 @@ module PerFunctionGas(GasVal:GasVal):Gas = struct module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) let startgas () = M.empty () let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) - let is_any_exhausted v = M.exists (fun _ g -> g <=0) v let callee_gas f v = let c = Option.default (G.top ()) (M.find_opt f v) in M.add f (max 0 c-1) v @@ -613,10 +610,10 @@ struct let query ctx (type a) (q: a Queries.t):a Queries.result = match q with - | Queries.GasExhausted -> + | Queries.GasExhausted f -> (* The query is only used in a way where overapproximating gas exhaustion is not harmful *) let (d,i) = ctx.local in - Gas.is_any_exhausted i + Gas.is_exhausted f i | _ -> S.query (conv ctx) q let sync ctx reason = S.sync (conv ctx) reason, cg_val ctx @@ -669,8 +666,8 @@ struct match ctx.prev_node, Cfg.prev ctx.prev_node with | _, _ :: _ :: _ -> (* Join in CFG. *) S.sync ctx `Join - | FunctionEntry _, _ -> (* Function entry, also needs sync because partial contexts joined by solver, see 00-sanity/35-join-contexts. *) - S.sync ctx `JoinCall + | FunctionEntry f, _ -> (* Function entry, also needs sync because partial contexts joined by solver, see 00-sanity/35-join-contexts. *) + S.sync ctx (`JoinCall f) | _, _ -> S.sync ctx `Normal let side_context sideg f c = From 1c2c428680c00e27c01abcb34fcb3f462a26aa1c Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 13:48:18 +0200 Subject: [PATCH 492/689] Outdated comment --- src/framework/constraints.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index b1c3919bd4..1794443bd1 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -611,7 +611,6 @@ struct let query ctx (type a) (q: a Queries.t):a Queries.result = match q with | Queries.GasExhausted f -> - (* The query is only used in a way where overapproximating gas exhaustion is not harmful *) let (d,i) = ctx.local in Gas.is_exhausted f i | _ -> S.query (conv ctx) q From d2fc47671fcaa2daba7dad032dabeda98fc17171 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 13:50:54 +0200 Subject: [PATCH 493/689] Fix compilation --- src/framework/constraints.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 1794443bd1..b9553b974a 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -524,7 +524,7 @@ module GlobalGas(GasVal:GasVal):Gas = struct module M = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) let startgas () = M.top () (* get_int "ana.context.gas_value" *) - let is_exhausted _ = is_any_exhausted + let is_exhausted _ v = v <= 0 (* callee gas = caller gas - 1 *) let callee_gas f v = max 0 (v - 1) From 5ea31d5d9533d5eee5a644237c388e5346f09e41 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 14:16:02 +0200 Subject: [PATCH 494/689] I won the fight with first-class modules --- src/framework/control.ml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/framework/control.ml b/src/framework/control.ml index df57878035..96b7ff41d4 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -18,18 +18,23 @@ let spec_module: (module Spec) Lazy.t = lazy ( let arg_enabled = get_bool "witness.graphml.enabled" || get_bool "exp.arg.enabled" in let termination_enabled = List.mem "termination" (get_string_list "ana.activated") in (* check if loop termination analysis is enabled*) let open Batteries in + let gas () = + let module GasVal = struct + (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) + let n () = get_int "ana.context.gas_value" + 1 + end + in + if get_string "ana.context.gas_scope" = "global" then + (module GlobalGas(GasVal):Gas) + else + (module PerFunctionGas(GasVal):Gas) + 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 - let module GasVal = struct - (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) - let n () = get_int "ana.context.gas_value" + 1 - end - in let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0 && get_string "ana.context.gas_scope" = "global") (module ContextGasLifter(GlobalGas(GasVal))) - |> lift (get_int "ana.context.gas_value" >= 0 && get_string "ana.context.gas_scope" = "function") (module ContextGasLifter(PerFunctionGas(GasVal))) + |> lift (get_int "ana.context.gas_value" >= 0) (let (module Gas) = gas () in (module ContextGasLifter(Gas))) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) From d421731e55c78505c769247ebeb63f4d75a64b4c Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 14:57:00 +0200 Subject: [PATCH 495/689] Comment why `top` is maximal gas. Co-authored-by: Julian Erhard --- src/framework/constraints.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index b9553b974a..5ba9f034c2 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -522,7 +522,7 @@ end module GlobalGas(GasVal:GasVal):Gas = struct module M = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) - let startgas () = M.top () (* get_int "ana.context.gas_value" *) + let startgas () = M.top () (* M.top () yields maximal gas value *) let is_exhausted _ v = v <= 0 From 3ee79bf980bee30691884652d76d795c338588c7 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 15:23:07 +0200 Subject: [PATCH 496/689] Embrace dynamic nature of everything --- src/framework/analyses.ml | 2 + src/framework/constraints.ml | 71 ++++++++++++++++++++---------------- src/framework/control.ml | 15 +------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/framework/analyses.ml b/src/framework/analyses.ml index bb494382d7..ab41335944 100644 --- a/src/framework/analyses.ml +++ b/src/framework/analyses.ml @@ -274,6 +274,8 @@ sig 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 +module type Spec2Spec = functor (S: Spec) -> Spec + module type MCPA = sig include Printable.S diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 5ba9f034c2..167ad08484 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -508,10 +508,6 @@ end module NoContext = struct let name = "no context" end -module type GasVal = sig - val n: unit -> int -end - module type Gas = sig module M:Lattice.S val startgas: unit -> M.t @@ -520,34 +516,6 @@ module type Gas = sig val thread_gas: varinfo -> M.t -> M.t end -module GlobalGas(GasVal:GasVal):Gas = struct - module M = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) - let startgas () = M.top () (* M.top () yields maximal gas value *) - - let is_exhausted _ v = v <= 0 - - (* callee gas = caller gas - 1 *) - let callee_gas f v = max 0 (v - 1) - let thread_gas f v = max 0 (v - 1) -end - -module PerFunctionGas(GasVal:GasVal):Gas = struct - module G = Lattice.Chain (struct include GasVal let names x = Format.asprintf "%d" x end) - module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) - let startgas () = M.empty () - let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) - let callee_gas f v = - let c = Option.default (G.top ()) (M.find_opt f v) in - M.add f (max 0 c-1) v - let thread_gas f v = - match Cilfacade.find_varinfo_fundec f with - | fd -> - callee_gas fd v - | exception Not_found -> - callee_gas Cil.dummyFunDec v -end - - (** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) module ContextGasLifter (Gas:Gas) (S:Spec) @@ -631,6 +599,45 @@ struct let event ctx e octx = S.event (conv ctx) e (conv octx), cg_val ctx end +let get_gas_lifter () = + let module GasChain = Lattice.Chain (struct + (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) + let n () = get_int "ana.context.gas_value" + 1 + let names x = Format.asprintf "%d" x + end) + in + if get_string "ana.context.gas_scope" = "global" then + let module GlobalGas:Gas = struct + module M = GasChain + let startgas () = M.top () (* M.top () yields maximal gas value *) + + let is_exhausted _ v = v <= 0 + + (* callee gas = caller gas - 1 *) + let callee_gas f v = max 0 (v - 1) + let thread_gas f v = max 0 (v - 1) + end + in + (module ContextGasLifter(GlobalGas):Spec2Spec) + else + let module PerFunctionGas:Gas = struct + module G = GasChain + module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) + let startgas () = M.empty () + let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) + let callee_gas f v = + let c = Option.default (G.top ()) (M.find_opt f v) in + M.add f (max 0 c-1) v + let thread_gas f v = + match Cilfacade.find_varinfo_fundec f with + | fd -> + callee_gas fd v + | exception Not_found -> + callee_gas Cil.dummyFunDec v + end + in + (module ContextGasLifter(PerFunctionGas):Spec2Spec) + module type Increment = sig diff --git a/src/framework/control.ml b/src/framework/control.ml index 96b7ff41d4..856695e690 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -10,7 +10,7 @@ open ConstrSys open GobConfig open Constraints -module type S2S = functor (X : Spec) -> Spec +module type S2S = Spec2Spec (* spec is lazy, so HConsed table in Hashcons lifters is preserved between analyses in server mode *) let spec_module: (module Spec) Lazy.t = lazy ( @@ -18,23 +18,12 @@ let spec_module: (module Spec) Lazy.t = lazy ( let arg_enabled = get_bool "witness.graphml.enabled" || get_bool "exp.arg.enabled" in let termination_enabled = List.mem "termination" (get_string_list "ana.activated") in (* check if loop termination analysis is enabled*) let open Batteries in - let gas () = - let module GasVal = struct - (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) - let n () = get_int "ana.context.gas_value" + 1 - end - in - if get_string "ana.context.gas_scope" = "global" then - (module GlobalGas(GasVal):Gas) - else - (module PerFunctionGas(GasVal):Gas) - 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 let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0) (let (module Gas) = gas () in (module ContextGasLifter(Gas))) + |> lift (get_int "ana.context.gas_value" >= 0) (Constraints.get_gas_lifter ()) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) From 426ec6964f777e3901952569916dd4eb63295cf3 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 15:31:39 +0200 Subject: [PATCH 497/689] Make `contextGasLifter` its own module --- src/framework/constraints.ml | 133 --------------------------- src/framework/contextGasLifter.ml | 140 +++++++++++++++++++++++++++++ src/framework/contextGasLifter.mli | 1 + src/framework/control.ml | 2 +- 4 files changed, 142 insertions(+), 134 deletions(-) create mode 100644 src/framework/contextGasLifter.ml create mode 100644 src/framework/contextGasLifter.mli diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 167ad08484..23cc297439 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -506,139 +506,6 @@ struct 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 -module NoContext = struct let name = "no context" end - -module type Gas = sig - module M:Lattice.S - val startgas: unit -> M.t - val is_exhausted: fundec -> M.t -> bool - val callee_gas: fundec -> M.t -> M.t - val thread_gas: varinfo -> M.t -> M.t -end - -(** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. - For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) -module ContextGasLifter (Gas:Gas) (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Gas.M) - and module C = Printable.Option (S.C) (NoContext) - and module G = S.G -= -struct - include S - - module Context_Gas_Prod (Base1: Lattice.S) (Base2: Lattice.S) = - struct - include Lattice.Prod (Base1) (Base2) - let printXml f (x,y) = - BatPrintf.fprintf f "\n%a\n%a\n" Base1.printXml x Base2.printXml y - end - module D = Context_Gas_Prod (S.D) (Gas.M) (* Product of S.D and an integer, tracking the context gas value *) - module C = Printable.Option (S.C) (NoContext) - module G = S.G - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - (* returns context gas value of the given ctx *) - let cg_val ctx = snd ctx.local - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - - let startcontext () = Some (S.startcontext ()) - let name () = S.name ()^" with context gas" - let startstate v = S.startstate v, Gas.startgas () - let exitstate v = S.exitstate v, Gas.startgas () - let morphstate v (d,i) = S.morphstate v d, i - - let conv (ctx:(D.t,G.t,C.t,V.t) ctx): (S.D.t,G.t,S.C.t,V.t)ctx = - {ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, cg_val ctx) es) - ; context = (fun () -> match ctx.context () with Some c -> c | None -> ctx_failwith "no context (contextGas = 0)")} - - let context ctx fd (d,i) = - (* only keep context if the context gas is greater zero *) - if Gas.is_exhausted fd i then - None - else - Some (S.context (conv ctx) fd d) - - let enter ctx r f args = - let liftmap_tup = List.map (fun (x,y) -> (x, cg_val ctx), (y, Gas.callee_gas f (cg_val ctx))) in - liftmap_tup (S.enter (conv ctx) r f args) - - let threadenter ctx ~multiple lval f args = - let liftmap d = List.map (fun (x) -> (x, Gas.thread_gas f (cg_val ctx))) d in - liftmap (S.threadenter (conv ctx) ~multiple lval f args) - - let query ctx (type a) (q: a Queries.t):a Queries.result = - match q with - | Queries.GasExhausted f -> - let (d,i) = ctx.local in - Gas.is_exhausted f i - | _ -> S.query (conv ctx) q - - let sync ctx reason = S.sync (conv ctx) reason, cg_val ctx - let assign ctx lval expr = S.assign (conv ctx) lval expr, cg_val ctx - let vdecl ctx v = S.vdecl (conv ctx) v, cg_val ctx - let body ctx fundec = S.body (conv ctx) fundec, cg_val ctx - let branch ctx e tv = S.branch (conv ctx) e tv, cg_val ctx - let return ctx r f = S.return (conv ctx) r f, cg_val ctx - let asm ctx = S.asm (conv ctx), cg_val ctx - let skip ctx = S.skip (conv ctx), cg_val ctx - let special ctx r f args = S.special (conv ctx) r f args, cg_val ctx - let combine_env ctx r fe f args fc es f_ask = S.combine_env (conv ctx) r fe f args (Option.bind fc Fun.id) (fst es) f_ask, cg_val ctx - let combine_assign ctx r fe f args fc es f_ask = S.combine_assign (conv ctx) r fe f args (Option.bind fc Fun.id) (fst es) f_ask, cg_val ctx - let paths_as_set ctx = List.map (fun (x) -> (x, cg_val ctx)) @@ S.paths_as_set (conv ctx) - let threadspawn ctx ~multiple lval f args fctx = S.threadspawn (conv ctx) ~multiple lval f args (conv fctx), cg_val ctx - let event ctx e octx = S.event (conv ctx) e (conv octx), cg_val ctx -end - -let get_gas_lifter () = - let module GasChain = Lattice.Chain (struct - (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) - let n () = get_int "ana.context.gas_value" + 1 - let names x = Format.asprintf "%d" x - end) - in - if get_string "ana.context.gas_scope" = "global" then - let module GlobalGas:Gas = struct - module M = GasChain - let startgas () = M.top () (* M.top () yields maximal gas value *) - - let is_exhausted _ v = v <= 0 - - (* callee gas = caller gas - 1 *) - let callee_gas f v = max 0 (v - 1) - let thread_gas f v = max 0 (v - 1) - end - in - (module ContextGasLifter(GlobalGas):Spec2Spec) - else - let module PerFunctionGas:Gas = struct - module G = GasChain - module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) - let startgas () = M.empty () - let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) - let callee_gas f v = - let c = Option.default (G.top ()) (M.find_opt f v) in - M.add f (max 0 c-1) v - let thread_gas f v = - match Cilfacade.find_varinfo_fundec f with - | fd -> - callee_gas fd v - | exception Not_found -> - callee_gas Cil.dummyFunDec v - end - in - (module ContextGasLifter(PerFunctionGas):Spec2Spec) - - module type Increment = sig val increment: increment_data option diff --git a/src/framework/contextGasLifter.ml b/src/framework/contextGasLifter.ml new file mode 100644 index 0000000000..155eae2d78 --- /dev/null +++ b/src/framework/contextGasLifter.ml @@ -0,0 +1,140 @@ +open Batteries +open GoblintCil +open MyCFG +open Analyses +open ConstrSys +open GobConfig + +module M = Messages + +module NoContext = struct let name = "no context" end + +module type Gas = sig + module M:Lattice.S + val startgas: unit -> M.t + val is_exhausted: fundec -> M.t -> bool + val callee_gas: fundec -> M.t -> M.t + val thread_gas: varinfo -> M.t -> M.t +end + +(** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. + For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) +module ContextGasLifter (Gas:Gas) (S:Spec) + : Spec with module D = Lattice.Prod (S.D) (Gas.M) + and module C = Printable.Option (S.C) (NoContext) + and module G = S.G += +struct + include S + + module Context_Gas_Prod (Base1: Lattice.S) (Base2: Lattice.S) = + struct + include Lattice.Prod (Base1) (Base2) + let printXml f (x,y) = + BatPrintf.fprintf f "\n%a\n%a\n" Base1.printXml x Base2.printXml y + end + module D = Context_Gas_Prod (S.D) (Gas.M) (* Product of S.D and an integer, tracking the context gas value *) + module C = Printable.Option (S.C) (NoContext) + module G = S.G + module V = S.V + module P = + struct + include S.P + let of_elt (x, _) = of_elt x + end + + (* returns context gas value of the given ctx *) + let cg_val ctx = snd ctx.local + + type marshal = S.marshal + let init = S.init + let finalize = S.finalize + + + let startcontext () = Some (S.startcontext ()) + let name () = S.name ()^" with context gas" + let startstate v = S.startstate v, Gas.startgas () + let exitstate v = S.exitstate v, Gas.startgas () + let morphstate v (d,i) = S.morphstate v d, i + + let conv (ctx:(D.t,G.t,C.t,V.t) ctx): (S.D.t,G.t,S.C.t,V.t)ctx = + {ctx with local = fst ctx.local + ; split = (fun d es -> ctx.split (d, cg_val ctx) es) + ; context = (fun () -> match ctx.context () with Some c -> c | None -> ctx_failwith "no context (contextGas = 0)")} + + let context ctx fd (d,i) = + (* only keep context if the context gas is greater zero *) + if Gas.is_exhausted fd i then + None + else + Some (S.context (conv ctx) fd d) + + let enter ctx r f args = + let liftmap_tup = List.map (fun (x,y) -> (x, cg_val ctx), (y, Gas.callee_gas f (cg_val ctx))) in + liftmap_tup (S.enter (conv ctx) r f args) + + let threadenter ctx ~multiple lval f args = + let liftmap d = List.map (fun (x) -> (x, Gas.thread_gas f (cg_val ctx))) d in + liftmap (S.threadenter (conv ctx) ~multiple lval f args) + + let query ctx (type a) (q: a Queries.t):a Queries.result = + match q with + | Queries.GasExhausted f -> + let (d,i) = ctx.local in + Gas.is_exhausted f i + | _ -> S.query (conv ctx) q + + let sync ctx reason = S.sync (conv ctx) reason, cg_val ctx + let assign ctx lval expr = S.assign (conv ctx) lval expr, cg_val ctx + let vdecl ctx v = S.vdecl (conv ctx) v, cg_val ctx + let body ctx fundec = S.body (conv ctx) fundec, cg_val ctx + let branch ctx e tv = S.branch (conv ctx) e tv, cg_val ctx + let return ctx r f = S.return (conv ctx) r f, cg_val ctx + let asm ctx = S.asm (conv ctx), cg_val ctx + let skip ctx = S.skip (conv ctx), cg_val ctx + let special ctx r f args = S.special (conv ctx) r f args, cg_val ctx + let combine_env ctx r fe f args fc es f_ask = S.combine_env (conv ctx) r fe f args (Option.bind fc Fun.id) (fst es) f_ask, cg_val ctx + let combine_assign ctx r fe f args fc es f_ask = S.combine_assign (conv ctx) r fe f args (Option.bind fc Fun.id) (fst es) f_ask, cg_val ctx + let paths_as_set ctx = List.map (fun (x) -> (x, cg_val ctx)) @@ S.paths_as_set (conv ctx) + let threadspawn ctx ~multiple lval f args fctx = S.threadspawn (conv ctx) ~multiple lval f args (conv fctx), cg_val ctx + let event ctx e octx = S.event (conv ctx) e (conv octx), cg_val ctx +end + +let get_gas_lifter () = + let module GasChain = Lattice.Chain (struct + (* Chain lattice has elements [0,n-1], but we want [0,gas_value] *) + let n () = get_int "ana.context.gas_value" + 1 + let names x = Format.asprintf "%d" x + end) + in + if get_string "ana.context.gas_scope" = "global" then + let module GlobalGas:Gas = struct + module M = GasChain + let startgas () = M.top () (* M.top () yields maximal gas value *) + + let is_exhausted _ v = v <= 0 + + (* callee gas = caller gas - 1 *) + let callee_gas f v = max 0 (v - 1) + let thread_gas f v = max 0 (v - 1) + end + in + (module ContextGasLifter(GlobalGas):Spec2Spec) + else + let module PerFunctionGas:Gas = struct + module G = GasChain + module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) + let startgas () = M.empty () + let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) + let callee_gas f v = + let c = Option.default (G.top ()) (M.find_opt f v) in + M.add f (max 0 c-1) v + let thread_gas f v = + match Cilfacade.find_varinfo_fundec f with + | fd -> + callee_gas fd v + | exception Not_found -> + callee_gas Cil.dummyFunDec v + end + in + (module ContextGasLifter(PerFunctionGas):Spec2Spec) diff --git a/src/framework/contextGasLifter.mli b/src/framework/contextGasLifter.mli new file mode 100644 index 0000000000..4f8ce4fb72 --- /dev/null +++ b/src/framework/contextGasLifter.mli @@ -0,0 +1 @@ +val get_gas_lifter : unit -> (module Analyses.Spec2Spec) diff --git a/src/framework/control.ml b/src/framework/control.ml index 856695e690..7ea144e1d1 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -23,7 +23,7 @@ let spec_module: (module Spec) Lazy.t = lazy ( let module S1 = (val (module MCP.MCP2 : Spec) - |> lift (get_int "ana.context.gas_value" >= 0) (Constraints.get_gas_lifter ()) + |> lift (get_int "ana.context.gas_value" >= 0) (ContextGasLifter.get_gas_lifter ()) |> lift true (module WidenContextLifterSide) (* option checked in functor *) (* hashcons before witness to reduce duplicates, because witness re-uses contexts in domain and requires tag for PathSensitive3 *) |> lift (get_bool "ana.opt.hashcons" || arg_enabled) (module HashconsContextLifter) From 7112baffc61ce6b4883ab409f8734bba34594f97 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 22 Sep 2024 15:35:11 +0200 Subject: [PATCH 498/689] Document context gas lifter --- src/framework/contextGasLifter.ml | 5 +++-- src/goblint_lib.ml | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/framework/contextGasLifter.ml b/src/framework/contextGasLifter.ml index 155eae2d78..6a991b1f58 100644 --- a/src/framework/contextGasLifter.ml +++ b/src/framework/contextGasLifter.ml @@ -1,3 +1,6 @@ +(** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. + For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) + open Batteries open GoblintCil open MyCFG @@ -17,8 +20,6 @@ module type Gas = sig val thread_gas: varinfo -> M.t -> M.t end -(** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. - For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) module ContextGasLifter (Gas:Gas) (S:Spec) : Spec with module D = Lattice.Prod (S.D) (Gas.M) and module C = Printable.Option (S.C) (NoContext) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 8013d9b2fe..1743e87bea 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -26,6 +26,7 @@ module Constraints = Constraints module AnalysisState = AnalysisState module AnalysisStateUtil = AnalysisStateUtil module ControlSpecC = ControlSpecC +module ContextGasLifter = ContextGasLifter (** Master control program (MCP) is the analysis specification for the dynamic product of activated analyses. *) From d76e40ec0312fa044318a41eea398efe4ba01830 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 23 Sep 2024 10:45:41 +0200 Subject: [PATCH 499/689] Duplicate module synopsis --- src/framework/contextGasLifter.mli | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/framework/contextGasLifter.mli b/src/framework/contextGasLifter.mli index 4f8ce4fb72..f5b07e2b35 100644 --- a/src/framework/contextGasLifter.mli +++ b/src/framework/contextGasLifter.mli @@ -1 +1,5 @@ +(** Lifts a [Spec] with the context gas variable. The gas variable limits the number of context-sensitively analyzed function calls in a call stack. + For every function call the gas is reduced. If the gas is zero, the remaining function calls are analyzed without context-information *) + +(** Gets the appropriate lifter (either local or per-function). Should only be called when context gas is active. *) val get_gas_lifter : unit -> (module Analyses.Spec2Spec) From c4c9c89e0446ff2619deb961525583f4d37e4f44 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 23 Sep 2024 10:48:11 +0200 Subject: [PATCH 500/689] Update outdated comment --- src/framework/contextGasLifter.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/contextGasLifter.ml b/src/framework/contextGasLifter.ml index 6a991b1f58..adb55aa7a2 100644 --- a/src/framework/contextGasLifter.ml +++ b/src/framework/contextGasLifter.ml @@ -34,7 +34,7 @@ struct let printXml f (x,y) = BatPrintf.fprintf f "\n%a\n%a\n" Base1.printXml x Base2.printXml y end - module D = Context_Gas_Prod (S.D) (Gas.M) (* Product of S.D and an integer, tracking the context gas value *) + module D = Context_Gas_Prod (S.D) (Gas.M) (* Product of S.D and a value from the gas module, tracking the context gas value *) module C = Printable.Option (S.C) (NoContext) module G = S.G module V = S.V From 82d580f5214fec7dfac8b9fa5bf2576181837998 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 11:38:32 +0300 Subject: [PATCH 501/689] Pin CIL with 32bit and 64bit Machdeps --- goblint.opam | 2 +- goblint.opam.locked | 2 +- goblint.opam.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/goblint.opam b/goblint.opam index 565d1fab5b..0346e78252 100644 --- a/goblint.opam +++ b/goblint.opam @@ -97,7 +97,7 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#04b8a45a7d20425c7b6c8abe1ad094abc063922b" ] + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#73d02511a0366816d428853634fb939bd2f0a1b7" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index 28dd8e17e9..dcf81b7a53 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -140,7 +140,7 @@ post-messages: [ pin-depends: [ [ "goblint-cil.2.0.4" - "git+https://github.com/goblint/cil.git#04b8a45a7d20425c7b6c8abe1ad094abc063922b" + "git+https://github.com/goblint/cil.git#73d02511a0366816d428853634fb939bd2f0a1b7" ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.template b/goblint.opam.template index 9f29ceb7a5..2a5d5690fc 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -2,7 +2,7 @@ # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#04b8a45a7d20425c7b6c8abe1ad094abc063922b" ] + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#73d02511a0366816d428853634fb939bd2f0a1b7" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} From 917cf7e9387994ee79c5c156d5ded71f21361cf7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 11:38:53 +0300 Subject: [PATCH 502/689] Change Machdep based on SV-COMP architecture --- src/common/util/cilfacade.ml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/common/util/cilfacade.ml b/src/common/util/cilfacade.ml index d520d250e2..a23ee64149 100644 --- a/src/common/util/cilfacade.ml +++ b/src/common/util/cilfacade.ml @@ -47,7 +47,16 @@ 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"; + + if get_bool "ana.sv-comp.enabled" then ( + let machine = match get_string "exp.architecture" with + | "32bit" -> Machdep.gcc32 + | "64bit" -> Machdep.gcc64 + | _ -> assert false + in + Machdep.theMachine := Option.get machine + ) let init () = initCIL (); From 84e738bf7d675a226c820886b90d56bc78b44877 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 11:55:50 +0300 Subject: [PATCH 503/689] Initialize CIL after initializing CIL options initCIL already depends on theMachine, but it overwrites it. Must use envMachine to select it based on exp.architecture beforehand. --- src/common/util/cilfacade.ml | 4 +--- src/goblint.ml | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/common/util/cilfacade.ml b/src/common/util/cilfacade.ml index a23ee64149..a71f2544e3 100644 --- a/src/common/util/cilfacade.ml +++ b/src/common/util/cilfacade.ml @@ -50,12 +50,10 @@ let init_options () = Cabs2cil.addNestedScopeAttr := get_bool "cil.addNestedScopeAttr"; if get_bool "ana.sv-comp.enabled" then ( - let machine = match get_string "exp.architecture" with + Cil.envMachine := match get_string "exp.architecture" with | "32bit" -> Machdep.gcc32 | "64bit" -> Machdep.gcc64 | _ -> assert false - in - Machdep.theMachine := Option.get machine ) let init () = diff --git a/src/goblint.ml b/src/goblint.ml index 52b9bbdfc0..2707e6e57d 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -5,8 +5,8 @@ open Maingoblint (** the main function *) let main () = try - Cilfacade.init (); Maingoblint.parse_arguments (); + Cilfacade.init (); (* Timing. *) Maingoblint.reset_stats (); From d4b4291355fcdc1e89dd285dea957cf490cf092d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 11:56:34 +0300 Subject: [PATCH 504/689] Eta-expand iDtoIdx in base to prevent ptrdiff_ikind lookup during initialization --- 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 a69b3a2b23..bca66e16af 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -171,7 +171,7 @@ struct * Abstract evaluation functions **************************************************************************) - let iDtoIdx = ID.cast_to (Cilfacade.ptrdiff_ikind ()) + let iDtoIdx x = ID.cast_to (Cilfacade.ptrdiff_ikind ()) x let unop_ID = function | Neg -> ID.neg From 56e687ee21ccee9a4cb3401b77f3f847df0c2f58 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 14:55:04 +0300 Subject: [PATCH 505/689] Rename Constraints -> CompareConstraints for split --- .../{constraints.ml => compareConstraints.ml} | 0 src/framework/control.ml | 10 +++++----- src/goblint_lib.ml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename src/framework/{constraints.ml => compareConstraints.ml} (100%) diff --git a/src/framework/constraints.ml b/src/framework/compareConstraints.ml similarity index 100% rename from src/framework/constraints.ml rename to src/framework/compareConstraints.ml diff --git a/src/framework/control.ml b/src/framework/control.ml index 7ea144e1d1..620c5575d2 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -8,7 +8,7 @@ open MyCFG open Analyses open ConstrSys open GobConfig -open Constraints +open CompareConstraints module type S2S = Spec2Spec @@ -90,7 +90,7 @@ struct end module Slvr = (GlobSolverFromEqSolver (Goblint_solver.Selector.Make (PostSolverArg))) (EQSys) (LHT) (GHT) (* The comparator *) - module CompareGlobSys = Constraints.CompareGlobSys (SpecSys) + module CompareGlobSys = CompareConstraints.CompareGlobSys (SpecSys) (* Triple of the function, context, and the local value. *) module RT = AnalysisResult.ResultType2 (Spec) @@ -521,15 +521,15 @@ struct if get_bool "dbg.compare_runs.globsys" then CompareGlobSys.compare (d1, d2) r1 r2; - let module CompareEqSys = Constraints.CompareEqSys (S2) (VH) in + let module CompareEqSys = CompareConstraints.CompareEqSys (S2) (VH) in if get_bool "dbg.compare_runs.eqsys" then CompareEqSys.compare (d1, d2) r1' r2'; - let module CompareGlobal = Constraints.CompareGlobal (EQSys.GVar) (EQSys.G) (GHT) in + let module CompareGlobal = CompareConstraints.CompareGlobal (EQSys.GVar) (EQSys.G) (GHT) in if get_bool "dbg.compare_runs.global" then CompareGlobal.compare (d1, d2) (snd r1) (snd r2); - let module CompareNode = Constraints.CompareNode (Spec.C) (EQSys.D) (LHT) in + let module CompareNode = CompareConstraints.CompareNode (Spec.C) (EQSys.D) (LHT) in if get_bool "dbg.compare_runs.node" then CompareNode.compare (d1, d2) (fst r1) (fst r2); diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 1743e87bea..dcce048717 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -22,7 +22,7 @@ module CfgTools = CfgTools module Analyses = Analyses module ConstrSys = ConstrSys -module Constraints = Constraints +module CompareConstraints = CompareConstraints module AnalysisState = AnalysisState module AnalysisStateUtil = AnalysisStateUtil module ControlSpecC = ControlSpecC From ddd4b769bf43fdf9896d0f4839f915561b89c53f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 14:57:02 +0300 Subject: [PATCH 506/689] Remove non-compare modules from CompareConstraints --- src/framework/compareConstraints.ml | 1705 --------------------------- 1 file changed, 1705 deletions(-) diff --git a/src/framework/compareConstraints.ml b/src/framework/compareConstraints.ml index 23cc297439..5197ac8e4e 100644 --- a/src/framework/compareConstraints.ml +++ b/src/framework/compareConstraints.ml @@ -1,1713 +1,8 @@ -(** Construction of a {{!Analyses.MonSystem} constraint system} from an {{!Analyses.Spec} analysis specification} and {{!MyCFG.CfgBackward} CFGs}. - Transformatons of analysis specifications as functors. *) - open Batteries -open GoblintCil -open MyCFG open Analyses open ConstrSys open GobConfig -module M = Messages - - -(** Lifts a [Spec] so that the domain is [Hashcons]d *) -module HashconsLifter (S:Spec) - : Spec with module G = S.G - and module C = S.C -= -struct - module HConsedArg = - struct - (* 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 assume_idempotent = GobConfig.get_string "ana.int.refinement" = "never" - end - module D = Lattice.HConsed (S.D) (HConsedArg) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt x = of_elt (D.unlift x) - end - - let name () = S.name () ^" hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate v = D.lift (S.startstate v) - let exitstate v = D.lift (S.exitstate v) - let morphstate v d = D.lift (S.morphstate v (D.unlift d)) - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - let startcontext () = S.startcontext () - - let sync ctx reason = - D.lift @@ S.sync (conv ctx) reason - - let query ctx = - S.query (conv ctx) - - let assign ctx lv e = - D.lift @@ S.assign (conv ctx) lv e - - let vdecl ctx v = - D.lift @@ S.vdecl (conv ctx) v - - let branch ctx e tv = - D.lift @@ S.branch (conv ctx) e tv - - let body ctx f = - D.lift @@ S.body (conv ctx) f - - let return ctx r f = - D.lift @@ S.return (conv ctx) r f - - let asm ctx = - D.lift @@ S.asm (conv ctx) - - let skip ctx = - D.lift @@ S.skip (conv ctx) - - let enter ctx r f args = - List.map (fun (x,y) -> D.lift x, D.lift y) @@ S.enter (conv ctx) r f args - - let special ctx r f args = - D.lift @@ S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - D.lift @@ S.combine_env (conv ctx) r fe f args fc (D.unlift es) f_ask - - 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 ~multiple lval f args = - List.map D.lift @@ S.threadenter (conv ctx) ~multiple lval f args - - 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) - - let event ctx e octx = - D.lift @@ S.event (conv ctx) e (conv octx) -end - -(** Lifts a [Spec] so that the context is [Hashcons]d. *) -module HashconsContextLifter (S:Spec) - : Spec with module D = S.D - and module G = S.G - and module C = Printable.HConsed (S.C) -= -struct - module D = S.D - module G = S.G - module C = Printable.HConsed (S.C) - module V = S.V - module P = S.P - - let name () = S.name () ^" context hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate = S.startstate - let exitstate = S.exitstate - let morphstate = S.morphstate - - let conv ctx = - { ctx with context = (fun () -> C.unlift (ctx.context ())) } - - let context ctx fd = C.lift % S.context (conv ctx) fd - let startcontext () = C.lift @@ S.startcontext () - - let sync ctx reason = - S.sync (conv ctx) reason - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.IterPrevVars f -> - let g i (n, c, j) e = f i (n, Obj.repr (C.lift (Obj.obj c)), j) e in - S.query (conv ctx) (Queries.IterPrevVars g) - | _ -> S.query (conv ctx) q - - let assign ctx lv e = - S.assign (conv ctx) lv e - - let vdecl ctx v = - S.vdecl (conv ctx) v - - let branch ctx e tv = - S.branch (conv ctx) e tv - - let body ctx f = - S.body (conv ctx) f - - let return ctx r f = - S.return (conv ctx) r f - - let asm ctx = - S.asm (conv ctx) - - let skip ctx = - S.skip (conv ctx) - - let enter ctx r f args = - S.enter (conv ctx) r f args - - let special ctx r f args = - S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - S.combine_env (conv ctx) r fe f args (Option.map C.unlift fc) es f_ask - - 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 ~multiple lval f args = - S.threadenter (conv ctx) ~multiple lval f args - - 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) -end - -(* see option ana.opt.equal *) -module OptEqual (S: Spec) = struct - module D = struct include S.D let equal x y = x == y || equal x y end - module G = struct include S.G let equal x y = x == y || equal x y end - module C = struct include S.C let equal x y = x == y || equal x y end - include (S : Spec with module D := D and module G := G and module C := C) -end - -(** If dbg.slice.on, stops entering functions after dbg.slice.n levels. *) -module LevelSliceLifter (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - and module G = S.G - and module C = S.C -= -struct - module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - let name () = S.name ()^" level sliced" - - let start_level = ref (`Top) - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init marshal = - if get_bool "dbg.slice.on" then - start_level := `Lifted (Int64.of_int (get_int "dbg.slice.n")); - S.init marshal - - let finalize = S.finalize - - let startstate v = (S.startstate v, !start_level) - let exitstate v = (S.exitstate v, !start_level) - let morphstate v (d,l) = (S.morphstate v d, l) - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,_) = S.context (conv ctx) fd d - let startcontext () = S.startcontext () - - let lift_fun ctx f g h = - f @@ h (g (conv ctx)) - - let enter' ctx r f args = - let liftmap = List.map (fun (x,y) -> (x, snd ctx.local), (y, snd ctx.local)) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) - - let lift ctx d = (d, snd ctx.local) - let lift_start_level d = (d, !start_level) - - let sync ctx reason = lift_fun ctx (lift ctx) S.sync ((|>) reason) - let query' ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun x -> x q) - let assign ctx lv e = lift_fun ctx (lift ctx) S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx (lift ctx) S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx (lift ctx) S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx (lift ctx) S.body ((|>) f) - let return ctx r f = lift_fun ctx (lift ctx) S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx (lift ctx) S.asm identity - let skip ctx = lift_fun ctx (lift ctx) S.skip identity - let special ctx r f args = lift_fun ctx (lift ctx) S.special ((|>) args % (|>) f % (|>) r) - 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 ~multiple lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) 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 - | `Lifted x -> x <= 0L - | `Bot -> true - - let sub1 = function - | `Lifted x -> `Lifted (Int64.sub x 1L) - | x -> x - - let add1 = function - | `Lifted x -> `Lifted (Int64.add x 1L) - | x -> x - - let paths_as_set ctx = - let liftmap = List.map (fun x -> (x, snd ctx.local)) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) - - let event ctx e octx = - lift_fun ctx (lift ctx) S.event ((|>) (conv octx) % (|>) e) - - let enter ctx r f args = - let (d,l) = ctx.local in - if leq0 l then - [ctx.local, D.bot ()] - else - enter' {ctx with local=(d, sub1 l)} r f args - - let combine_env ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - let l = add1 l in - if leq0 l then - (d, l) - else - let d',_ = combine_env' ctx r fe f args fc es f_ask in - (d', l) - - let combine_assign ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - (* No need to add1 here, already done in combine_env. *) - if leq0 l then - (d, l) - else - let d',_ = combine_assign' ctx r fe f args fc es f_ask in - (d', l) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.EvalFunvar e -> - let (d,l) = ctx.local in - if leq0 l then - Queries.AD.empty () - else - query' ctx (Queries.EvalFunvar e) - | q -> query' ctx q -end - - -(** Limits the number of widenings per node. *) -module LimitLifter (S:Spec) = -struct - include (S : module type of S with module D := S.D and type marshal = S.marshal) - - let name () = S.name ()^" limited" - - let limit = ref 0 - - let init marshal = - limit := get_int "dbg.limit.widen"; - S.init marshal - - module H = MyCFG.NodeH - let h = H.create 13 - let incr k = - H.modify_def 1 k (fun v -> - if v >= !limit then failwith (GobPretty.sprintf "LimitLifter: Reached limit (%d) for node %a" !limit Node.pretty_plain_short (Option.get !MyCFG.current_node)); - v+1 - ) h; - module D = struct - include S.D - let widen x y = Option.may incr !MyCFG.current_node; widen x y (* when is this None? *) - end -end - - -(* widening on contexts, keeps contexts for calls only in D *) -module WidenContextLifterSide (S:Spec) -= -struct - module DD = - struct - include S.D - let printXml f d = BatPrintf.fprintf f "%a" printXml d - end - module M = MapDomain.MapBot (Basetype.Variables) (DD) (* should be CilFun -> S.C, but CilFun is not Groupable, and S.C is no Lattice *) - - module D = struct - include Lattice.Prod (S.D) (M) - let printXml f (d,m) = BatPrintf.fprintf f "\n%a\n%a\n" S.D.printXml d M.printXml m - end - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - - let name () = S.name ()^" with widened contexts" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - let inj f x = f x, M.bot () - - let startcontext () = S.startcontext () - let startstate = inj S.startstate - let exitstate = inj S.exitstate - let morphstate v (d,m) = S.morphstate v d, m - - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,m) = S.context (conv ctx) fd d (* just the child analysis' context *) - - let lift_fun ctx f g = g (f (conv ctx)), snd ctx.local - - let sync ctx reason = lift_fun ctx S.sync ((|>) reason) - let query ctx = S.query (conv ctx) - let assign ctx lv e = lift_fun ctx S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx S.body ((|>) f) - let return ctx r f = lift_fun ctx S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx S.asm identity - let skip ctx = lift_fun ctx S.skip identity - let special ctx r f args = lift_fun ctx S.special ((|>) args % (|>) f % (|>) r) - - 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 ~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 - let d' v_cur = - if ContextUtil.should_keep ~isAttr:GobContext ~keepOption:"ana.context.widen" ~keepAttr:"widen" ~removeAttr:"no-widen" f then ( - let v_old = M.find f.svar m in (* S.D.bot () if not found *) - let v_new = S.D.widen v_old (S.D.join v_old v_cur) in - Messages.(if tracing && not (S.D.equal v_old v_new) then tracel "widen-context" "enter results in new context for function %s" f.svar.vname); - v_new, M.add f.svar v_new m - ) - else - v_cur, m - in - S.enter (conv ctx) r f args - |> List.map (fun (c,v) -> (c,m), d' v) (* c: caller, v: callee *) - - let paths_as_set ctx = - let m = snd ctx.local in - S.paths_as_set (conv ctx) |> List.map (fun v -> (v,m)) - - let combine_env ctx r fe f args fc es f_ask = lift_fun 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 S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) -end - - -(** Lifts a [Spec] with a special bottom element that represent unreachable code. *) -module DeadCodeLifter (S:Spec) - : Spec with module D = Dom (S.D) - and module G = S.G - and module C = S.C -= -struct - module D = Dom (S.D) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include Printable.Option (S.P) (struct let name = "None" end) - - let of_elt = function - | `Lifted x -> Some (S.P.of_elt x) - | _ -> None - end - - let name () = S.name ()^" lifted" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - - let startcontext () = S.startcontext () - let startstate v = `Lifted (S.startstate v) - let exitstate v = `Lifted (S.exitstate v) - let morphstate v d = try `Lifted (S.morphstate v (D.unlift d)) with Deadcode -> d - - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - - let lift_fun ctx f g h b = - try f @@ h (g (conv ctx)) - with Deadcode -> b - - let sync ctx reason = lift_fun ctx D.lift S.sync ((|>) reason) `Bot - - let enter ctx r f args = - let liftmap = List.map (fun (x,y) -> D.lift x, D.lift y) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) [] - - let paths_as_set ctx = - let liftmap = List.map (fun x -> D.lift x) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) [D.bot ()] (* One dead path instead of none, such that combine_env gets called for functions with dead normal return (and thus longjmpy returns can be correctly handled by lifter). *) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun (x) -> x q) (Queries.Result.bot q) - let assign ctx lv e = lift_fun ctx D.lift S.assign ((|>) e % (|>) lv) `Bot - let vdecl ctx v = lift_fun ctx D.lift S.vdecl ((|>) v) `Bot - let branch ctx e tv = lift_fun ctx D.lift S.branch ((|>) tv % (|>) e) `Bot - let body ctx f = lift_fun ctx D.lift S.body ((|>) f) `Bot - let return ctx r f = lift_fun ctx D.lift S.return ((|>) f % (|>) r) `Bot - let asm ctx = lift_fun ctx D.lift S.asm identity `Bot - let skip ctx = lift_fun ctx D.lift S.skip identity `Bot - let special ctx r f args = lift_fun ctx D.lift S.special ((|>) args % (|>) f % (|>) r) `Bot - 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 ~multiple lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] - 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 - -module type Increment = -sig - val increment: increment_data option -end - - -(** The main point of this file---generating a [GlobConstrSys] from a [Spec]. *) -module FromSpec (S:Spec) (Cfg:CfgBackward) (I: Increment) - : sig - include GlobConstrSys with module LVar = VarF (S.C) - and module GVar = GVarF (S.V) - and module D = S.D - and module G = GVarG (S.G) (S.C) - end -= -struct - type lv = MyCFG.node * S.C.t - (* type gv = varinfo *) - type ld = S.D.t - (* type gd = S.G.t *) - module LVar = VarF (S.C) - module GVar = GVarF (S.V) - module D = S.D - module G = GVarG (S.G) (S.C) - - (* Two global invariants: - 1. S.V -> S.G -- used for Spec - 2. fundec -> set of S.C -- used for IterSysVars Node *) - - let sync ctx = - match ctx.prev_node, Cfg.prev ctx.prev_node with - | _, _ :: _ :: _ -> (* Join in CFG. *) - S.sync ctx `Join - | FunctionEntry f, _ -> (* Function entry, also needs sync because partial contexts joined by solver, see 00-sanity/35-join-contexts. *) - S.sync ctx (`JoinCall f) - | _, _ -> S.sync ctx `Normal - - let side_context sideg f c = - 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 * bool) list ref = - let r = ref [] in - let spawns = ref [] in - (* now watch this ... *) - let rec ctx = - { ask = (fun (type a) (q: a Queries.t) -> S.query ctx q) - ; emit = (fun _ -> failwith "emit outside MCP") - ; node = fst var - ; prev_node = prev_node - ; control_context = snd var |> Obj.obj - ; context = snd var |> Obj.obj - ; edge = edge - ; local = pval - ; global = (fun g -> G.spec (getg (GVar.spec g))) - ; spawn = spawn - ; 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 ?(multiple=false) lval f args = - (* TODO: adjust ctx node/edge? *) - (* 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, multiple) :: !spawns; - match Cilfacade.find_varinfo_fundec f with - | fd -> - let c = S.context ctx fd d in - sidel (FunctionEntry fd, c) d; - ignore (getl (Function fd, c)) - | exception Not_found -> - (* unknown function *) - M.error ~category:Imprecise ~tags:[Category Unsound] "Created a thread from unknown function %s" f.vname - (* actual implementation (e.g. invalidation) is done by threadenter *) - ) ds - in - (* ... nice, right! *) - let pval = sync ctx in - { ctx with local = pval }, r, spawns - - let rec bigsqcup = function - | [] -> D.bot () - | [x] -> x - | x::xs -> D.join x (bigsqcup xs) - - let thread_spawns ctx d spawns = - if List.is_empty spawns then - d - else - let rec ctx' = - { ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query ctx' q) - ; local = d - } - in - (* TODO: don't forget path dependencies *) - 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' ~multiple lval f args fctx - in - bigsqcup (List.map one_spawn spawns) - - let common_join ctx d splits spawns = - thread_spawns ctx (bigsqcup (d :: splits)) spawns - - let common_joins ctx ds splits spawns = common_join ctx (bigsqcup ds) splits spawns - - let tf_assign var edge prev_node lv e getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.assign ctx lv e in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_vdecl var edge prev_node v getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.vdecl ctx v in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let normal_return r fd ctx sideg = - let spawning_return = S.return ctx r fd in - let nval = S.sync { ctx with local = spawning_return } `Return in - nval - - let toplevel_kernel_return r fd ctx sideg = - let st = if fd.svar.vname = MyCFG.dummy_func.svar.vname then ctx.local else S.return ctx r fd in - let spawning_return = S.return {ctx with local = st} None MyCFG.dummy_func in - let nval = S.sync { ctx with local = spawning_return } `Return in - nval - - let tf_ret var edge prev_node ret fd getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - if (CilType.Fundec.equal fd MyCFG.dummy_func || - List.mem fd.svar.vname (get_string_list "mainfun")) && - get_bool "kernel" - then toplevel_kernel_return ret fd ctx sideg - else normal_return ret fd ctx sideg - in - common_join ctx d !r !spawns - - let tf_entry var edge prev_node fd getl sidel getg sideg d = - (* Side effect function context here instead of at sidel to FunctionEntry, - because otherwise context for main functions (entrystates) will be missing or pruned during postsolving. *) - let c: unit -> S.C.t = snd var |> Obj.obj in - side_context sideg fd (c ()); - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.body ctx fd in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_test var edge prev_node e tv getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.branch ctx e tv in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_normal_call ctx lv e (f:fundec) args getl sidel getg sideg = - let combine (cd, fc, fd) = - if M.tracing then M.traceli "combine" "local: %a" S.D.pretty cd; - if M.tracing then M.trace "combine" "function: %a" S.D.pretty fd; - let rec cd_ctx = - { ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query cd_ctx q); - local = cd; - } - in - let fd_ctx = - (* Inner scope to prevent unsynced fd_ctx from being used. *) - (* Extra sync in case function has multiple returns. - Each `Return sync is done before joining, so joined value may be unsound. - Since sync is normally done before tf (in common_ctx), simulate it here for fd. *) - (* TODO: don't do this extra sync here *) - let rec sync_ctx = - { ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query sync_ctx q); - local = fd; - prev_node = Function f; - } - in - (* TODO: more accurate ctx? *) - let synced = sync sync_ctx in - let rec fd_ctx = - { sync_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query fd_ctx q); - local = synced; - } - in - fd_ctx - in - let r = List.fold_left (fun acc fd1 -> - let rec fd1_ctx = - { fd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query fd1_ctx q); - local = fd1; - } - in - let combine_enved = S.combine_env cd_ctx lv e f args fc fd1_ctx.local (Analyses.ask_of_ctx fd1_ctx) in - let rec combine_assign_ctx = - { cd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query combine_assign_ctx q); - local = combine_enved; - } - in - S.D.join acc (S.combine_assign combine_assign_ctx lv e f args fc fd1_ctx.local (Analyses.ask_of_ctx fd1_ctx)) - ) (S.D.bot ()) (S.paths_as_set fd_ctx) - in - if M.tracing then M.traceu "combine" "combined local: %a" S.D.pretty r; - r - in - let paths = S.enter ctx lv f args in - let paths = List.map (fun (c,v) -> (c, S.context ctx f v, v)) paths in - List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then sidel (FunctionEntry f, fc) v) paths; - let paths = List.map (fun (c,fc,v) -> (c, fc, if S.D.is_bot v then v else getl (Function f, fc))) paths in - (* Don't filter bot paths, otherwise LongjmpLifter is not called. *) - (* let paths = List.filter (fun (c,fc,v) -> not (D.is_bot v)) paths in *) - let paths = List.map (Tuple3.map2 Option.some) paths in - if M.tracing then M.traceli "combine" "combining"; - let paths = List.map combine paths in - let r = List.fold_left D.join (D.bot ()) paths in - if M.tracing then M.traceu "combine" "combined: %a" S.D.pretty r; - r - - let tf_special_call ctx lv f args = S.special ctx lv f args - - let tf_proc var edge prev_node lv e args getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let functions = - match e with - | Lval (Var v, NoOffset) -> - (* Handle statically known function call directly. - Allows deactivating base. *) - [v] - | _ -> - (* Depends on base for query. *) - let ad = ctx.ask (Queries.EvalFunvar e) in - Queries.AD.to_var_may ad (* TODO: don't convert, handle UnknownPtr below *) - in - let one_function f = - match f.vtype with - | TFun (_, params, var_arg, _) -> - let arg_length = List.length args in - let p_length = Option.map_default List.length 0 params in - (* Check whether number of arguments fits. *) - (* If params is None, the function or its parameters are not declared, so we still analyze the unknown function call. *) - if Option.is_none params || p_length = arg_length || (var_arg && arg_length >= p_length) then - begin Some (match Cilfacade.find_varinfo_fundec f with - | fd when LibraryFunctions.use_special f.vname -> - M.info ~category:Analyzer "Using special for defined function %s" f.vname; - tf_special_call ctx lv f args - | fd -> - tf_normal_call ctx lv e fd args getl sidel getg sideg - | exception Not_found -> - tf_special_call ctx lv f args) - end - else begin - let geq = if var_arg then ">=" else "" in - M.warn ~category:Unsound ~tags:[Category Call; CWE 685] "Potential call to function %a with wrong number of arguments (expected: %s%d, actual: %d). This call will be ignored." CilType.Varinfo.pretty f geq p_length arg_length; - None - end - | _ -> - M.warn ~category:Call "Something that is not a function (%a) is called." CilType.Varinfo.pretty f; - None - in - let funs = List.filter_map one_function functions in - if [] = funs && not (S.D.is_bot ctx.local) then begin - M.msg_final Warning ~category:Unsound ~tags:[Category Call] "No suitable function to call"; - M.warn ~category:Unsound ~tags:[Category Call] "No suitable function to be called at call site. Continuing with state before call."; - d (* because LevelSliceLifter *) - end else - common_joins ctx funs !r !spawns - - let tf_asm var edge prev_node getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.asm ctx in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_skip var edge prev_node getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.skip ctx in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf var getl sidel getg sideg prev_node edge d = - begin match edge with - | Assign (lv,rv) -> tf_assign var edge prev_node lv rv - | VDecl (v) -> tf_vdecl var edge prev_node v - | Proc (r,f,ars) -> tf_proc var edge prev_node r f ars - | Entry f -> tf_entry var edge prev_node f - | Ret (r,fd) -> tf_ret var edge prev_node r fd - | Test (p,b) -> tf_test var edge prev_node p b - | ASM (_, _, _) -> tf_asm var edge prev_node (* TODO: use ASM fields for something? *) - | Skip -> tf_skip var edge prev_node - end getl sidel getg sideg d - - type Goblint_backtrace.mark += TfLocation of location - - let () = Goblint_backtrace.register_mark_printer (function - | TfLocation loc -> - Some ("transfer function at " ^ CilType.Location.show loc) - | _ -> None (* for other marks *) - ) - - let tf var getl sidel getg sideg prev_node (_,edge) d (f,t) = - let old_loc = !Goblint_tracing.current_loc in - let old_loc2 = !Goblint_tracing.next_loc in - Goblint_tracing.current_loc := f; - Goblint_tracing.next_loc := t; - Goblint_backtrace.protect ~mark:(fun () -> TfLocation f) ~finally:(fun () -> - Goblint_tracing.current_loc := old_loc; - Goblint_tracing.next_loc := old_loc2 - ) (fun () -> - let d = tf var getl sidel getg sideg prev_node edge d in - d - ) - - let tf (v,c) (edges, u) getl sidel getg sideg = - let pval = getl (u,c) in - let _, locs = List.fold_right (fun (f,e) (t,xs) -> f, (f,t)::xs) edges (Node.location v,[]) in - List.fold_left2 (|>) pval (List.map (tf (v,Obj.repr (fun () -> c)) getl sidel getg sideg u) edges) locs - - let tf (v,c) (e,u) getl sidel getg sideg = - let old_node = !current_node in - let old_fd = Option.map Node.find_fundec old_node |? Cil.dummyFunDec in - let new_fd = Node.find_fundec v in - if not (CilType.Fundec.equal old_fd new_fd) then - Timing.Program.enter new_fd.svar.vname; - let old_context = !M.current_context in - current_node := Some u; - M.current_context := Some (Obj.magic c); (* magic is fine because Spec is top-level Control Spec *) - Fun.protect ~finally:(fun () -> - current_node := old_node; - M.current_context := old_context; - if not (CilType.Fundec.equal old_fd new_fd) then - Timing.Program.exit new_fd.svar.vname - ) (fun () -> - let d = tf (v,c) (e,u) getl sidel getg sideg in - d - ) - - let system (v,c) = - match v with - | FunctionEntry _ -> - None - | _ -> - let tf getl sidel getg sideg = - let tf' eu = tf (v,c) eu getl sidel getg sideg in - - match NodeH.find_option CfgTools.node_scc_global v with - | Some scc when NodeH.mem scc.prev v && NodeH.length scc.prev = 1 -> - (* Limited to loops with only one entry node. Otherwise unsound as is. *) - (* TODO: Is it possible to do soundly for multi-entry loops? *) - let stricts = NodeH.find_default scc.prev v [] in - let xs_stricts = List.map tf' stricts in - (* Evaluate non-strict for dead code warnings. See 00-sanity/36-strict-loop-dead. *) - let equal = [%eq: (CilType.Location.t * Edge.t) list * Node.t] in - let is_strict eu = List.exists (equal eu) stricts in - let non_stricts = List.filter (neg is_strict) (Cfg.prev v) in - let xs_non_stricts = List.map tf' non_stricts in - if List.for_all S.D.is_bot xs_stricts then - S.D.bot () - else ( - let xs_strict = List.fold_left S.D.join (S.D.bot ()) xs_stricts in - List.fold_left S.D.join xs_strict xs_non_stricts - ) - | _ -> - let xs = List.map tf' (Cfg.prev v) in - List.fold_left S.D.join (S.D.bot ()) xs - in - Some tf - - let iter_vars getl getg vq fl fg = - (* vars for Spec *) - let rec ctx = - { ask = (fun (type a) (q: a Queries.t) -> S.query ctx q) - ; emit = (fun _ -> failwith "Cannot \"emit\" in query context.") - ; node = MyCFG.dummy_node (* TODO maybe ask should take a node (which could be used here) instead of a location *) - ; prev_node = MyCFG.dummy_node - ; control_context = (fun () -> ctx_failwith "No context in query context.") - ; context = (fun () -> ctx_failwith "No context in query context.") - ; edge = MyCFG.Skip - ; local = S.startstate Cil.dummyFunDec.svar (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) - ; global = (fun g -> G.spec (getg (GVar.spec g))) - ; 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.") - } - in - let f v = fg (GVar.spec (Obj.obj v)) in - S.query ctx (IterSysVars (vq, f)); - - (* node vars for locals *) - match vq with - | Node {node; fundec} -> - let fd = Option.default_delayed (fun () -> Node.find_fundec node) fundec in - let cs = G.contexts (getg (GVar.contexts fd)) in - G.CSet.iter (fun c -> - fl (node, c) - ) cs - | _ -> - () - - let sys_change getl getg = - let open CompareCIL in - - let c = match I.increment with - | Some {changes; _} -> changes - | None -> empty_change_info () - in - List.(Logs.info "change_info = { unchanged = %d; changed = %d (with unchangedHeader = %d); added = %d; removed = %d }" (length c.unchanged) (length c.changed) (BatList.count_matching (fun c -> c.unchangedHeader) c.changed) (length c.added) (length c.removed)); - - let changed_funs = List.filter_map (function - | {old = {def = Some (Fun f); _}; diff = None; _} -> - Logs.info "Completely changed function: %s" f.svar.vname; - Some f - | _ -> None - ) c.changed - in - let part_changed_funs = List.filter_map (function - | {old = {def = Some (Fun f); _}; diff = Some nd; _} -> - Logs.info "Partially changed function: %s" f.svar.vname; - Some (f, nd.primObsoleteNodes, nd.unchangedNodes) - | _ -> None - ) c.changed - in - let removed_funs = List.filter_map (function - | {def = Some (Fun f); _} -> - Logs.info "Removed function: %s" f.svar.vname; - Some f - | _ -> None - ) c.removed - in - - let module HM = Hashtbl.Make (Var2 (LVar) (GVar)) in - - let mark_node hm f node = - iter_vars getl getg (Node {node; fundec = Some f}) (fun v -> - HM.replace hm (`L v) () - ) (fun v -> - HM.replace hm (`G v) () - ) - in - - let reluctant = GobConfig.get_bool "incremental.reluctant.enabled" in - let reanalyze_entry f = - (* destabilize the entry points of a changed function when reluctant is off, - or the function is to be force-reanalyzed *) - (not reluctant) || CompareCIL.VarinfoSet.mem f.svar c.exclude_from_rel_destab - in - let obsolete_ret = HM.create 103 in - let obsolete_entry = HM.create 103 in - let obsolete_prim = HM.create 103 in - - (* When reluctant is on: - Only add function entry nodes to obsolete_entry if they are in force-reanalyze *) - List.iter (fun f -> - if reanalyze_entry f then - (* collect function entry for eager destabilization *) - mark_node obsolete_entry f (FunctionEntry f) - else - (* collect function return for reluctant analysis *) - mark_node obsolete_ret f (Function f) - ) changed_funs; - (* Primary changed unknowns from partially changed functions need only to be collected for eager destabilization when reluctant is off *) - (* The return nodes of partially changed functions are collected in obsolete_ret for reluctant analysis *) - (* We utilize that force-reanalyzed functions are always considered as completely changed (and not partially changed) *) - List.iter (fun (f, pn, _) -> - if not reluctant then ( - List.iter (fun n -> - mark_node obsolete_prim f n - ) pn - ) - else - mark_node obsolete_ret f (Function f) - ) part_changed_funs; - - let obsolete = Enum.append (HM.keys obsolete_entry) (HM.keys obsolete_prim) |> List.of_enum in - let reluctant = HM.keys obsolete_ret |> List.of_enum in - - let marked_for_deletion = HM.create 103 in - - let dummy_pseudo_return_node f = - (* not the same as in CFG, but compares equal because of sid *) - Node.Statement ({Cil.dummyStmt with sid = Cilfacade.get_pseudo_return_id f}) - in - let add_nodes_of_fun (functions: fundec list) (withEntry: fundec -> bool) = - let add_stmts (f: fundec) = - List.iter (fun s -> - mark_node marked_for_deletion f (Statement s) - ) f.sallstmts - in - List.iter (fun f -> - if withEntry f then - mark_node marked_for_deletion f (FunctionEntry f); - mark_node marked_for_deletion f (Function f); - add_stmts f; - mark_node marked_for_deletion f (dummy_pseudo_return_node f) - ) functions; - in - - add_nodes_of_fun changed_funs reanalyze_entry; - add_nodes_of_fun removed_funs (fun _ -> true); - (* it is necessary to remove all unknowns for changed pseudo-returns because they have static ids *) - let add_pseudo_return f un = - let pseudo = dummy_pseudo_return_node f in - if not (List.exists (Node.equal pseudo % fst) un) then - mark_node marked_for_deletion f (dummy_pseudo_return_node f) - in - List.iter (fun (f,_,un) -> - mark_node marked_for_deletion f (Function f); - add_pseudo_return f un - ) part_changed_funs; - - let delete = HM.keys marked_for_deletion |> List.of_enum in - - let restart = match I.increment with - | Some data -> - let restart = ref [] in - List.iter (fun g -> - iter_vars getl getg g (fun v -> - restart := `L v :: !restart - ) (fun v -> - restart := `G v :: !restart - ) - ) data.restarting; - !restart - | None -> [] - in - - {obsolete; delete; reluctant; restart} -end - - -(** Add path sensitivity to a analysis *) -module PathSensitive2 (Spec:Spec) - : Spec - with module G = Spec.G - and module C = Spec.C - and module V = Spec.V -= -struct - module D = - struct - (* TODO is it really worth it to check every time instead of just using sets and joining later? *) - module R = - struct - include Spec.P - type elt = Spec.D.t - end - module J = SetDomain.Joined (Spec.D) - include DisjointDomain.ProjectiveSet (Spec.D) (J) (R) - let name () = "PathSensitive (" ^ name () ^ ")" - - let printXml f x = - let print_one x = - BatPrintf.fprintf f "\n%a" Spec.D.printXml x - in - iter print_one x - end - - module G = Spec.G - module C = Spec.C - module V = Spec.V - module P = UnitP - - let name () = "PathSensitive2("^Spec.name ()^")" - - type marshal = Spec.marshal - let init = Spec.init - let finalize = Spec.finalize - - let startcontext () = Spec.startcontext () - let exitstate v = D.singleton (Spec.exitstate v) - let startstate v = D.singleton (Spec.startstate v) - let morphstate v d = D.map (Spec.morphstate v) d - - let conv ctx x = - let rec ctx' = { ctx with ask = (fun (type a) (q: a Queries.t) -> Spec.query ctx' q) - ; local = x - ; split = (ctx.split % D.singleton) } - in - ctx' - - let context ctx fd l = - if D.cardinal l <> 1 then - failwith "PathSensitive2.context must be called with a singleton set." - else - let x = D.choose l in - Spec.context (conv ctx x) fd x - - - let map ctx f g = - let h x xs = - try D.add (g (f (conv ctx x))) xs - with Deadcode -> xs - in - let d = D.fold h ctx.local (D.empty ()) in - if D.is_bot d then raise Deadcode else d - - let fold' ctx f g h a = - let k x a = - try h a @@ g @@ f @@ conv ctx x - with Deadcode -> a - in - D.fold k ctx.local a - - let assign ctx l e = map ctx Spec.assign (fun h -> h l e ) - let vdecl ctx v = map ctx Spec.vdecl (fun h -> h v) - let body ctx f = map ctx Spec.body (fun h -> h f ) - let return ctx e f = map ctx Spec.return (fun h -> h e f ) - let branch ctx e tv = map ctx Spec.branch (fun h -> h e tv) - let asm ctx = map ctx Spec.asm identity - let skip ctx = map ctx Spec.skip identity - let special ctx l f a = map ctx Spec.special (fun h -> h l f a) - - let event ctx e octx = - let fd1 = D.choose octx.local in - map ctx Spec.event (fun h -> h e (conv octx fd1)) - - 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 [] - - let threadspawn ctx ~multiple lval f args fctx = - let fd1 = D.choose fctx.local in - 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) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - (* TODO: handle Invariant path like PathSensitive3? *) - (* join results so that they are sound for all paths *) - let module Result = (val Queries.Result.lattice q) in - fold' ctx Spec.query identity (fun x f -> Result.join x (f q)) (Result.bot ()) - - let enter ctx l f a = - let g xs ys = (List.map (fun (x,y) -> D.singleton x, D.singleton y) ys) @ xs in - fold' ctx Spec.enter (fun h -> h l f a) g [] - - let paths_as_set ctx = - (* Path-sensitivity is only here, not below! *) - let elems = D.elements ctx.local in - List.map (D.singleton) elems - - let combine_env ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_env (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d - - let combine_assign ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_assign (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d -end - -module DeadBranchLifter (S: Spec): Spec = -struct - include S - - let name () = "DeadBranch (" ^ S.name () ^ ")" - - (* Two global invariants: - 1. S.V -> S.G -- used for S - 2. node -> (exp -> flat bool) -- used for warnings *) - - module V = - struct - include Printable.EitherConf (struct let expand1 = false let expand2 = true end) (S.V) (Node) - let name () = "DeadBranch" - let s x = `Left x - let node x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | `Right _ -> true - end - - module EM = - struct - include MapDomain.MapBot (Basetype.CilExp) (BoolDomain.FlatBool) - let name () = "branches" - end - - module G = - struct - include Lattice.Lift2 (S.G) (EM) - let name () = "deadbranch" - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "DeadBranchLifter.s" - let node = function - | `Bot -> EM.bot () - | `Lifted2 x -> x - | _ -> failwith "DeadBranchLifter.node" - let create_s s = `Lifted1 s - let create_node node = `Lifted2 node - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" EM.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | `Right g -> - let em = G.node (ctx.global (V.node g)) in - EM.iter (fun exp tv -> - match tv with - | `Lifted tv -> - let loc = Node.location g in (* TODO: looking up location now doesn't work nicely with incremental *) - let cilinserted = if loc.synthetic then "(possibly inserted by CIL) " else "" in - M.warn ~loc:(Node g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' %sis always %B" d_exp exp cilinserted tv - | `Bot when not (CilType.Exp.equal exp one) -> (* all branches dead *) - M.msg_final Error ~category:Analyzer ~tags:[Category Unsound] "Both branches dead"; - M.error ~loc:(Node g) ~category:Analyzer ~tags:[Category Unsound] "both branches over condition '%a' are dead" d_exp exp - | `Bot (* all branches dead, fine at our inserted Neg(1)-s because no Pos(1) *) - | `Top -> (* may be both true and false *) - () - ) em; - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | `Right g -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - - (* node vars for dead branches *) - begin match vq with - | Node {node; _} -> - vf (Obj.repr (V.node node)) - | _ -> - () - end - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let context ctx = S.context (conv ctx) - - let branch ctx exp tv = - if !AnalysisState.postsolving then ( - try - let r = branch ctx exp tv in - (* branch is live *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); (* record expression with reached tv *) - r - with Deadcode -> - (* branch is dead *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); (* record expression without reached tv *) - raise Deadcode - ) - else ( - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); (* create global variable during solving, to allow postsolving leq hack to pass verify *) - branch ctx exp tv - ) - - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - 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 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end - -module LongjmpLifter (S: Spec): Spec = -struct - include S - - let name () = "Longjmp (" ^ S.name () ^ ")" - - module V = - struct - include Printable.Either3Conf (struct let expand1 = false let expand2 = true let expand3 = true end) (S.V) (Printable.Prod (Node) (C)) (Printable.Prod (CilType.Fundec) (C)) - let name () = "longjmp" - let s x = `Left x - let longjmpto x = `Middle x - let longjmpret x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | _ -> false - end - - module G = - struct - include Lattice.Lift2 (S.G) (S.D) - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "LongjmpLifter.s" - let local = function - | `Bot -> S.D.bot () - | `Lifted2 x -> x - | _ -> failwith "LongjmpLifter.local" - let create_s s = `Lifted1 s - let create_local local = `Lifted2 local - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" S.D.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - (* TODO: vars? *) - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let context ctx = S.context (conv ctx) - - let combine_env ctx lv e f args fc fd f_ask = - let conv_ctx = conv ctx in - let current_fundec = Node.find_fundec ctx.node in - let handle_longjmp (cd, fc, longfd) = - (* This is called per-path. *) - let rec cd_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query cd_ctx q); - local = cd; - } - in - let longfd_ctx = - (* Inner scope to prevent unsynced longfd_ctx from being used. *) - (* Extra sync like with normal combine. *) - let rec sync_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query sync_ctx q); - local = longfd; - prev_node = Function f; - } - in - let synced = S.sync sync_ctx `Join in - let rec longfd_ctx = - { sync_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query longfd_ctx q); - local = synced; - } - in - longfd_ctx - in - let combined = lazy ( (* does not depend on target, do at most once *) - (* Globals are non-problematic here, as they are always carried around without any issues! *) - (* A combine call is mostly needed to ensure locals have appropriate values. *) - (* Using f from called function on purpose here! Needed? *) - S.combine_env cd_ctx None e f args fc longfd_ctx.local (Analyses.ask_of_ctx longfd_ctx) (* no lval because longjmp return skips return value assignment *) - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec combined_ctx = - { cd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query combined_ctx q); - local = Lazy.force combined; - } - in - S.return combined_ctx None current_fundec - ) - in - let (active_targets, _) = longfd_ctx.ask ActiveJumpBuf in - let valid_targets = cd_ctx.ask ValidLongJmp in - let handle_target target = match target with - | JmpBufDomain.BufferEntryOrTop.AllTargets -> () (* The warning is already emitted at the point where the longjmp happens *) - | 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 ( - if M.tracing then Messages.tracel "longjmp" "Fun: Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force combined)) - (* No need to propagate this outwards here, the set of valid longjumps is part of the context, we can never have the same context setting the longjmp multiple times *) - ) - (* Appropriate setjmp is not in current function & current context *) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - else - (* It actually is not handled here but was propagated here spuriously, we already warned at the location where this issue is caused *) - (* As the validlongjumps inside the callee is a a superset of the ones inside the caller *) - () - in - JmpBufDomain.JmpBufSet.iter handle_target active_targets - in - if M.tracing then M.tracel "longjmp" "longfd getg %a" CilType.Fundec.pretty f; - let longfd = G.local (ctx.global (V.longjmpret (f, Option.get fc))) in - if M.tracing then M.tracel "longjmp" "longfd %a" D.pretty longfd; - if not (D.is_bot longfd) then - handle_longjmp (ctx.local, fc, longfd); - S.combine_env (conv_ctx) lv e f args fc fd f_ask - - let combine_assign ctx lv e f args fc fd f_ask = - S.combine_assign (conv ctx) lv e f args fc fd f_ask - - let special ctx lv f args = - let conv_ctx = conv ctx in - match (LibraryFunctions.find f).special args with - | Setjmp {env} -> - (* Handling of returning for the first time *) - let normal_return = S.special conv_ctx lv f args in - let jmp_return = G.local (ctx.global (V.longjmpto (ctx.prev_node, ctx.context ()))) in - if S.D.is_bot jmp_return then - normal_return - else ( - let rec jmp_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query jmp_ctx q); - local = jmp_return; - } - in - let longjmped = S.event jmp_ctx (Events.Longjmped {lval=lv}) jmp_ctx in - S.D.join normal_return longjmped - ) - | Longjmp {env; value} -> - let current_fundec = Node.find_fundec ctx.node in - let handle_path path = ( - let rec path_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query path_ctx q); - local = path; - } - in - let specialed = lazy ( (* does not depend on target, do at most once *) - S.special path_ctx lv f args - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec specialed_ctx = - { path_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query specialed_ctx q); - local = Lazy.force specialed; - } - in - S.return specialed_ctx None current_fundec - ) - in - (* Eval `env` again to avoid having to construct bespoke ctx to ask *) - let targets = path_ctx.ask (EvalJumpBuf env) in - let valid_targets = path_ctx.ask ValidLongJmp in - if M.tracing then Messages.tracel "longjmp" "Jumping to %a" 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.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 ( - if M.tracing then Messages.tracel "longjmp" "Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force specialed)) - ) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then ( - if M.tracing then Messages.tracel "longjmp" "Longjmp to somewhere else, side-effect to %i" (S.C.hash (ctx.context ())); - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - ) - else - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target! (Target %a in Function %a which may have already returned or is in a different thread)" Node.pretty target_node CilType.Fundec.pretty target_fundec - in - if JmpBufDomain.JmpBufSet.is_empty targets then - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target (%a is bot?!)" d_exp env - else - JmpBufDomain.JmpBufSet.iter handle_target targets - ) - in - List.iter handle_path (S.paths_as_set conv_ctx); - if !AnalysisState.should_warn && List.mem "termination" @@ get_string_list "ana.activated" then ( - AnalysisState.svcomp_may_not_terminate := true; - M.warn ~category:Termination "The program might not terminate! (Longjmp)" - ); - S.D.bot () - | _ -> S.special conv_ctx lv f args - let threadenter ctx = S.threadenter (conv ctx) - 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end - - -(** Add cycle detection in the context-sensitive dynamic function call graph to an analysis *) -module RecursionTermLifter (S: Spec) - : Spec with module D = S.D - and module C = S.C -= -(* two global invariants: - - S.V -> S.G - Needed to store the previously built global invariants - - fundec * S.C -> (Set (fundec * S.C)) - The second global invariant maps from the callee fundec and context to a set of caller fundecs and contexts. - This structure therefore stores the context-sensitive call graph. - For example: - let the function f in context c call function g in context c'. - In the global invariant structure it would be stored like this: (g,c') -> {(f, c)} -*) - -struct - include S - - (* contains all the callee fundecs and contexts *) - module V = GVarFC(S.V)(S.C) - - (* Tuple containing the fundec and context of a caller *) - module Call = Printable.Prod (CilType.Fundec) (S.C) - - (* Set containing multiple caller tuples *) - module CallerSet = SetDomain.Make (Call) - - module G = - struct - include Lattice.Lift2 (G) (CallerSet) - - let spec = function - | `Bot -> G.bot () - | `Lifted1 x -> x - | _ -> failwith "RecursionTermLifter.spec" - - let callers = function - | `Bot -> CallerSet.bot () - | `Lifted2 x -> x - | _ -> failwith "RecursionTermLifter.callGraph" - - let create_spec spec = `Lifted1 spec - let create_singleton_caller caller = `Lifted2 (CallerSet.singleton caller) - - let printXml f = function - | `Lifted1 x -> G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" CallerSet.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - - end - - let name () = "RecursionTermLifter (" ^ S.name () ^ ")" - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.spec (ctx.global (V.spec v))); - sideg = (fun v g -> ctx.sideg (V.spec v) (G.create_spec g)); - } - - let cycleDetection ctx call = - let module LH = Hashtbl.Make (Printable.Prod (CilType.Fundec) (S.C)) in - let module LS = Set.Make (Printable.Prod (CilType.Fundec) (S.C)) in - (* find all cycles/SCCs *) - let global_visited_calls = LH.create 100 in - - (* DFS *) - let rec iter_call (path_visited_calls: LS.t) ((fundec, _) as call) = - if LS.mem call path_visited_calls then ( - AnalysisState.svcomp_may_not_terminate := true; (*set the indicator for a non-terminating program for the sv comp*) - (*Cycle found*) - let loc = M.Location.CilLocation fundec.svar.vdecl in - M.warn ~loc ~category:Termination "The program might not terminate! (Fundec %a is contained in a call graph cycle)" CilType.Fundec.pretty fundec) (* output a warning for non-termination*) - else if not (LH.mem global_visited_calls call) then begin - LH.replace global_visited_calls call (); - let new_path_visited_calls = LS.add call path_visited_calls in - let gvar = V.call call in - let callers = G.callers (ctx.global gvar) in - CallerSet.iter (fun to_call -> - iter_call new_path_visited_calls to_call - ) callers; - end - in - iter_call LS.empty call - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal v -> - (* check result of loop analysis *) - if not (ctx.ask Queries.MustTermAllLoops) then - AnalysisState.svcomp_may_not_terminate := true; - let v: V.t = Obj.obj v in - begin match v with - | `Left v' -> - S.query (conv ctx) (WarnGlobal (Obj.repr v')) - | `Right call -> cycleDetection ctx call (* Note: to make it more efficient, one could only execute the cycle detection in case the loop analysis returns true, because otherwise the program will probably not terminate anyway*) - end - | InvariantGlobal v -> - let v: V.t = Obj.obj v in - begin match v with - | `Left v -> - S.query (conv ctx) (InvariantGlobal (Obj.repr v)) - | `Right v -> - Queries.Result.top q - end - | _ -> S.query (conv ctx) q - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - - - let record_call sideg callee caller = - sideg (V.call callee) (G.create_singleton_caller caller) - - let enter ctx = S.enter (conv ctx) - let context ctx = S.context (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let combine_env ctx r fe f args fc es f_ask = - if !AnalysisState.postsolving then ( - let c_r: S.C.t = ctx.context () in (* Caller context *) - let nodeF = ctx.node in - let fd_r : fundec = Node.find_fundec nodeF in (* Caller fundec *) - let caller: (fundec * S.C.t) = (fd_r, c_r) in - let c_e: S.C.t = Option.get fc in (* Callee context *) - let fd_e : fundec = f in (* Callee fundec *) - let callee = (fd_e, c_e) in - record_call ctx.sideg callee caller - ); - S.combine_env (conv ctx) r fe f args fc es f_ask - - 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 ~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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end module CompareGlobSys (SpecSys: SpecSys) = struct From 0061608f3b9bd0c13e4d7fd81819262797124314 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 14:57:50 +0300 Subject: [PATCH 507/689] Remove compare modules from Constraints --- src/framework/constraints.ml | 212 ----------------------------------- 1 file changed, 212 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 23cc297439..a8728f2548 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1708,215 +1708,3 @@ struct let asm ctx = S.asm (conv ctx) let event ctx e octx = S.event (conv ctx) e (conv octx) end - -module CompareGlobSys (SpecSys: SpecSys) = -struct - open SpecSys - module Sys = EQSys - module LH = LHT - module GH = GHT - - open Spec - module G = Sys.G - - module PP = Hashtbl.Make (Node) - - let compare_globals g1 g2 = - let eq, le, gr, uk = ref 0, ref 0, ref 0, ref 0 in - let f_eq () = incr eq in - let f_le () = incr le in - let f_gr () = incr gr in - let f_uk () = incr uk in - let f k v1 = - let v2 = try GH.find g2 k with Not_found -> G.bot () in - let b1 = G.leq v1 v2 in - let b2 = G.leq v2 v1 in - if b1 && b2 then - f_eq () - else if b1 then begin - if get_bool "dbg.compare_runs.diff" then - Logs.info "Global %a is more precise using left:\n%a" Sys.GVar.pretty_trace k G.pretty_diff (v2,v1); - f_le () - end else if b2 then begin - if get_bool "dbg.compare_runs.diff" then - Logs.info "Global %a is more precise using right:\n%a" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2); - f_gr () - end else begin - if get_bool "dbg.compare_runs.diff" then ( - Logs.info "Global %a is incomparable (diff):\n%a" Sys.GVar.pretty_trace k G.pretty_diff (v1,v2); - Logs.info "Global %a is incomparable (reverse diff):\n%a" Sys.GVar.pretty_trace k G.pretty_diff (v2,v1); - ); - f_uk () - end - in - GH.iter f g1; - Logs.info "globals:\tequal = %d\tleft = %d\tright = %d\tincomparable = %d" !eq !le !gr !uk - - let compare_locals h1 h2 = - let eq, le, gr, uk = ref 0, ref 0, ref 0, ref 0 in - let f k v1 = - if PP.mem h2 k then - let v2 = PP.find h2 k in - let b1 = D.leq v1 v2 in - let b2 = D.leq v2 v1 in - if b1 && b2 then - incr eq - else if b1 then begin - if get_bool "dbg.compare_runs.diff" then - Logs.info "%a @@ %a is more precise using left:\n%a" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v2,v1); - incr le - end else if b2 then begin - if get_bool "dbg.compare_runs.diff" then - Logs.info "%a @@ %a is more precise using right:\n%a" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2); - incr gr - end else begin - if get_bool "dbg.compare_runs.diff" then ( - Logs.info "%a @@ %a is incomparable (diff):\n%a" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v1,v2); - Logs.info "%a @@ %a is incomparable (reverse diff):\n%a" Node.pretty_plain k CilType.Location.pretty (Node.location k) D.pretty_diff (v2,v1); - ); - incr uk - end - in - PP.iter f h1; - (* let k1 = Set.of_enum @@ PP.keys h1 in - let k2 = Set.of_enum @@ PP.keys h2 in - let o1 = Set.cardinal @@ Set.diff k1 k2 in - let o2 = Set.cardinal @@ Set.diff k2 k1 in - Logs.info "locals: \tequal = %d\tleft = %d[%d]\tright = %d[%d]\tincomparable = %d" !eq !le o1 !gr o2 !uk *) - Logs.info "locals: \tequal = %d\tleft = %d\tright = %d\tincomparable = %d" !eq !le !gr !uk - - let compare_locals_ctx h1 h2 = - let eq, le, gr, uk, no2, no1 = ref 0, ref 0, ref 0, ref 0, ref 0, ref 0 in - let f_eq () = incr eq in - let f_le () = incr le in - let f_gr () = incr gr in - let f_uk () = incr uk in - let f k v1 = - if not (LH.mem h2 k) then incr no2 else - let v2 = LH.find h2 k in - let b1 = D.leq v1 v2 in - let b2 = D.leq v2 v1 in - if b1 && b2 then - f_eq () - else if b1 then begin - if get_bool "dbg.compare_runs.diff" then - Logs.info "%a is more precise using left:\n%a" Sys.LVar.pretty_trace k D.pretty_diff (v2,v1); - f_le () - end else if b2 then begin - if get_bool "dbg.compare_runs.diff" then - Logs.info "%a is more precise using right:\n%a" Sys.LVar.pretty_trace k D.pretty_diff (v1,v2); - f_gr () - end else begin - if get_bool "dbg.compare_runs.diff" then ( - Logs.info "%a is incomparable (diff):\n%a" Sys.LVar.pretty_trace k D.pretty_diff (v1,v2); - Logs.info "%a is incomparable (reverse diff):\n%a" Sys.LVar.pretty_trace k D.pretty_diff (v2,v1); - ); - f_uk () - end - in - LH.iter f h1; - let f k v2 = - if not (LH.mem h1 k) then incr no1 - in - LH.iter f h2; - (* let k1 = Set.of_enum @@ PP.keys h1 in *) - (* let k2 = Set.of_enum @@ PP.keys h2 in *) - (* let o1 = Set.cardinal @@ Set.diff k1 k2 in *) - (* let o2 = Set.cardinal @@ Set.diff k2 k1 in *) - Logs.info "locals_ctx:\tequal = %d\tleft = %d\tright = %d\tincomparable = %d\tno_ctx_in_right = %d\tno_ctx_in_left = %d" !eq !le !gr !uk !no2 !no1 - - let compare (name1,name2) (l1,g1) (l2,g2) = - let one_ctx (n,_) v h = - PP.replace h n (try D.join v (PP.find h n) with Not_found -> v); - h - in - (* these contain results where the contexts per node have been joined *) - let h1 = PP.create 113 in - let h2 = PP.create 113 in - let _ = LH.fold one_ctx l1 h1 in - let _ = LH.fold one_ctx l2 h2 in - Logs.newline (); - Logs.info "Comparing GlobConstrSys precision of %s (left) with %s (right):" name1 name2; - compare_globals g1 g2; - compare_locals h1 h2; - compare_locals_ctx l1 l2; - Logs.newline (); -end - -module CompareHashtbl (Var: VarType) (Dom: Lattice.S) (VH: Hashtbl.S with type key = Var.t) = -struct - module Var = - struct - include Printable.Std - include Var - let name () = "var" - - let pretty = pretty_trace - include Printable.SimplePretty ( - struct - type nonrec t = t - let pretty = pretty - end - ) - end - - include PrecCompare.MakeHashtbl (Var) (Dom) (VH) -end - -module CompareEqSys (Sys: EqConstrSys) (VH: Hashtbl.S with type key = Sys.Var.t) = -struct - module Compare = CompareHashtbl (Sys.Var) (Sys.Dom) (VH) - - let compare (name1, name2) vh1 vh2 = - Logs.newline (); - Logs.info "Comparing EqConstrSys precision of %s (left) with %s (right):" name1 name2; - let verbose = get_bool "dbg.compare_runs.diff" in - let (_, msg) = Compare.compare ~verbose ~name1 vh1 ~name2 vh2 in - Logs.info "EqConstrSys comparison summary: %t" (fun () -> msg); - Logs.newline (); -end - -module CompareGlobal (GVar: VarType) (G: Lattice.S) (GH: Hashtbl.S with type key = GVar.t) = -struct - module Compare = CompareHashtbl (GVar) (G) (GH) - - let compare (name1, name2) vh1 vh2 = - Logs.newline (); - Logs.info "Comparing globals precision of %s (left) with %s (right):" name1 name2; - let verbose = get_bool "dbg.compare_runs.diff" in - let (_, msg) = Compare.compare ~verbose ~name1 vh1 ~name2 vh2 in - Logs.info "Globals comparison summary: %t" (fun () -> msg); - Logs.newline (); -end - -module CompareNode (C: Printable.S) (D: Lattice.S) (LH: Hashtbl.S with type key = VarF (C).t) = -struct - module Node = - struct - include Node - let var_id _ = "nodes" - let node x = x - let is_write_only _ = false - end - module NH = Hashtbl.Make (Node) - - module Compare = CompareHashtbl (Node) (D) (NH) - - let join_contexts (lh: D.t LH.t): D.t NH.t = - let nh = NH.create 113 in - LH.iter (fun (n, _) d -> - let d' = try D.join (NH.find nh n) d with Not_found -> d in - NH.replace nh n d' - ) lh; - nh - - let compare (name1, name2) vh1 vh2 = - Logs.newline (); - Logs.info "Comparing nodes precision of %s (left) with %s (right):" name1 name2; - let vh1' = join_contexts vh1 in - let vh2' = join_contexts vh2 in - let verbose = get_bool "dbg.compare_runs.diff" in - let (_, msg) = Compare.compare ~verbose ~name1 vh1' ~name2 vh2' in - Logs.info "Nodes comparison summary: %t" (fun () -> msg); - Logs.newline (); -end From 5a3d53d44b7945d0b7056a0f2ced1899dbcbdb8e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:02:20 +0300 Subject: [PATCH 508/689] Rename Constraints -> SpecLifters for split --- src/framework/control.ml | 2 +- src/framework/{constraints.ml => specLifters.ml} | 0 src/goblint_lib.ml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/framework/{constraints.ml => specLifters.ml} (100%) diff --git a/src/framework/control.ml b/src/framework/control.ml index ada639bb59..b156acc1d3 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -8,7 +8,7 @@ open MyCFG open Analyses open ConstrSys open GobConfig -open Constraints +open SpecLifters module type S2S = Spec2Spec diff --git a/src/framework/constraints.ml b/src/framework/specLifters.ml similarity index 100% rename from src/framework/constraints.ml rename to src/framework/specLifters.ml diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index e1b04afa2e..fa610643ad 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -22,7 +22,7 @@ module CfgTools = CfgTools module Analyses = Analyses module ConstrSys = ConstrSys -module Constraints = Constraints +module SpecLifters = SpecLifters module CompareConstraints = CompareConstraints module AnalysisState = AnalysisState module AnalysisStateUtil = AnalysisStateUtil From 6b6bb6251b8d271d8869ba820d25870b1c0d8917 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:03:19 +0300 Subject: [PATCH 509/689] Remove FromSpec from SpecLifters --- src/framework/specLifters.ml | 539 ----------------------------------- 1 file changed, 539 deletions(-) diff --git a/src/framework/specLifters.ml b/src/framework/specLifters.ml index a8728f2548..2012b5cdcf 100644 --- a/src/framework/specLifters.ml +++ b/src/framework/specLifters.ml @@ -1,15 +1,8 @@ -(** Construction of a {{!Analyses.MonSystem} constraint system} from an {{!Analyses.Spec} analysis specification} and {{!MyCFG.CfgBackward} CFGs}. - Transformatons of analysis specifications as functors. *) - open Batteries open GoblintCil -open MyCFG open Analyses -open ConstrSys open GobConfig -module M = Messages - (** Lifts a [Spec] so that the domain is [Hashcons]d *) module HashconsLifter (S:Spec) @@ -506,538 +499,6 @@ struct 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 -module type Increment = -sig - val increment: increment_data option -end - - -(** The main point of this file---generating a [GlobConstrSys] from a [Spec]. *) -module FromSpec (S:Spec) (Cfg:CfgBackward) (I: Increment) - : sig - include GlobConstrSys with module LVar = VarF (S.C) - and module GVar = GVarF (S.V) - and module D = S.D - and module G = GVarG (S.G) (S.C) - end -= -struct - type lv = MyCFG.node * S.C.t - (* type gv = varinfo *) - type ld = S.D.t - (* type gd = S.G.t *) - module LVar = VarF (S.C) - module GVar = GVarF (S.V) - module D = S.D - module G = GVarG (S.G) (S.C) - - (* Two global invariants: - 1. S.V -> S.G -- used for Spec - 2. fundec -> set of S.C -- used for IterSysVars Node *) - - let sync ctx = - match ctx.prev_node, Cfg.prev ctx.prev_node with - | _, _ :: _ :: _ -> (* Join in CFG. *) - S.sync ctx `Join - | FunctionEntry f, _ -> (* Function entry, also needs sync because partial contexts joined by solver, see 00-sanity/35-join-contexts. *) - S.sync ctx (`JoinCall f) - | _, _ -> S.sync ctx `Normal - - let side_context sideg f c = - 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 * bool) list ref = - let r = ref [] in - let spawns = ref [] in - (* now watch this ... *) - let rec ctx = - { ask = (fun (type a) (q: a Queries.t) -> S.query ctx q) - ; emit = (fun _ -> failwith "emit outside MCP") - ; node = fst var - ; prev_node = prev_node - ; control_context = snd var |> Obj.obj - ; context = snd var |> Obj.obj - ; edge = edge - ; local = pval - ; global = (fun g -> G.spec (getg (GVar.spec g))) - ; spawn = spawn - ; 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 ?(multiple=false) lval f args = - (* TODO: adjust ctx node/edge? *) - (* 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, multiple) :: !spawns; - match Cilfacade.find_varinfo_fundec f with - | fd -> - let c = S.context ctx fd d in - sidel (FunctionEntry fd, c) d; - ignore (getl (Function fd, c)) - | exception Not_found -> - (* unknown function *) - M.error ~category:Imprecise ~tags:[Category Unsound] "Created a thread from unknown function %s" f.vname - (* actual implementation (e.g. invalidation) is done by threadenter *) - ) ds - in - (* ... nice, right! *) - let pval = sync ctx in - { ctx with local = pval }, r, spawns - - let rec bigsqcup = function - | [] -> D.bot () - | [x] -> x - | x::xs -> D.join x (bigsqcup xs) - - let thread_spawns ctx d spawns = - if List.is_empty spawns then - d - else - let rec ctx' = - { ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query ctx' q) - ; local = d - } - in - (* TODO: don't forget path dependencies *) - 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' ~multiple lval f args fctx - in - bigsqcup (List.map one_spawn spawns) - - let common_join ctx d splits spawns = - thread_spawns ctx (bigsqcup (d :: splits)) spawns - - let common_joins ctx ds splits spawns = common_join ctx (bigsqcup ds) splits spawns - - let tf_assign var edge prev_node lv e getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.assign ctx lv e in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_vdecl var edge prev_node v getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.vdecl ctx v in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let normal_return r fd ctx sideg = - let spawning_return = S.return ctx r fd in - let nval = S.sync { ctx with local = spawning_return } `Return in - nval - - let toplevel_kernel_return r fd ctx sideg = - let st = if fd.svar.vname = MyCFG.dummy_func.svar.vname then ctx.local else S.return ctx r fd in - let spawning_return = S.return {ctx with local = st} None MyCFG.dummy_func in - let nval = S.sync { ctx with local = spawning_return } `Return in - nval - - let tf_ret var edge prev_node ret fd getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - if (CilType.Fundec.equal fd MyCFG.dummy_func || - List.mem fd.svar.vname (get_string_list "mainfun")) && - get_bool "kernel" - then toplevel_kernel_return ret fd ctx sideg - else normal_return ret fd ctx sideg - in - common_join ctx d !r !spawns - - let tf_entry var edge prev_node fd getl sidel getg sideg d = - (* Side effect function context here instead of at sidel to FunctionEntry, - because otherwise context for main functions (entrystates) will be missing or pruned during postsolving. *) - let c: unit -> S.C.t = snd var |> Obj.obj in - side_context sideg fd (c ()); - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.body ctx fd in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_test var edge prev_node e tv getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.branch ctx e tv in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_normal_call ctx lv e (f:fundec) args getl sidel getg sideg = - let combine (cd, fc, fd) = - if M.tracing then M.traceli "combine" "local: %a" S.D.pretty cd; - if M.tracing then M.trace "combine" "function: %a" S.D.pretty fd; - let rec cd_ctx = - { ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query cd_ctx q); - local = cd; - } - in - let fd_ctx = - (* Inner scope to prevent unsynced fd_ctx from being used. *) - (* Extra sync in case function has multiple returns. - Each `Return sync is done before joining, so joined value may be unsound. - Since sync is normally done before tf (in common_ctx), simulate it here for fd. *) - (* TODO: don't do this extra sync here *) - let rec sync_ctx = - { ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query sync_ctx q); - local = fd; - prev_node = Function f; - } - in - (* TODO: more accurate ctx? *) - let synced = sync sync_ctx in - let rec fd_ctx = - { sync_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query fd_ctx q); - local = synced; - } - in - fd_ctx - in - let r = List.fold_left (fun acc fd1 -> - let rec fd1_ctx = - { fd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query fd1_ctx q); - local = fd1; - } - in - let combine_enved = S.combine_env cd_ctx lv e f args fc fd1_ctx.local (Analyses.ask_of_ctx fd1_ctx) in - let rec combine_assign_ctx = - { cd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query combine_assign_ctx q); - local = combine_enved; - } - in - S.D.join acc (S.combine_assign combine_assign_ctx lv e f args fc fd1_ctx.local (Analyses.ask_of_ctx fd1_ctx)) - ) (S.D.bot ()) (S.paths_as_set fd_ctx) - in - if M.tracing then M.traceu "combine" "combined local: %a" S.D.pretty r; - r - in - let paths = S.enter ctx lv f args in - let paths = List.map (fun (c,v) -> (c, S.context ctx f v, v)) paths in - List.iter (fun (c,fc,v) -> if not (S.D.is_bot v) then sidel (FunctionEntry f, fc) v) paths; - let paths = List.map (fun (c,fc,v) -> (c, fc, if S.D.is_bot v then v else getl (Function f, fc))) paths in - (* Don't filter bot paths, otherwise LongjmpLifter is not called. *) - (* let paths = List.filter (fun (c,fc,v) -> not (D.is_bot v)) paths in *) - let paths = List.map (Tuple3.map2 Option.some) paths in - if M.tracing then M.traceli "combine" "combining"; - let paths = List.map combine paths in - let r = List.fold_left D.join (D.bot ()) paths in - if M.tracing then M.traceu "combine" "combined: %a" S.D.pretty r; - r - - let tf_special_call ctx lv f args = S.special ctx lv f args - - let tf_proc var edge prev_node lv e args getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let functions = - match e with - | Lval (Var v, NoOffset) -> - (* Handle statically known function call directly. - Allows deactivating base. *) - [v] - | _ -> - (* Depends on base for query. *) - let ad = ctx.ask (Queries.EvalFunvar e) in - Queries.AD.to_var_may ad (* TODO: don't convert, handle UnknownPtr below *) - in - let one_function f = - match f.vtype with - | TFun (_, params, var_arg, _) -> - let arg_length = List.length args in - let p_length = Option.map_default List.length 0 params in - (* Check whether number of arguments fits. *) - (* If params is None, the function or its parameters are not declared, so we still analyze the unknown function call. *) - if Option.is_none params || p_length = arg_length || (var_arg && arg_length >= p_length) then - begin Some (match Cilfacade.find_varinfo_fundec f with - | fd when LibraryFunctions.use_special f.vname -> - M.info ~category:Analyzer "Using special for defined function %s" f.vname; - tf_special_call ctx lv f args - | fd -> - tf_normal_call ctx lv e fd args getl sidel getg sideg - | exception Not_found -> - tf_special_call ctx lv f args) - end - else begin - let geq = if var_arg then ">=" else "" in - M.warn ~category:Unsound ~tags:[Category Call; CWE 685] "Potential call to function %a with wrong number of arguments (expected: %s%d, actual: %d). This call will be ignored." CilType.Varinfo.pretty f geq p_length arg_length; - None - end - | _ -> - M.warn ~category:Call "Something that is not a function (%a) is called." CilType.Varinfo.pretty f; - None - in - let funs = List.filter_map one_function functions in - if [] = funs && not (S.D.is_bot ctx.local) then begin - M.msg_final Warning ~category:Unsound ~tags:[Category Call] "No suitable function to call"; - M.warn ~category:Unsound ~tags:[Category Call] "No suitable function to be called at call site. Continuing with state before call."; - d (* because LevelSliceLifter *) - end else - common_joins ctx funs !r !spawns - - let tf_asm var edge prev_node getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.asm ctx in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf_skip var edge prev_node getl sidel getg sideg d = - let ctx, r, spawns = common_ctx var edge prev_node d getl sidel getg sideg in - let d = S.skip ctx in (* Force transfer function to be evaluated before dereferencing in common_join argument. *) - common_join ctx d !r !spawns - - let tf var getl sidel getg sideg prev_node edge d = - begin match edge with - | Assign (lv,rv) -> tf_assign var edge prev_node lv rv - | VDecl (v) -> tf_vdecl var edge prev_node v - | Proc (r,f,ars) -> tf_proc var edge prev_node r f ars - | Entry f -> tf_entry var edge prev_node f - | Ret (r,fd) -> tf_ret var edge prev_node r fd - | Test (p,b) -> tf_test var edge prev_node p b - | ASM (_, _, _) -> tf_asm var edge prev_node (* TODO: use ASM fields for something? *) - | Skip -> tf_skip var edge prev_node - end getl sidel getg sideg d - - type Goblint_backtrace.mark += TfLocation of location - - let () = Goblint_backtrace.register_mark_printer (function - | TfLocation loc -> - Some ("transfer function at " ^ CilType.Location.show loc) - | _ -> None (* for other marks *) - ) - - let tf var getl sidel getg sideg prev_node (_,edge) d (f,t) = - let old_loc = !Goblint_tracing.current_loc in - let old_loc2 = !Goblint_tracing.next_loc in - Goblint_tracing.current_loc := f; - Goblint_tracing.next_loc := t; - Goblint_backtrace.protect ~mark:(fun () -> TfLocation f) ~finally:(fun () -> - Goblint_tracing.current_loc := old_loc; - Goblint_tracing.next_loc := old_loc2 - ) (fun () -> - let d = tf var getl sidel getg sideg prev_node edge d in - d - ) - - let tf (v,c) (edges, u) getl sidel getg sideg = - let pval = getl (u,c) in - let _, locs = List.fold_right (fun (f,e) (t,xs) -> f, (f,t)::xs) edges (Node.location v,[]) in - List.fold_left2 (|>) pval (List.map (tf (v,Obj.repr (fun () -> c)) getl sidel getg sideg u) edges) locs - - let tf (v,c) (e,u) getl sidel getg sideg = - let old_node = !current_node in - let old_fd = Option.map Node.find_fundec old_node |? Cil.dummyFunDec in - let new_fd = Node.find_fundec v in - if not (CilType.Fundec.equal old_fd new_fd) then - Timing.Program.enter new_fd.svar.vname; - let old_context = !M.current_context in - current_node := Some u; - M.current_context := Some (Obj.magic c); (* magic is fine because Spec is top-level Control Spec *) - Fun.protect ~finally:(fun () -> - current_node := old_node; - M.current_context := old_context; - if not (CilType.Fundec.equal old_fd new_fd) then - Timing.Program.exit new_fd.svar.vname - ) (fun () -> - let d = tf (v,c) (e,u) getl sidel getg sideg in - d - ) - - let system (v,c) = - match v with - | FunctionEntry _ -> - None - | _ -> - let tf getl sidel getg sideg = - let tf' eu = tf (v,c) eu getl sidel getg sideg in - - match NodeH.find_option CfgTools.node_scc_global v with - | Some scc when NodeH.mem scc.prev v && NodeH.length scc.prev = 1 -> - (* Limited to loops with only one entry node. Otherwise unsound as is. *) - (* TODO: Is it possible to do soundly for multi-entry loops? *) - let stricts = NodeH.find_default scc.prev v [] in - let xs_stricts = List.map tf' stricts in - (* Evaluate non-strict for dead code warnings. See 00-sanity/36-strict-loop-dead. *) - let equal = [%eq: (CilType.Location.t * Edge.t) list * Node.t] in - let is_strict eu = List.exists (equal eu) stricts in - let non_stricts = List.filter (neg is_strict) (Cfg.prev v) in - let xs_non_stricts = List.map tf' non_stricts in - if List.for_all S.D.is_bot xs_stricts then - S.D.bot () - else ( - let xs_strict = List.fold_left S.D.join (S.D.bot ()) xs_stricts in - List.fold_left S.D.join xs_strict xs_non_stricts - ) - | _ -> - let xs = List.map tf' (Cfg.prev v) in - List.fold_left S.D.join (S.D.bot ()) xs - in - Some tf - - let iter_vars getl getg vq fl fg = - (* vars for Spec *) - let rec ctx = - { ask = (fun (type a) (q: a Queries.t) -> S.query ctx q) - ; emit = (fun _ -> failwith "Cannot \"emit\" in query context.") - ; node = MyCFG.dummy_node (* TODO maybe ask should take a node (which could be used here) instead of a location *) - ; prev_node = MyCFG.dummy_node - ; control_context = (fun () -> ctx_failwith "No context in query context.") - ; context = (fun () -> ctx_failwith "No context in query context.") - ; edge = MyCFG.Skip - ; local = S.startstate Cil.dummyFunDec.svar (* bot and top both silently raise and catch Deadcode in DeadcodeLifter *) - ; global = (fun g -> G.spec (getg (GVar.spec g))) - ; 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.") - } - in - let f v = fg (GVar.spec (Obj.obj v)) in - S.query ctx (IterSysVars (vq, f)); - - (* node vars for locals *) - match vq with - | Node {node; fundec} -> - let fd = Option.default_delayed (fun () -> Node.find_fundec node) fundec in - let cs = G.contexts (getg (GVar.contexts fd)) in - G.CSet.iter (fun c -> - fl (node, c) - ) cs - | _ -> - () - - let sys_change getl getg = - let open CompareCIL in - - let c = match I.increment with - | Some {changes; _} -> changes - | None -> empty_change_info () - in - List.(Logs.info "change_info = { unchanged = %d; changed = %d (with unchangedHeader = %d); added = %d; removed = %d }" (length c.unchanged) (length c.changed) (BatList.count_matching (fun c -> c.unchangedHeader) c.changed) (length c.added) (length c.removed)); - - let changed_funs = List.filter_map (function - | {old = {def = Some (Fun f); _}; diff = None; _} -> - Logs.info "Completely changed function: %s" f.svar.vname; - Some f - | _ -> None - ) c.changed - in - let part_changed_funs = List.filter_map (function - | {old = {def = Some (Fun f); _}; diff = Some nd; _} -> - Logs.info "Partially changed function: %s" f.svar.vname; - Some (f, nd.primObsoleteNodes, nd.unchangedNodes) - | _ -> None - ) c.changed - in - let removed_funs = List.filter_map (function - | {def = Some (Fun f); _} -> - Logs.info "Removed function: %s" f.svar.vname; - Some f - | _ -> None - ) c.removed - in - - let module HM = Hashtbl.Make (Var2 (LVar) (GVar)) in - - let mark_node hm f node = - iter_vars getl getg (Node {node; fundec = Some f}) (fun v -> - HM.replace hm (`L v) () - ) (fun v -> - HM.replace hm (`G v) () - ) - in - - let reluctant = GobConfig.get_bool "incremental.reluctant.enabled" in - let reanalyze_entry f = - (* destabilize the entry points of a changed function when reluctant is off, - or the function is to be force-reanalyzed *) - (not reluctant) || CompareCIL.VarinfoSet.mem f.svar c.exclude_from_rel_destab - in - let obsolete_ret = HM.create 103 in - let obsolete_entry = HM.create 103 in - let obsolete_prim = HM.create 103 in - - (* When reluctant is on: - Only add function entry nodes to obsolete_entry if they are in force-reanalyze *) - List.iter (fun f -> - if reanalyze_entry f then - (* collect function entry for eager destabilization *) - mark_node obsolete_entry f (FunctionEntry f) - else - (* collect function return for reluctant analysis *) - mark_node obsolete_ret f (Function f) - ) changed_funs; - (* Primary changed unknowns from partially changed functions need only to be collected for eager destabilization when reluctant is off *) - (* The return nodes of partially changed functions are collected in obsolete_ret for reluctant analysis *) - (* We utilize that force-reanalyzed functions are always considered as completely changed (and not partially changed) *) - List.iter (fun (f, pn, _) -> - if not reluctant then ( - List.iter (fun n -> - mark_node obsolete_prim f n - ) pn - ) - else - mark_node obsolete_ret f (Function f) - ) part_changed_funs; - - let obsolete = Enum.append (HM.keys obsolete_entry) (HM.keys obsolete_prim) |> List.of_enum in - let reluctant = HM.keys obsolete_ret |> List.of_enum in - - let marked_for_deletion = HM.create 103 in - - let dummy_pseudo_return_node f = - (* not the same as in CFG, but compares equal because of sid *) - Node.Statement ({Cil.dummyStmt with sid = Cilfacade.get_pseudo_return_id f}) - in - let add_nodes_of_fun (functions: fundec list) (withEntry: fundec -> bool) = - let add_stmts (f: fundec) = - List.iter (fun s -> - mark_node marked_for_deletion f (Statement s) - ) f.sallstmts - in - List.iter (fun f -> - if withEntry f then - mark_node marked_for_deletion f (FunctionEntry f); - mark_node marked_for_deletion f (Function f); - add_stmts f; - mark_node marked_for_deletion f (dummy_pseudo_return_node f) - ) functions; - in - - add_nodes_of_fun changed_funs reanalyze_entry; - add_nodes_of_fun removed_funs (fun _ -> true); - (* it is necessary to remove all unknowns for changed pseudo-returns because they have static ids *) - let add_pseudo_return f un = - let pseudo = dummy_pseudo_return_node f in - if not (List.exists (Node.equal pseudo % fst) un) then - mark_node marked_for_deletion f (dummy_pseudo_return_node f) - in - List.iter (fun (f,_,un) -> - mark_node marked_for_deletion f (Function f); - add_pseudo_return f un - ) part_changed_funs; - - let delete = HM.keys marked_for_deletion |> List.of_enum in - - let restart = match I.increment with - | Some data -> - let restart = ref [] in - List.iter (fun g -> - iter_vars getl getg g (fun v -> - restart := `L v :: !restart - ) (fun v -> - restart := `G v :: !restart - ) - ) data.restarting; - !restart - | None -> [] - in - - {obsolete; delete; reluctant; restart} -end - (** Add path sensitivity to a analysis *) module PathSensitive2 (Spec:Spec) From ab5a7b6e56aca81b70e7a1b913b39f78d0fdb377 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:05:57 +0300 Subject: [PATCH 510/689] Remove Spec lifters from Constraints --- src/framework/constraints.ml | 1168 ---------------------------------- 1 file changed, 1168 deletions(-) diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index a8728f2548..fb4b5081e8 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -8,503 +8,6 @@ open Analyses open ConstrSys open GobConfig -module M = Messages - - -(** Lifts a [Spec] so that the domain is [Hashcons]d *) -module HashconsLifter (S:Spec) - : Spec with module G = S.G - and module C = S.C -= -struct - module HConsedArg = - struct - (* 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 assume_idempotent = GobConfig.get_string "ana.int.refinement" = "never" - end - module D = Lattice.HConsed (S.D) (HConsedArg) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt x = of_elt (D.unlift x) - end - - let name () = S.name () ^" hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate v = D.lift (S.startstate v) - let exitstate v = D.lift (S.exitstate v) - let morphstate v d = D.lift (S.morphstate v (D.unlift d)) - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - let startcontext () = S.startcontext () - - let sync ctx reason = - D.lift @@ S.sync (conv ctx) reason - - let query ctx = - S.query (conv ctx) - - let assign ctx lv e = - D.lift @@ S.assign (conv ctx) lv e - - let vdecl ctx v = - D.lift @@ S.vdecl (conv ctx) v - - let branch ctx e tv = - D.lift @@ S.branch (conv ctx) e tv - - let body ctx f = - D.lift @@ S.body (conv ctx) f - - let return ctx r f = - D.lift @@ S.return (conv ctx) r f - - let asm ctx = - D.lift @@ S.asm (conv ctx) - - let skip ctx = - D.lift @@ S.skip (conv ctx) - - let enter ctx r f args = - List.map (fun (x,y) -> D.lift x, D.lift y) @@ S.enter (conv ctx) r f args - - let special ctx r f args = - D.lift @@ S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - D.lift @@ S.combine_env (conv ctx) r fe f args fc (D.unlift es) f_ask - - 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 ~multiple lval f args = - List.map D.lift @@ S.threadenter (conv ctx) ~multiple lval f args - - 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) - - let event ctx e octx = - D.lift @@ S.event (conv ctx) e (conv octx) -end - -(** Lifts a [Spec] so that the context is [Hashcons]d. *) -module HashconsContextLifter (S:Spec) - : Spec with module D = S.D - and module G = S.G - and module C = Printable.HConsed (S.C) -= -struct - module D = S.D - module G = S.G - module C = Printable.HConsed (S.C) - module V = S.V - module P = S.P - - let name () = S.name () ^" context hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate = S.startstate - let exitstate = S.exitstate - let morphstate = S.morphstate - - let conv ctx = - { ctx with context = (fun () -> C.unlift (ctx.context ())) } - - let context ctx fd = C.lift % S.context (conv ctx) fd - let startcontext () = C.lift @@ S.startcontext () - - let sync ctx reason = - S.sync (conv ctx) reason - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.IterPrevVars f -> - let g i (n, c, j) e = f i (n, Obj.repr (C.lift (Obj.obj c)), j) e in - S.query (conv ctx) (Queries.IterPrevVars g) - | _ -> S.query (conv ctx) q - - let assign ctx lv e = - S.assign (conv ctx) lv e - - let vdecl ctx v = - S.vdecl (conv ctx) v - - let branch ctx e tv = - S.branch (conv ctx) e tv - - let body ctx f = - S.body (conv ctx) f - - let return ctx r f = - S.return (conv ctx) r f - - let asm ctx = - S.asm (conv ctx) - - let skip ctx = - S.skip (conv ctx) - - let enter ctx r f args = - S.enter (conv ctx) r f args - - let special ctx r f args = - S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - S.combine_env (conv ctx) r fe f args (Option.map C.unlift fc) es f_ask - - 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 ~multiple lval f args = - S.threadenter (conv ctx) ~multiple lval f args - - 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) -end - -(* see option ana.opt.equal *) -module OptEqual (S: Spec) = struct - module D = struct include S.D let equal x y = x == y || equal x y end - module G = struct include S.G let equal x y = x == y || equal x y end - module C = struct include S.C let equal x y = x == y || equal x y end - include (S : Spec with module D := D and module G := G and module C := C) -end - -(** If dbg.slice.on, stops entering functions after dbg.slice.n levels. *) -module LevelSliceLifter (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - and module G = S.G - and module C = S.C -= -struct - module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - let name () = S.name ()^" level sliced" - - let start_level = ref (`Top) - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init marshal = - if get_bool "dbg.slice.on" then - start_level := `Lifted (Int64.of_int (get_int "dbg.slice.n")); - S.init marshal - - let finalize = S.finalize - - let startstate v = (S.startstate v, !start_level) - let exitstate v = (S.exitstate v, !start_level) - let morphstate v (d,l) = (S.morphstate v d, l) - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,_) = S.context (conv ctx) fd d - let startcontext () = S.startcontext () - - let lift_fun ctx f g h = - f @@ h (g (conv ctx)) - - let enter' ctx r f args = - let liftmap = List.map (fun (x,y) -> (x, snd ctx.local), (y, snd ctx.local)) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) - - let lift ctx d = (d, snd ctx.local) - let lift_start_level d = (d, !start_level) - - let sync ctx reason = lift_fun ctx (lift ctx) S.sync ((|>) reason) - let query' ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun x -> x q) - let assign ctx lv e = lift_fun ctx (lift ctx) S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx (lift ctx) S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx (lift ctx) S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx (lift ctx) S.body ((|>) f) - let return ctx r f = lift_fun ctx (lift ctx) S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx (lift ctx) S.asm identity - let skip ctx = lift_fun ctx (lift ctx) S.skip identity - let special ctx r f args = lift_fun ctx (lift ctx) S.special ((|>) args % (|>) f % (|>) r) - 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 ~multiple lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) 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 - | `Lifted x -> x <= 0L - | `Bot -> true - - let sub1 = function - | `Lifted x -> `Lifted (Int64.sub x 1L) - | x -> x - - let add1 = function - | `Lifted x -> `Lifted (Int64.add x 1L) - | x -> x - - let paths_as_set ctx = - let liftmap = List.map (fun x -> (x, snd ctx.local)) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) - - let event ctx e octx = - lift_fun ctx (lift ctx) S.event ((|>) (conv octx) % (|>) e) - - let enter ctx r f args = - let (d,l) = ctx.local in - if leq0 l then - [ctx.local, D.bot ()] - else - enter' {ctx with local=(d, sub1 l)} r f args - - let combine_env ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - let l = add1 l in - if leq0 l then - (d, l) - else - let d',_ = combine_env' ctx r fe f args fc es f_ask in - (d', l) - - let combine_assign ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - (* No need to add1 here, already done in combine_env. *) - if leq0 l then - (d, l) - else - let d',_ = combine_assign' ctx r fe f args fc es f_ask in - (d', l) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.EvalFunvar e -> - let (d,l) = ctx.local in - if leq0 l then - Queries.AD.empty () - else - query' ctx (Queries.EvalFunvar e) - | q -> query' ctx q -end - - -(** Limits the number of widenings per node. *) -module LimitLifter (S:Spec) = -struct - include (S : module type of S with module D := S.D and type marshal = S.marshal) - - let name () = S.name ()^" limited" - - let limit = ref 0 - - let init marshal = - limit := get_int "dbg.limit.widen"; - S.init marshal - - module H = MyCFG.NodeH - let h = H.create 13 - let incr k = - H.modify_def 1 k (fun v -> - if v >= !limit then failwith (GobPretty.sprintf "LimitLifter: Reached limit (%d) for node %a" !limit Node.pretty_plain_short (Option.get !MyCFG.current_node)); - v+1 - ) h; - module D = struct - include S.D - let widen x y = Option.may incr !MyCFG.current_node; widen x y (* when is this None? *) - end -end - - -(* widening on contexts, keeps contexts for calls only in D *) -module WidenContextLifterSide (S:Spec) -= -struct - module DD = - struct - include S.D - let printXml f d = BatPrintf.fprintf f "%a" printXml d - end - module M = MapDomain.MapBot (Basetype.Variables) (DD) (* should be CilFun -> S.C, but CilFun is not Groupable, and S.C is no Lattice *) - - module D = struct - include Lattice.Prod (S.D) (M) - let printXml f (d,m) = BatPrintf.fprintf f "\n%a\n%a\n" S.D.printXml d M.printXml m - end - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - - let name () = S.name ()^" with widened contexts" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - let inj f x = f x, M.bot () - - let startcontext () = S.startcontext () - let startstate = inj S.startstate - let exitstate = inj S.exitstate - let morphstate v (d,m) = S.morphstate v d, m - - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,m) = S.context (conv ctx) fd d (* just the child analysis' context *) - - let lift_fun ctx f g = g (f (conv ctx)), snd ctx.local - - let sync ctx reason = lift_fun ctx S.sync ((|>) reason) - let query ctx = S.query (conv ctx) - let assign ctx lv e = lift_fun ctx S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx S.body ((|>) f) - let return ctx r f = lift_fun ctx S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx S.asm identity - let skip ctx = lift_fun ctx S.skip identity - let special ctx r f args = lift_fun ctx S.special ((|>) args % (|>) f % (|>) r) - - 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 ~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 - let d' v_cur = - if ContextUtil.should_keep ~isAttr:GobContext ~keepOption:"ana.context.widen" ~keepAttr:"widen" ~removeAttr:"no-widen" f then ( - let v_old = M.find f.svar m in (* S.D.bot () if not found *) - let v_new = S.D.widen v_old (S.D.join v_old v_cur) in - Messages.(if tracing && not (S.D.equal v_old v_new) then tracel "widen-context" "enter results in new context for function %s" f.svar.vname); - v_new, M.add f.svar v_new m - ) - else - v_cur, m - in - S.enter (conv ctx) r f args - |> List.map (fun (c,v) -> (c,m), d' v) (* c: caller, v: callee *) - - let paths_as_set ctx = - let m = snd ctx.local in - S.paths_as_set (conv ctx) |> List.map (fun v -> (v,m)) - - let combine_env ctx r fe f args fc es f_ask = lift_fun 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 S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) -end - - -(** Lifts a [Spec] with a special bottom element that represent unreachable code. *) -module DeadCodeLifter (S:Spec) - : Spec with module D = Dom (S.D) - and module G = S.G - and module C = S.C -= -struct - module D = Dom (S.D) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include Printable.Option (S.P) (struct let name = "None" end) - - let of_elt = function - | `Lifted x -> Some (S.P.of_elt x) - | _ -> None - end - - let name () = S.name ()^" lifted" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - - let startcontext () = S.startcontext () - let startstate v = `Lifted (S.startstate v) - let exitstate v = `Lifted (S.exitstate v) - let morphstate v d = try `Lifted (S.morphstate v (D.unlift d)) with Deadcode -> d - - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - - let lift_fun ctx f g h b = - try f @@ h (g (conv ctx)) - with Deadcode -> b - - let sync ctx reason = lift_fun ctx D.lift S.sync ((|>) reason) `Bot - - let enter ctx r f args = - let liftmap = List.map (fun (x,y) -> D.lift x, D.lift y) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) [] - - let paths_as_set ctx = - let liftmap = List.map (fun x -> D.lift x) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) [D.bot ()] (* One dead path instead of none, such that combine_env gets called for functions with dead normal return (and thus longjmpy returns can be correctly handled by lifter). *) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun (x) -> x q) (Queries.Result.bot q) - let assign ctx lv e = lift_fun ctx D.lift S.assign ((|>) e % (|>) lv) `Bot - let vdecl ctx v = lift_fun ctx D.lift S.vdecl ((|>) v) `Bot - let branch ctx e tv = lift_fun ctx D.lift S.branch ((|>) tv % (|>) e) `Bot - let body ctx f = lift_fun ctx D.lift S.body ((|>) f) `Bot - let return ctx r f = lift_fun ctx D.lift S.return ((|>) f % (|>) r) `Bot - let asm ctx = lift_fun ctx D.lift S.asm identity `Bot - let skip ctx = lift_fun ctx D.lift S.skip identity `Bot - let special ctx r f args = lift_fun ctx D.lift S.special ((|>) args % (|>) f % (|>) r) `Bot - 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 ~multiple lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] - 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 module type Increment = sig @@ -1037,674 +540,3 @@ struct {obsolete; delete; reluctant; restart} end - - -(** Add path sensitivity to a analysis *) -module PathSensitive2 (Spec:Spec) - : Spec - with module G = Spec.G - and module C = Spec.C - and module V = Spec.V -= -struct - module D = - struct - (* TODO is it really worth it to check every time instead of just using sets and joining later? *) - module R = - struct - include Spec.P - type elt = Spec.D.t - end - module J = SetDomain.Joined (Spec.D) - include DisjointDomain.ProjectiveSet (Spec.D) (J) (R) - let name () = "PathSensitive (" ^ name () ^ ")" - - let printXml f x = - let print_one x = - BatPrintf.fprintf f "\n%a" Spec.D.printXml x - in - iter print_one x - end - - module G = Spec.G - module C = Spec.C - module V = Spec.V - module P = UnitP - - let name () = "PathSensitive2("^Spec.name ()^")" - - type marshal = Spec.marshal - let init = Spec.init - let finalize = Spec.finalize - - let startcontext () = Spec.startcontext () - let exitstate v = D.singleton (Spec.exitstate v) - let startstate v = D.singleton (Spec.startstate v) - let morphstate v d = D.map (Spec.morphstate v) d - - let conv ctx x = - let rec ctx' = { ctx with ask = (fun (type a) (q: a Queries.t) -> Spec.query ctx' q) - ; local = x - ; split = (ctx.split % D.singleton) } - in - ctx' - - let context ctx fd l = - if D.cardinal l <> 1 then - failwith "PathSensitive2.context must be called with a singleton set." - else - let x = D.choose l in - Spec.context (conv ctx x) fd x - - - let map ctx f g = - let h x xs = - try D.add (g (f (conv ctx x))) xs - with Deadcode -> xs - in - let d = D.fold h ctx.local (D.empty ()) in - if D.is_bot d then raise Deadcode else d - - let fold' ctx f g h a = - let k x a = - try h a @@ g @@ f @@ conv ctx x - with Deadcode -> a - in - D.fold k ctx.local a - - let assign ctx l e = map ctx Spec.assign (fun h -> h l e ) - let vdecl ctx v = map ctx Spec.vdecl (fun h -> h v) - let body ctx f = map ctx Spec.body (fun h -> h f ) - let return ctx e f = map ctx Spec.return (fun h -> h e f ) - let branch ctx e tv = map ctx Spec.branch (fun h -> h e tv) - let asm ctx = map ctx Spec.asm identity - let skip ctx = map ctx Spec.skip identity - let special ctx l f a = map ctx Spec.special (fun h -> h l f a) - - let event ctx e octx = - let fd1 = D.choose octx.local in - map ctx Spec.event (fun h -> h e (conv octx fd1)) - - 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 [] - - let threadspawn ctx ~multiple lval f args fctx = - let fd1 = D.choose fctx.local in - 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) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - (* TODO: handle Invariant path like PathSensitive3? *) - (* join results so that they are sound for all paths *) - let module Result = (val Queries.Result.lattice q) in - fold' ctx Spec.query identity (fun x f -> Result.join x (f q)) (Result.bot ()) - - let enter ctx l f a = - let g xs ys = (List.map (fun (x,y) -> D.singleton x, D.singleton y) ys) @ xs in - fold' ctx Spec.enter (fun h -> h l f a) g [] - - let paths_as_set ctx = - (* Path-sensitivity is only here, not below! *) - let elems = D.elements ctx.local in - List.map (D.singleton) elems - - let combine_env ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_env (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d - - let combine_assign ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_assign (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d -end - -module DeadBranchLifter (S: Spec): Spec = -struct - include S - - let name () = "DeadBranch (" ^ S.name () ^ ")" - - (* Two global invariants: - 1. S.V -> S.G -- used for S - 2. node -> (exp -> flat bool) -- used for warnings *) - - module V = - struct - include Printable.EitherConf (struct let expand1 = false let expand2 = true end) (S.V) (Node) - let name () = "DeadBranch" - let s x = `Left x - let node x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | `Right _ -> true - end - - module EM = - struct - include MapDomain.MapBot (Basetype.CilExp) (BoolDomain.FlatBool) - let name () = "branches" - end - - module G = - struct - include Lattice.Lift2 (S.G) (EM) - let name () = "deadbranch" - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "DeadBranchLifter.s" - let node = function - | `Bot -> EM.bot () - | `Lifted2 x -> x - | _ -> failwith "DeadBranchLifter.node" - let create_s s = `Lifted1 s - let create_node node = `Lifted2 node - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" EM.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | `Right g -> - let em = G.node (ctx.global (V.node g)) in - EM.iter (fun exp tv -> - match tv with - | `Lifted tv -> - let loc = Node.location g in (* TODO: looking up location now doesn't work nicely with incremental *) - let cilinserted = if loc.synthetic then "(possibly inserted by CIL) " else "" in - M.warn ~loc:(Node g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' %sis always %B" d_exp exp cilinserted tv - | `Bot when not (CilType.Exp.equal exp one) -> (* all branches dead *) - M.msg_final Error ~category:Analyzer ~tags:[Category Unsound] "Both branches dead"; - M.error ~loc:(Node g) ~category:Analyzer ~tags:[Category Unsound] "both branches over condition '%a' are dead" d_exp exp - | `Bot (* all branches dead, fine at our inserted Neg(1)-s because no Pos(1) *) - | `Top -> (* may be both true and false *) - () - ) em; - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | `Right g -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - - (* node vars for dead branches *) - begin match vq with - | Node {node; _} -> - vf (Obj.repr (V.node node)) - | _ -> - () - end - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let context ctx = S.context (conv ctx) - - let branch ctx exp tv = - if !AnalysisState.postsolving then ( - try - let r = branch ctx exp tv in - (* branch is live *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); (* record expression with reached tv *) - r - with Deadcode -> - (* branch is dead *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); (* record expression without reached tv *) - raise Deadcode - ) - else ( - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); (* create global variable during solving, to allow postsolving leq hack to pass verify *) - branch ctx exp tv - ) - - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - 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 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end - -module LongjmpLifter (S: Spec): Spec = -struct - include S - - let name () = "Longjmp (" ^ S.name () ^ ")" - - module V = - struct - include Printable.Either3Conf (struct let expand1 = false let expand2 = true let expand3 = true end) (S.V) (Printable.Prod (Node) (C)) (Printable.Prod (CilType.Fundec) (C)) - let name () = "longjmp" - let s x = `Left x - let longjmpto x = `Middle x - let longjmpret x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | _ -> false - end - - module G = - struct - include Lattice.Lift2 (S.G) (S.D) - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "LongjmpLifter.s" - let local = function - | `Bot -> S.D.bot () - | `Lifted2 x -> x - | _ -> failwith "LongjmpLifter.local" - let create_s s = `Lifted1 s - let create_local local = `Lifted2 local - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" S.D.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - (* TODO: vars? *) - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let context ctx = S.context (conv ctx) - - let combine_env ctx lv e f args fc fd f_ask = - let conv_ctx = conv ctx in - let current_fundec = Node.find_fundec ctx.node in - let handle_longjmp (cd, fc, longfd) = - (* This is called per-path. *) - let rec cd_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query cd_ctx q); - local = cd; - } - in - let longfd_ctx = - (* Inner scope to prevent unsynced longfd_ctx from being used. *) - (* Extra sync like with normal combine. *) - let rec sync_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query sync_ctx q); - local = longfd; - prev_node = Function f; - } - in - let synced = S.sync sync_ctx `Join in - let rec longfd_ctx = - { sync_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query longfd_ctx q); - local = synced; - } - in - longfd_ctx - in - let combined = lazy ( (* does not depend on target, do at most once *) - (* Globals are non-problematic here, as they are always carried around without any issues! *) - (* A combine call is mostly needed to ensure locals have appropriate values. *) - (* Using f from called function on purpose here! Needed? *) - S.combine_env cd_ctx None e f args fc longfd_ctx.local (Analyses.ask_of_ctx longfd_ctx) (* no lval because longjmp return skips return value assignment *) - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec combined_ctx = - { cd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query combined_ctx q); - local = Lazy.force combined; - } - in - S.return combined_ctx None current_fundec - ) - in - let (active_targets, _) = longfd_ctx.ask ActiveJumpBuf in - let valid_targets = cd_ctx.ask ValidLongJmp in - let handle_target target = match target with - | JmpBufDomain.BufferEntryOrTop.AllTargets -> () (* The warning is already emitted at the point where the longjmp happens *) - | 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 ( - if M.tracing then Messages.tracel "longjmp" "Fun: Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force combined)) - (* No need to propagate this outwards here, the set of valid longjumps is part of the context, we can never have the same context setting the longjmp multiple times *) - ) - (* Appropriate setjmp is not in current function & current context *) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - else - (* It actually is not handled here but was propagated here spuriously, we already warned at the location where this issue is caused *) - (* As the validlongjumps inside the callee is a a superset of the ones inside the caller *) - () - in - JmpBufDomain.JmpBufSet.iter handle_target active_targets - in - if M.tracing then M.tracel "longjmp" "longfd getg %a" CilType.Fundec.pretty f; - let longfd = G.local (ctx.global (V.longjmpret (f, Option.get fc))) in - if M.tracing then M.tracel "longjmp" "longfd %a" D.pretty longfd; - if not (D.is_bot longfd) then - handle_longjmp (ctx.local, fc, longfd); - S.combine_env (conv_ctx) lv e f args fc fd f_ask - - let combine_assign ctx lv e f args fc fd f_ask = - S.combine_assign (conv ctx) lv e f args fc fd f_ask - - let special ctx lv f args = - let conv_ctx = conv ctx in - match (LibraryFunctions.find f).special args with - | Setjmp {env} -> - (* Handling of returning for the first time *) - let normal_return = S.special conv_ctx lv f args in - let jmp_return = G.local (ctx.global (V.longjmpto (ctx.prev_node, ctx.context ()))) in - if S.D.is_bot jmp_return then - normal_return - else ( - let rec jmp_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query jmp_ctx q); - local = jmp_return; - } - in - let longjmped = S.event jmp_ctx (Events.Longjmped {lval=lv}) jmp_ctx in - S.D.join normal_return longjmped - ) - | Longjmp {env; value} -> - let current_fundec = Node.find_fundec ctx.node in - let handle_path path = ( - let rec path_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query path_ctx q); - local = path; - } - in - let specialed = lazy ( (* does not depend on target, do at most once *) - S.special path_ctx lv f args - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec specialed_ctx = - { path_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query specialed_ctx q); - local = Lazy.force specialed; - } - in - S.return specialed_ctx None current_fundec - ) - in - (* Eval `env` again to avoid having to construct bespoke ctx to ask *) - let targets = path_ctx.ask (EvalJumpBuf env) in - let valid_targets = path_ctx.ask ValidLongJmp in - if M.tracing then Messages.tracel "longjmp" "Jumping to %a" 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.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 ( - if M.tracing then Messages.tracel "longjmp" "Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force specialed)) - ) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then ( - if M.tracing then Messages.tracel "longjmp" "Longjmp to somewhere else, side-effect to %i" (S.C.hash (ctx.context ())); - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - ) - else - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target! (Target %a in Function %a which may have already returned or is in a different thread)" Node.pretty target_node CilType.Fundec.pretty target_fundec - in - if JmpBufDomain.JmpBufSet.is_empty targets then - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target (%a is bot?!)" d_exp env - else - JmpBufDomain.JmpBufSet.iter handle_target targets - ) - in - List.iter handle_path (S.paths_as_set conv_ctx); - if !AnalysisState.should_warn && List.mem "termination" @@ get_string_list "ana.activated" then ( - AnalysisState.svcomp_may_not_terminate := true; - M.warn ~category:Termination "The program might not terminate! (Longjmp)" - ); - S.D.bot () - | _ -> S.special conv_ctx lv f args - let threadenter ctx = S.threadenter (conv ctx) - 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end - - -(** Add cycle detection in the context-sensitive dynamic function call graph to an analysis *) -module RecursionTermLifter (S: Spec) - : Spec with module D = S.D - and module C = S.C -= -(* two global invariants: - - S.V -> S.G - Needed to store the previously built global invariants - - fundec * S.C -> (Set (fundec * S.C)) - The second global invariant maps from the callee fundec and context to a set of caller fundecs and contexts. - This structure therefore stores the context-sensitive call graph. - For example: - let the function f in context c call function g in context c'. - In the global invariant structure it would be stored like this: (g,c') -> {(f, c)} -*) - -struct - include S - - (* contains all the callee fundecs and contexts *) - module V = GVarFC(S.V)(S.C) - - (* Tuple containing the fundec and context of a caller *) - module Call = Printable.Prod (CilType.Fundec) (S.C) - - (* Set containing multiple caller tuples *) - module CallerSet = SetDomain.Make (Call) - - module G = - struct - include Lattice.Lift2 (G) (CallerSet) - - let spec = function - | `Bot -> G.bot () - | `Lifted1 x -> x - | _ -> failwith "RecursionTermLifter.spec" - - let callers = function - | `Bot -> CallerSet.bot () - | `Lifted2 x -> x - | _ -> failwith "RecursionTermLifter.callGraph" - - let create_spec spec = `Lifted1 spec - let create_singleton_caller caller = `Lifted2 (CallerSet.singleton caller) - - let printXml f = function - | `Lifted1 x -> G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" CallerSet.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - - end - - let name () = "RecursionTermLifter (" ^ S.name () ^ ")" - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.spec (ctx.global (V.spec v))); - sideg = (fun v g -> ctx.sideg (V.spec v) (G.create_spec g)); - } - - let cycleDetection ctx call = - let module LH = Hashtbl.Make (Printable.Prod (CilType.Fundec) (S.C)) in - let module LS = Set.Make (Printable.Prod (CilType.Fundec) (S.C)) in - (* find all cycles/SCCs *) - let global_visited_calls = LH.create 100 in - - (* DFS *) - let rec iter_call (path_visited_calls: LS.t) ((fundec, _) as call) = - if LS.mem call path_visited_calls then ( - AnalysisState.svcomp_may_not_terminate := true; (*set the indicator for a non-terminating program for the sv comp*) - (*Cycle found*) - let loc = M.Location.CilLocation fundec.svar.vdecl in - M.warn ~loc ~category:Termination "The program might not terminate! (Fundec %a is contained in a call graph cycle)" CilType.Fundec.pretty fundec) (* output a warning for non-termination*) - else if not (LH.mem global_visited_calls call) then begin - LH.replace global_visited_calls call (); - let new_path_visited_calls = LS.add call path_visited_calls in - let gvar = V.call call in - let callers = G.callers (ctx.global gvar) in - CallerSet.iter (fun to_call -> - iter_call new_path_visited_calls to_call - ) callers; - end - in - iter_call LS.empty call - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal v -> - (* check result of loop analysis *) - if not (ctx.ask Queries.MustTermAllLoops) then - AnalysisState.svcomp_may_not_terminate := true; - let v: V.t = Obj.obj v in - begin match v with - | `Left v' -> - S.query (conv ctx) (WarnGlobal (Obj.repr v')) - | `Right call -> cycleDetection ctx call (* Note: to make it more efficient, one could only execute the cycle detection in case the loop analysis returns true, because otherwise the program will probably not terminate anyway*) - end - | InvariantGlobal v -> - let v: V.t = Obj.obj v in - begin match v with - | `Left v -> - S.query (conv ctx) (InvariantGlobal (Obj.repr v)) - | `Right v -> - Queries.Result.top q - end - | _ -> S.query (conv ctx) q - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - - - let record_call sideg callee caller = - sideg (V.call callee) (G.create_singleton_caller caller) - - let enter ctx = S.enter (conv ctx) - let context ctx = S.context (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let combine_env ctx r fe f args fc es f_ask = - if !AnalysisState.postsolving then ( - let c_r: S.C.t = ctx.context () in (* Caller context *) - let nodeF = ctx.node in - let fd_r : fundec = Node.find_fundec nodeF in (* Caller fundec *) - let caller: (fundec * S.C.t) = (fd_r, c_r) in - let c_e: S.C.t = Option.get fc in (* Callee context *) - let fd_e : fundec = f in (* Callee fundec *) - let callee = (fd_e, c_e) in - record_call ctx.sideg callee caller - ); - S.combine_env (conv ctx) r fe f args fc es f_ask - - 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 ~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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end From 7ab1b0b7baca3b9ca30e88121b45f4d34e565620 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:16:54 +0300 Subject: [PATCH 511/689] Reorganize analysis lifters --- src/goblint_lib.ml | 15 +++++++++++---- src/{framework => lifters}/contextGasLifter.ml | 0 src/{framework => lifters}/contextGasLifter.mli | 0 src/{framework => lifters}/specLifters.ml | 0 src/{util => lifters}/wideningTokens.ml | 0 5 files changed, 11 insertions(+), 4 deletions(-) rename src/{framework => lifters}/contextGasLifter.ml (100%) rename src/{framework => lifters}/contextGasLifter.mli (100%) rename src/{framework => lifters}/specLifters.ml (100%) rename src/{util => lifters}/wideningTokens.ml (100%) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 192bf441f5..b8a0c6eedb 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -23,12 +23,10 @@ module CfgTools = CfgTools module Analyses = Analyses module ConstrSys = ConstrSys module Constraints = Constraints -module SpecLifters = SpecLifters module CompareConstraints = CompareConstraints module AnalysisState = AnalysisState module AnalysisStateUtil = AnalysisStateUtil module ControlSpecC = ControlSpecC -module ContextGasLifter = ContextGasLifter (** Master control program (MCP) is the analysis specification for the dynamic product of activated analyses. *) @@ -174,6 +172,17 @@ module AbortUnless = AbortUnless module PtranalAnalysis = PtranalAnalysis +(** {1 Analysis lifters} + + Transformations of analyses into extended analyses. *) + +module SpecLifters = SpecLifters +module ContextGasLifter = ContextGasLifter +module WideningTokens = WideningTokens + +module WitnessConstraints = WitnessConstraints + + (** {1 Domains} Domains used by analysis specifications and constraint systems are {{!Lattice.S} lattices}. @@ -329,7 +338,6 @@ module WitnessUtil = WitnessUtil Automaton-based GraphML witnesses used in SV-COMP. *) module MyARG = MyARG -module WitnessConstraints = WitnessConstraints module ArgTools = ArgTools module Witness = Witness module Graphml = Graphml @@ -340,7 +348,6 @@ module Graphml = Graphml module YamlWitness = YamlWitness module YamlWitnessType = YamlWitnessType -module WideningTokens = WideningTokens (** {3 Violation} diff --git a/src/framework/contextGasLifter.ml b/src/lifters/contextGasLifter.ml similarity index 100% rename from src/framework/contextGasLifter.ml rename to src/lifters/contextGasLifter.ml diff --git a/src/framework/contextGasLifter.mli b/src/lifters/contextGasLifter.mli similarity index 100% rename from src/framework/contextGasLifter.mli rename to src/lifters/contextGasLifter.mli diff --git a/src/framework/specLifters.ml b/src/lifters/specLifters.ml similarity index 100% rename from src/framework/specLifters.ml rename to src/lifters/specLifters.ml diff --git a/src/util/wideningTokens.ml b/src/lifters/wideningTokens.ml similarity index 100% rename from src/util/wideningTokens.ml rename to src/lifters/wideningTokens.ml From 01762ace12408323e501ef0ae7039a708f0c420e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:21:32 +0300 Subject: [PATCH 512/689] Rename SpecLifters -> RecursionTermLifter for split --- src/framework/control.ml | 2 +- src/goblint_lib.ml | 2 +- src/lifters/{specLifters.ml => recursionTermLifter.ml} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lifters/{specLifters.ml => recursionTermLifter.ml} (100%) diff --git a/src/framework/control.ml b/src/framework/control.ml index dff398d00f..eebd50c208 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -9,7 +9,7 @@ open Analyses open ConstrSys open GobConfig open Constraints -open SpecLifters +open RecursionTermLifter module type S2S = Spec2Spec diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index b8a0c6eedb..04c2459723 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -176,7 +176,7 @@ module PtranalAnalysis = PtranalAnalysis Transformations of analyses into extended analyses. *) -module SpecLifters = SpecLifters +module RecursionTermLifter = RecursionTermLifter module ContextGasLifter = ContextGasLifter module WideningTokens = WideningTokens diff --git a/src/lifters/specLifters.ml b/src/lifters/recursionTermLifter.ml similarity index 100% rename from src/lifters/specLifters.ml rename to src/lifters/recursionTermLifter.ml From 0beb786d9fae26b0c7d0ff5d63c60a3307937ec8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:22:39 +0300 Subject: [PATCH 513/689] Remove non-recursion lifters from RecursionTermLifter --- src/lifters/recursionTermLifter.ml | 1025 ---------------------------- 1 file changed, 1025 deletions(-) diff --git a/src/lifters/recursionTermLifter.ml b/src/lifters/recursionTermLifter.ml index 2012b5cdcf..3de3810569 100644 --- a/src/lifters/recursionTermLifter.ml +++ b/src/lifters/recursionTermLifter.ml @@ -1,1030 +1,5 @@ -open Batteries open GoblintCil open Analyses -open GobConfig - - -(** Lifts a [Spec] so that the domain is [Hashcons]d *) -module HashconsLifter (S:Spec) - : Spec with module G = S.G - and module C = S.C -= -struct - module HConsedArg = - struct - (* 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 assume_idempotent = GobConfig.get_string "ana.int.refinement" = "never" - end - module D = Lattice.HConsed (S.D) (HConsedArg) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt x = of_elt (D.unlift x) - end - - let name () = S.name () ^" hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate v = D.lift (S.startstate v) - let exitstate v = D.lift (S.exitstate v) - let morphstate v d = D.lift (S.morphstate v (D.unlift d)) - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - let startcontext () = S.startcontext () - - let sync ctx reason = - D.lift @@ S.sync (conv ctx) reason - - let query ctx = - S.query (conv ctx) - - let assign ctx lv e = - D.lift @@ S.assign (conv ctx) lv e - - let vdecl ctx v = - D.lift @@ S.vdecl (conv ctx) v - - let branch ctx e tv = - D.lift @@ S.branch (conv ctx) e tv - - let body ctx f = - D.lift @@ S.body (conv ctx) f - - let return ctx r f = - D.lift @@ S.return (conv ctx) r f - - let asm ctx = - D.lift @@ S.asm (conv ctx) - - let skip ctx = - D.lift @@ S.skip (conv ctx) - - let enter ctx r f args = - List.map (fun (x,y) -> D.lift x, D.lift y) @@ S.enter (conv ctx) r f args - - let special ctx r f args = - D.lift @@ S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - D.lift @@ S.combine_env (conv ctx) r fe f args fc (D.unlift es) f_ask - - 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 ~multiple lval f args = - List.map D.lift @@ S.threadenter (conv ctx) ~multiple lval f args - - 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) - - let event ctx e octx = - D.lift @@ S.event (conv ctx) e (conv octx) -end - -(** Lifts a [Spec] so that the context is [Hashcons]d. *) -module HashconsContextLifter (S:Spec) - : Spec with module D = S.D - and module G = S.G - and module C = Printable.HConsed (S.C) -= -struct - module D = S.D - module G = S.G - module C = Printable.HConsed (S.C) - module V = S.V - module P = S.P - - let name () = S.name () ^" context hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate = S.startstate - let exitstate = S.exitstate - let morphstate = S.morphstate - - let conv ctx = - { ctx with context = (fun () -> C.unlift (ctx.context ())) } - - let context ctx fd = C.lift % S.context (conv ctx) fd - let startcontext () = C.lift @@ S.startcontext () - - let sync ctx reason = - S.sync (conv ctx) reason - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.IterPrevVars f -> - let g i (n, c, j) e = f i (n, Obj.repr (C.lift (Obj.obj c)), j) e in - S.query (conv ctx) (Queries.IterPrevVars g) - | _ -> S.query (conv ctx) q - - let assign ctx lv e = - S.assign (conv ctx) lv e - - let vdecl ctx v = - S.vdecl (conv ctx) v - - let branch ctx e tv = - S.branch (conv ctx) e tv - - let body ctx f = - S.body (conv ctx) f - - let return ctx r f = - S.return (conv ctx) r f - - let asm ctx = - S.asm (conv ctx) - - let skip ctx = - S.skip (conv ctx) - - let enter ctx r f args = - S.enter (conv ctx) r f args - - let special ctx r f args = - S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - S.combine_env (conv ctx) r fe f args (Option.map C.unlift fc) es f_ask - - 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 ~multiple lval f args = - S.threadenter (conv ctx) ~multiple lval f args - - 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) -end - -(* see option ana.opt.equal *) -module OptEqual (S: Spec) = struct - module D = struct include S.D let equal x y = x == y || equal x y end - module G = struct include S.G let equal x y = x == y || equal x y end - module C = struct include S.C let equal x y = x == y || equal x y end - include (S : Spec with module D := D and module G := G and module C := C) -end - -(** If dbg.slice.on, stops entering functions after dbg.slice.n levels. *) -module LevelSliceLifter (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - and module G = S.G - and module C = S.C -= -struct - module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - let name () = S.name ()^" level sliced" - - let start_level = ref (`Top) - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init marshal = - if get_bool "dbg.slice.on" then - start_level := `Lifted (Int64.of_int (get_int "dbg.slice.n")); - S.init marshal - - let finalize = S.finalize - - let startstate v = (S.startstate v, !start_level) - let exitstate v = (S.exitstate v, !start_level) - let morphstate v (d,l) = (S.morphstate v d, l) - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,_) = S.context (conv ctx) fd d - let startcontext () = S.startcontext () - - let lift_fun ctx f g h = - f @@ h (g (conv ctx)) - - let enter' ctx r f args = - let liftmap = List.map (fun (x,y) -> (x, snd ctx.local), (y, snd ctx.local)) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) - - let lift ctx d = (d, snd ctx.local) - let lift_start_level d = (d, !start_level) - - let sync ctx reason = lift_fun ctx (lift ctx) S.sync ((|>) reason) - let query' ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun x -> x q) - let assign ctx lv e = lift_fun ctx (lift ctx) S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx (lift ctx) S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx (lift ctx) S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx (lift ctx) S.body ((|>) f) - let return ctx r f = lift_fun ctx (lift ctx) S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx (lift ctx) S.asm identity - let skip ctx = lift_fun ctx (lift ctx) S.skip identity - let special ctx r f args = lift_fun ctx (lift ctx) S.special ((|>) args % (|>) f % (|>) r) - 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 ~multiple lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) 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 - | `Lifted x -> x <= 0L - | `Bot -> true - - let sub1 = function - | `Lifted x -> `Lifted (Int64.sub x 1L) - | x -> x - - let add1 = function - | `Lifted x -> `Lifted (Int64.add x 1L) - | x -> x - - let paths_as_set ctx = - let liftmap = List.map (fun x -> (x, snd ctx.local)) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) - - let event ctx e octx = - lift_fun ctx (lift ctx) S.event ((|>) (conv octx) % (|>) e) - - let enter ctx r f args = - let (d,l) = ctx.local in - if leq0 l then - [ctx.local, D.bot ()] - else - enter' {ctx with local=(d, sub1 l)} r f args - - let combine_env ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - let l = add1 l in - if leq0 l then - (d, l) - else - let d',_ = combine_env' ctx r fe f args fc es f_ask in - (d', l) - - let combine_assign ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - (* No need to add1 here, already done in combine_env. *) - if leq0 l then - (d, l) - else - let d',_ = combine_assign' ctx r fe f args fc es f_ask in - (d', l) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.EvalFunvar e -> - let (d,l) = ctx.local in - if leq0 l then - Queries.AD.empty () - else - query' ctx (Queries.EvalFunvar e) - | q -> query' ctx q -end - - -(** Limits the number of widenings per node. *) -module LimitLifter (S:Spec) = -struct - include (S : module type of S with module D := S.D and type marshal = S.marshal) - - let name () = S.name ()^" limited" - - let limit = ref 0 - - let init marshal = - limit := get_int "dbg.limit.widen"; - S.init marshal - - module H = MyCFG.NodeH - let h = H.create 13 - let incr k = - H.modify_def 1 k (fun v -> - if v >= !limit then failwith (GobPretty.sprintf "LimitLifter: Reached limit (%d) for node %a" !limit Node.pretty_plain_short (Option.get !MyCFG.current_node)); - v+1 - ) h; - module D = struct - include S.D - let widen x y = Option.may incr !MyCFG.current_node; widen x y (* when is this None? *) - end -end - - -(* widening on contexts, keeps contexts for calls only in D *) -module WidenContextLifterSide (S:Spec) -= -struct - module DD = - struct - include S.D - let printXml f d = BatPrintf.fprintf f "%a" printXml d - end - module M = MapDomain.MapBot (Basetype.Variables) (DD) (* should be CilFun -> S.C, but CilFun is not Groupable, and S.C is no Lattice *) - - module D = struct - include Lattice.Prod (S.D) (M) - let printXml f (d,m) = BatPrintf.fprintf f "\n%a\n%a\n" S.D.printXml d M.printXml m - end - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - - let name () = S.name ()^" with widened contexts" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - let inj f x = f x, M.bot () - - let startcontext () = S.startcontext () - let startstate = inj S.startstate - let exitstate = inj S.exitstate - let morphstate v (d,m) = S.morphstate v d, m - - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,m) = S.context (conv ctx) fd d (* just the child analysis' context *) - - let lift_fun ctx f g = g (f (conv ctx)), snd ctx.local - - let sync ctx reason = lift_fun ctx S.sync ((|>) reason) - let query ctx = S.query (conv ctx) - let assign ctx lv e = lift_fun ctx S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx S.body ((|>) f) - let return ctx r f = lift_fun ctx S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx S.asm identity - let skip ctx = lift_fun ctx S.skip identity - let special ctx r f args = lift_fun ctx S.special ((|>) args % (|>) f % (|>) r) - - 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 ~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 - let d' v_cur = - if ContextUtil.should_keep ~isAttr:GobContext ~keepOption:"ana.context.widen" ~keepAttr:"widen" ~removeAttr:"no-widen" f then ( - let v_old = M.find f.svar m in (* S.D.bot () if not found *) - let v_new = S.D.widen v_old (S.D.join v_old v_cur) in - Messages.(if tracing && not (S.D.equal v_old v_new) then tracel "widen-context" "enter results in new context for function %s" f.svar.vname); - v_new, M.add f.svar v_new m - ) - else - v_cur, m - in - S.enter (conv ctx) r f args - |> List.map (fun (c,v) -> (c,m), d' v) (* c: caller, v: callee *) - - let paths_as_set ctx = - let m = snd ctx.local in - S.paths_as_set (conv ctx) |> List.map (fun v -> (v,m)) - - let combine_env ctx r fe f args fc es f_ask = lift_fun 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 S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) -end - - -(** Lifts a [Spec] with a special bottom element that represent unreachable code. *) -module DeadCodeLifter (S:Spec) - : Spec with module D = Dom (S.D) - and module G = S.G - and module C = S.C -= -struct - module D = Dom (S.D) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include Printable.Option (S.P) (struct let name = "None" end) - - let of_elt = function - | `Lifted x -> Some (S.P.of_elt x) - | _ -> None - end - - let name () = S.name ()^" lifted" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - - let startcontext () = S.startcontext () - let startstate v = `Lifted (S.startstate v) - let exitstate v = `Lifted (S.exitstate v) - let morphstate v d = try `Lifted (S.morphstate v (D.unlift d)) with Deadcode -> d - - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - - let lift_fun ctx f g h b = - try f @@ h (g (conv ctx)) - with Deadcode -> b - - let sync ctx reason = lift_fun ctx D.lift S.sync ((|>) reason) `Bot - - let enter ctx r f args = - let liftmap = List.map (fun (x,y) -> D.lift x, D.lift y) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) [] - - let paths_as_set ctx = - let liftmap = List.map (fun x -> D.lift x) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) [D.bot ()] (* One dead path instead of none, such that combine_env gets called for functions with dead normal return (and thus longjmpy returns can be correctly handled by lifter). *) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun (x) -> x q) (Queries.Result.bot q) - let assign ctx lv e = lift_fun ctx D.lift S.assign ((|>) e % (|>) lv) `Bot - let vdecl ctx v = lift_fun ctx D.lift S.vdecl ((|>) v) `Bot - let branch ctx e tv = lift_fun ctx D.lift S.branch ((|>) tv % (|>) e) `Bot - let body ctx f = lift_fun ctx D.lift S.body ((|>) f) `Bot - let return ctx r f = lift_fun ctx D.lift S.return ((|>) f % (|>) r) `Bot - let asm ctx = lift_fun ctx D.lift S.asm identity `Bot - let skip ctx = lift_fun ctx D.lift S.skip identity `Bot - let special ctx r f args = lift_fun ctx D.lift S.special ((|>) args % (|>) f % (|>) r) `Bot - 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 ~multiple lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] - 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 - - -(** Add path sensitivity to a analysis *) -module PathSensitive2 (Spec:Spec) - : Spec - with module G = Spec.G - and module C = Spec.C - and module V = Spec.V -= -struct - module D = - struct - (* TODO is it really worth it to check every time instead of just using sets and joining later? *) - module R = - struct - include Spec.P - type elt = Spec.D.t - end - module J = SetDomain.Joined (Spec.D) - include DisjointDomain.ProjectiveSet (Spec.D) (J) (R) - let name () = "PathSensitive (" ^ name () ^ ")" - - let printXml f x = - let print_one x = - BatPrintf.fprintf f "\n%a" Spec.D.printXml x - in - iter print_one x - end - - module G = Spec.G - module C = Spec.C - module V = Spec.V - module P = UnitP - - let name () = "PathSensitive2("^Spec.name ()^")" - - type marshal = Spec.marshal - let init = Spec.init - let finalize = Spec.finalize - - let startcontext () = Spec.startcontext () - let exitstate v = D.singleton (Spec.exitstate v) - let startstate v = D.singleton (Spec.startstate v) - let morphstate v d = D.map (Spec.morphstate v) d - - let conv ctx x = - let rec ctx' = { ctx with ask = (fun (type a) (q: a Queries.t) -> Spec.query ctx' q) - ; local = x - ; split = (ctx.split % D.singleton) } - in - ctx' - - let context ctx fd l = - if D.cardinal l <> 1 then - failwith "PathSensitive2.context must be called with a singleton set." - else - let x = D.choose l in - Spec.context (conv ctx x) fd x - - - let map ctx f g = - let h x xs = - try D.add (g (f (conv ctx x))) xs - with Deadcode -> xs - in - let d = D.fold h ctx.local (D.empty ()) in - if D.is_bot d then raise Deadcode else d - - let fold' ctx f g h a = - let k x a = - try h a @@ g @@ f @@ conv ctx x - with Deadcode -> a - in - D.fold k ctx.local a - - let assign ctx l e = map ctx Spec.assign (fun h -> h l e ) - let vdecl ctx v = map ctx Spec.vdecl (fun h -> h v) - let body ctx f = map ctx Spec.body (fun h -> h f ) - let return ctx e f = map ctx Spec.return (fun h -> h e f ) - let branch ctx e tv = map ctx Spec.branch (fun h -> h e tv) - let asm ctx = map ctx Spec.asm identity - let skip ctx = map ctx Spec.skip identity - let special ctx l f a = map ctx Spec.special (fun h -> h l f a) - - let event ctx e octx = - let fd1 = D.choose octx.local in - map ctx Spec.event (fun h -> h e (conv octx fd1)) - - 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 [] - - let threadspawn ctx ~multiple lval f args fctx = - let fd1 = D.choose fctx.local in - 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) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - (* TODO: handle Invariant path like PathSensitive3? *) - (* join results so that they are sound for all paths *) - let module Result = (val Queries.Result.lattice q) in - fold' ctx Spec.query identity (fun x f -> Result.join x (f q)) (Result.bot ()) - - let enter ctx l f a = - let g xs ys = (List.map (fun (x,y) -> D.singleton x, D.singleton y) ys) @ xs in - fold' ctx Spec.enter (fun h -> h l f a) g [] - - let paths_as_set ctx = - (* Path-sensitivity is only here, not below! *) - let elems = D.elements ctx.local in - List.map (D.singleton) elems - - let combine_env ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_env (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d - - let combine_assign ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_assign (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d -end - -module DeadBranchLifter (S: Spec): Spec = -struct - include S - - let name () = "DeadBranch (" ^ S.name () ^ ")" - - (* Two global invariants: - 1. S.V -> S.G -- used for S - 2. node -> (exp -> flat bool) -- used for warnings *) - - module V = - struct - include Printable.EitherConf (struct let expand1 = false let expand2 = true end) (S.V) (Node) - let name () = "DeadBranch" - let s x = `Left x - let node x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | `Right _ -> true - end - - module EM = - struct - include MapDomain.MapBot (Basetype.CilExp) (BoolDomain.FlatBool) - let name () = "branches" - end - - module G = - struct - include Lattice.Lift2 (S.G) (EM) - let name () = "deadbranch" - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "DeadBranchLifter.s" - let node = function - | `Bot -> EM.bot () - | `Lifted2 x -> x - | _ -> failwith "DeadBranchLifter.node" - let create_s s = `Lifted1 s - let create_node node = `Lifted2 node - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" EM.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | `Right g -> - let em = G.node (ctx.global (V.node g)) in - EM.iter (fun exp tv -> - match tv with - | `Lifted tv -> - let loc = Node.location g in (* TODO: looking up location now doesn't work nicely with incremental *) - let cilinserted = if loc.synthetic then "(possibly inserted by CIL) " else "" in - M.warn ~loc:(Node g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' %sis always %B" d_exp exp cilinserted tv - | `Bot when not (CilType.Exp.equal exp one) -> (* all branches dead *) - M.msg_final Error ~category:Analyzer ~tags:[Category Unsound] "Both branches dead"; - M.error ~loc:(Node g) ~category:Analyzer ~tags:[Category Unsound] "both branches over condition '%a' are dead" d_exp exp - | `Bot (* all branches dead, fine at our inserted Neg(1)-s because no Pos(1) *) - | `Top -> (* may be both true and false *) - () - ) em; - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | `Right g -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - - (* node vars for dead branches *) - begin match vq with - | Node {node; _} -> - vf (Obj.repr (V.node node)) - | _ -> - () - end - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let context ctx = S.context (conv ctx) - - let branch ctx exp tv = - if !AnalysisState.postsolving then ( - try - let r = branch ctx exp tv in - (* branch is live *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); (* record expression with reached tv *) - r - with Deadcode -> - (* branch is dead *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); (* record expression without reached tv *) - raise Deadcode - ) - else ( - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); (* create global variable during solving, to allow postsolving leq hack to pass verify *) - branch ctx exp tv - ) - - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - 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 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end - -module LongjmpLifter (S: Spec): Spec = -struct - include S - - let name () = "Longjmp (" ^ S.name () ^ ")" - - module V = - struct - include Printable.Either3Conf (struct let expand1 = false let expand2 = true let expand3 = true end) (S.V) (Printable.Prod (Node) (C)) (Printable.Prod (CilType.Fundec) (C)) - let name () = "longjmp" - let s x = `Left x - let longjmpto x = `Middle x - let longjmpret x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | _ -> false - end - - module G = - struct - include Lattice.Lift2 (S.G) (S.D) - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "LongjmpLifter.s" - let local = function - | `Bot -> S.D.bot () - | `Lifted2 x -> x - | _ -> failwith "LongjmpLifter.local" - let create_s s = `Lifted1 s - let create_local local = `Lifted2 local - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" S.D.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - (* TODO: vars? *) - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let context ctx = S.context (conv ctx) - - let combine_env ctx lv e f args fc fd f_ask = - let conv_ctx = conv ctx in - let current_fundec = Node.find_fundec ctx.node in - let handle_longjmp (cd, fc, longfd) = - (* This is called per-path. *) - let rec cd_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query cd_ctx q); - local = cd; - } - in - let longfd_ctx = - (* Inner scope to prevent unsynced longfd_ctx from being used. *) - (* Extra sync like with normal combine. *) - let rec sync_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query sync_ctx q); - local = longfd; - prev_node = Function f; - } - in - let synced = S.sync sync_ctx `Join in - let rec longfd_ctx = - { sync_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query longfd_ctx q); - local = synced; - } - in - longfd_ctx - in - let combined = lazy ( (* does not depend on target, do at most once *) - (* Globals are non-problematic here, as they are always carried around without any issues! *) - (* A combine call is mostly needed to ensure locals have appropriate values. *) - (* Using f from called function on purpose here! Needed? *) - S.combine_env cd_ctx None e f args fc longfd_ctx.local (Analyses.ask_of_ctx longfd_ctx) (* no lval because longjmp return skips return value assignment *) - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec combined_ctx = - { cd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query combined_ctx q); - local = Lazy.force combined; - } - in - S.return combined_ctx None current_fundec - ) - in - let (active_targets, _) = longfd_ctx.ask ActiveJumpBuf in - let valid_targets = cd_ctx.ask ValidLongJmp in - let handle_target target = match target with - | JmpBufDomain.BufferEntryOrTop.AllTargets -> () (* The warning is already emitted at the point where the longjmp happens *) - | 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 ( - if M.tracing then Messages.tracel "longjmp" "Fun: Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force combined)) - (* No need to propagate this outwards here, the set of valid longjumps is part of the context, we can never have the same context setting the longjmp multiple times *) - ) - (* Appropriate setjmp is not in current function & current context *) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - else - (* It actually is not handled here but was propagated here spuriously, we already warned at the location where this issue is caused *) - (* As the validlongjumps inside the callee is a a superset of the ones inside the caller *) - () - in - JmpBufDomain.JmpBufSet.iter handle_target active_targets - in - if M.tracing then M.tracel "longjmp" "longfd getg %a" CilType.Fundec.pretty f; - let longfd = G.local (ctx.global (V.longjmpret (f, Option.get fc))) in - if M.tracing then M.tracel "longjmp" "longfd %a" D.pretty longfd; - if not (D.is_bot longfd) then - handle_longjmp (ctx.local, fc, longfd); - S.combine_env (conv_ctx) lv e f args fc fd f_ask - - let combine_assign ctx lv e f args fc fd f_ask = - S.combine_assign (conv ctx) lv e f args fc fd f_ask - - let special ctx lv f args = - let conv_ctx = conv ctx in - match (LibraryFunctions.find f).special args with - | Setjmp {env} -> - (* Handling of returning for the first time *) - let normal_return = S.special conv_ctx lv f args in - let jmp_return = G.local (ctx.global (V.longjmpto (ctx.prev_node, ctx.context ()))) in - if S.D.is_bot jmp_return then - normal_return - else ( - let rec jmp_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query jmp_ctx q); - local = jmp_return; - } - in - let longjmped = S.event jmp_ctx (Events.Longjmped {lval=lv}) jmp_ctx in - S.D.join normal_return longjmped - ) - | Longjmp {env; value} -> - let current_fundec = Node.find_fundec ctx.node in - let handle_path path = ( - let rec path_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query path_ctx q); - local = path; - } - in - let specialed = lazy ( (* does not depend on target, do at most once *) - S.special path_ctx lv f args - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec specialed_ctx = - { path_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query specialed_ctx q); - local = Lazy.force specialed; - } - in - S.return specialed_ctx None current_fundec - ) - in - (* Eval `env` again to avoid having to construct bespoke ctx to ask *) - let targets = path_ctx.ask (EvalJumpBuf env) in - let valid_targets = path_ctx.ask ValidLongJmp in - if M.tracing then Messages.tracel "longjmp" "Jumping to %a" 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.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 ( - if M.tracing then Messages.tracel "longjmp" "Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force specialed)) - ) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then ( - if M.tracing then Messages.tracel "longjmp" "Longjmp to somewhere else, side-effect to %i" (S.C.hash (ctx.context ())); - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - ) - else - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target! (Target %a in Function %a which may have already returned or is in a different thread)" Node.pretty target_node CilType.Fundec.pretty target_fundec - in - if JmpBufDomain.JmpBufSet.is_empty targets then - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target (%a is bot?!)" d_exp env - else - JmpBufDomain.JmpBufSet.iter handle_target targets - ) - in - List.iter handle_path (S.paths_as_set conv_ctx); - if !AnalysisState.should_warn && List.mem "termination" @@ get_string_list "ana.activated" then ( - AnalysisState.svcomp_may_not_terminate := true; - M.warn ~category:Termination "The program might not terminate! (Longjmp)" - ); - S.D.bot () - | _ -> S.special conv_ctx lv f args - let threadenter ctx = S.threadenter (conv ctx) - 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end (** Add cycle detection in the context-sensitive dynamic function call graph to an analysis *) From cb405d752a45f80cc610552805e7014117ee37dc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:23:11 +0300 Subject: [PATCH 514/689] Remove RecursionTermLifter from SpecLifters --- src/lifters/specLifters.ml | 144 ------------------------------------- 1 file changed, 144 deletions(-) diff --git a/src/lifters/specLifters.ml b/src/lifters/specLifters.ml index 2012b5cdcf..1be137cf8c 100644 --- a/src/lifters/specLifters.ml +++ b/src/lifters/specLifters.ml @@ -1025,147 +1025,3 @@ struct let asm ctx = S.asm (conv ctx) let event ctx e octx = S.event (conv ctx) e (conv octx) end - - -(** Add cycle detection in the context-sensitive dynamic function call graph to an analysis *) -module RecursionTermLifter (S: Spec) - : Spec with module D = S.D - and module C = S.C -= -(* two global invariants: - - S.V -> S.G - Needed to store the previously built global invariants - - fundec * S.C -> (Set (fundec * S.C)) - The second global invariant maps from the callee fundec and context to a set of caller fundecs and contexts. - This structure therefore stores the context-sensitive call graph. - For example: - let the function f in context c call function g in context c'. - In the global invariant structure it would be stored like this: (g,c') -> {(f, c)} -*) - -struct - include S - - (* contains all the callee fundecs and contexts *) - module V = GVarFC(S.V)(S.C) - - (* Tuple containing the fundec and context of a caller *) - module Call = Printable.Prod (CilType.Fundec) (S.C) - - (* Set containing multiple caller tuples *) - module CallerSet = SetDomain.Make (Call) - - module G = - struct - include Lattice.Lift2 (G) (CallerSet) - - let spec = function - | `Bot -> G.bot () - | `Lifted1 x -> x - | _ -> failwith "RecursionTermLifter.spec" - - let callers = function - | `Bot -> CallerSet.bot () - | `Lifted2 x -> x - | _ -> failwith "RecursionTermLifter.callGraph" - - let create_spec spec = `Lifted1 spec - let create_singleton_caller caller = `Lifted2 (CallerSet.singleton caller) - - let printXml f = function - | `Lifted1 x -> G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" CallerSet.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - - end - - let name () = "RecursionTermLifter (" ^ S.name () ^ ")" - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.spec (ctx.global (V.spec v))); - sideg = (fun v g -> ctx.sideg (V.spec v) (G.create_spec g)); - } - - let cycleDetection ctx call = - let module LH = Hashtbl.Make (Printable.Prod (CilType.Fundec) (S.C)) in - let module LS = Set.Make (Printable.Prod (CilType.Fundec) (S.C)) in - (* find all cycles/SCCs *) - let global_visited_calls = LH.create 100 in - - (* DFS *) - let rec iter_call (path_visited_calls: LS.t) ((fundec, _) as call) = - if LS.mem call path_visited_calls then ( - AnalysisState.svcomp_may_not_terminate := true; (*set the indicator for a non-terminating program for the sv comp*) - (*Cycle found*) - let loc = M.Location.CilLocation fundec.svar.vdecl in - M.warn ~loc ~category:Termination "The program might not terminate! (Fundec %a is contained in a call graph cycle)" CilType.Fundec.pretty fundec) (* output a warning for non-termination*) - else if not (LH.mem global_visited_calls call) then begin - LH.replace global_visited_calls call (); - let new_path_visited_calls = LS.add call path_visited_calls in - let gvar = V.call call in - let callers = G.callers (ctx.global gvar) in - CallerSet.iter (fun to_call -> - iter_call new_path_visited_calls to_call - ) callers; - end - in - iter_call LS.empty call - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal v -> - (* check result of loop analysis *) - if not (ctx.ask Queries.MustTermAllLoops) then - AnalysisState.svcomp_may_not_terminate := true; - let v: V.t = Obj.obj v in - begin match v with - | `Left v' -> - S.query (conv ctx) (WarnGlobal (Obj.repr v')) - | `Right call -> cycleDetection ctx call (* Note: to make it more efficient, one could only execute the cycle detection in case the loop analysis returns true, because otherwise the program will probably not terminate anyway*) - end - | InvariantGlobal v -> - let v: V.t = Obj.obj v in - begin match v with - | `Left v -> - S.query (conv ctx) (InvariantGlobal (Obj.repr v)) - | `Right v -> - Queries.Result.top q - end - | _ -> S.query (conv ctx) q - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - - - let record_call sideg callee caller = - sideg (V.call callee) (G.create_singleton_caller caller) - - let enter ctx = S.enter (conv ctx) - let context ctx = S.context (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let combine_env ctx r fe f args fc es f_ask = - if !AnalysisState.postsolving then ( - let c_r: S.C.t = ctx.context () in (* Caller context *) - let nodeF = ctx.node in - let fd_r : fundec = Node.find_fundec nodeF in (* Caller fundec *) - let caller: (fundec * S.C.t) = (fd_r, c_r) in - let c_e: S.C.t = Option.get fc in (* Callee context *) - let fd_e : fundec = f in (* Callee fundec *) - let callee = (fd_e, c_e) in - record_call ctx.sideg callee caller - ); - S.combine_env (conv ctx) r fe f args fc es f_ask - - 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 ~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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end From 8edddc3904298245f9440e2b9a731d29c16d8cdc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:26:09 +0300 Subject: [PATCH 515/689] Rename SpecLifters -> LongjmpLifter for split --- src/framework/control.ml | 2 +- src/goblint_lib.ml | 2 +- src/lifters/{specLifters.ml => longjmpLifter.ml} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lifters/{specLifters.ml => longjmpLifter.ml} (100%) diff --git a/src/framework/control.ml b/src/framework/control.ml index 56f42e78d2..947be9e6b0 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -9,7 +9,7 @@ open Analyses open ConstrSys open GobConfig open Constraints -open SpecLifters +open LongjmpLifter module type S2S = Spec2Spec diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index a1b03fe618..b8d0638bbb 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -176,7 +176,7 @@ module PtranalAnalysis = PtranalAnalysis Transformations of analyses into extended analyses. *) -module SpecLifters = SpecLifters +module LongjmpLifter = LongjmpLifter module RecursionTermLifter = RecursionTermLifter module ContextGasLifter = ContextGasLifter module WideningTokens = WideningTokens diff --git a/src/lifters/specLifters.ml b/src/lifters/longjmpLifter.ml similarity index 100% rename from src/lifters/specLifters.ml rename to src/lifters/longjmpLifter.ml From 259ea677f5a2fbcca481e24de836da03ca39f61e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:26:53 +0300 Subject: [PATCH 516/689] Remove non-longjmp lifters from LongjmpLifter --- src/lifters/longjmpLifter.ml | 780 ----------------------------------- 1 file changed, 780 deletions(-) diff --git a/src/lifters/longjmpLifter.ml b/src/lifters/longjmpLifter.ml index 1be137cf8c..1150bc1bca 100644 --- a/src/lifters/longjmpLifter.ml +++ b/src/lifters/longjmpLifter.ml @@ -1,788 +1,8 @@ -open Batteries open GoblintCil open Analyses open GobConfig -(** Lifts a [Spec] so that the domain is [Hashcons]d *) -module HashconsLifter (S:Spec) - : Spec with module G = S.G - and module C = S.C -= -struct - module HConsedArg = - struct - (* 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 assume_idempotent = GobConfig.get_string "ana.int.refinement" = "never" - end - module D = Lattice.HConsed (S.D) (HConsedArg) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt x = of_elt (D.unlift x) - end - - let name () = S.name () ^" hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate v = D.lift (S.startstate v) - let exitstate v = D.lift (S.exitstate v) - let morphstate v d = D.lift (S.morphstate v (D.unlift d)) - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - let startcontext () = S.startcontext () - - let sync ctx reason = - D.lift @@ S.sync (conv ctx) reason - - let query ctx = - S.query (conv ctx) - - let assign ctx lv e = - D.lift @@ S.assign (conv ctx) lv e - - let vdecl ctx v = - D.lift @@ S.vdecl (conv ctx) v - - let branch ctx e tv = - D.lift @@ S.branch (conv ctx) e tv - - let body ctx f = - D.lift @@ S.body (conv ctx) f - - let return ctx r f = - D.lift @@ S.return (conv ctx) r f - - let asm ctx = - D.lift @@ S.asm (conv ctx) - - let skip ctx = - D.lift @@ S.skip (conv ctx) - - let enter ctx r f args = - List.map (fun (x,y) -> D.lift x, D.lift y) @@ S.enter (conv ctx) r f args - - let special ctx r f args = - D.lift @@ S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - D.lift @@ S.combine_env (conv ctx) r fe f args fc (D.unlift es) f_ask - - 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 ~multiple lval f args = - List.map D.lift @@ S.threadenter (conv ctx) ~multiple lval f args - - 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) - - let event ctx e octx = - D.lift @@ S.event (conv ctx) e (conv octx) -end - -(** Lifts a [Spec] so that the context is [Hashcons]d. *) -module HashconsContextLifter (S:Spec) - : Spec with module D = S.D - and module G = S.G - and module C = Printable.HConsed (S.C) -= -struct - module D = S.D - module G = S.G - module C = Printable.HConsed (S.C) - module V = S.V - module P = S.P - - let name () = S.name () ^" context hashconsed" - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init = S.init - let finalize = S.finalize - - let startstate = S.startstate - let exitstate = S.exitstate - let morphstate = S.morphstate - - let conv ctx = - { ctx with context = (fun () -> C.unlift (ctx.context ())) } - - let context ctx fd = C.lift % S.context (conv ctx) fd - let startcontext () = C.lift @@ S.startcontext () - - let sync ctx reason = - S.sync (conv ctx) reason - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.IterPrevVars f -> - let g i (n, c, j) e = f i (n, Obj.repr (C.lift (Obj.obj c)), j) e in - S.query (conv ctx) (Queries.IterPrevVars g) - | _ -> S.query (conv ctx) q - - let assign ctx lv e = - S.assign (conv ctx) lv e - - let vdecl ctx v = - S.vdecl (conv ctx) v - - let branch ctx e tv = - S.branch (conv ctx) e tv - - let body ctx f = - S.body (conv ctx) f - - let return ctx r f = - S.return (conv ctx) r f - - let asm ctx = - S.asm (conv ctx) - - let skip ctx = - S.skip (conv ctx) - - let enter ctx r f args = - S.enter (conv ctx) r f args - - let special ctx r f args = - S.special (conv ctx) r f args - - let combine_env ctx r fe f args fc es f_ask = - S.combine_env (conv ctx) r fe f args (Option.map C.unlift fc) es f_ask - - 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 ~multiple lval f args = - S.threadenter (conv ctx) ~multiple lval f args - - 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) -end - -(* see option ana.opt.equal *) -module OptEqual (S: Spec) = struct - module D = struct include S.D let equal x y = x == y || equal x y end - module G = struct include S.G let equal x y = x == y || equal x y end - module C = struct include S.C let equal x y = x == y || equal x y end - include (S : Spec with module D := D and module G := G and module C := C) -end - -(** If dbg.slice.on, stops entering functions after dbg.slice.n levels. *) -module LevelSliceLifter (S:Spec) - : Spec with module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - and module G = S.G - and module C = S.C -= -struct - module D = Lattice.Prod (S.D) (Lattice.Reverse (IntDomain.Lifted)) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - let name () = S.name ()^" level sliced" - - let start_level = ref (`Top) - - type marshal = S.marshal (* TODO: should hashcons table be in here to avoid relift altogether? *) - let init marshal = - if get_bool "dbg.slice.on" then - start_level := `Lifted (Int64.of_int (get_int "dbg.slice.n")); - S.init marshal - - let finalize = S.finalize - - let startstate v = (S.startstate v, !start_level) - let exitstate v = (S.exitstate v, !start_level) - let morphstate v (d,l) = (S.morphstate v d, l) - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,_) = S.context (conv ctx) fd d - let startcontext () = S.startcontext () - - let lift_fun ctx f g h = - f @@ h (g (conv ctx)) - - let enter' ctx r f args = - let liftmap = List.map (fun (x,y) -> (x, snd ctx.local), (y, snd ctx.local)) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) - - let lift ctx d = (d, snd ctx.local) - let lift_start_level d = (d, !start_level) - - let sync ctx reason = lift_fun ctx (lift ctx) S.sync ((|>) reason) - let query' ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun x -> x q) - let assign ctx lv e = lift_fun ctx (lift ctx) S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx (lift ctx) S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx (lift ctx) S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx (lift ctx) S.body ((|>) f) - let return ctx r f = lift_fun ctx (lift ctx) S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx (lift ctx) S.asm identity - let skip ctx = lift_fun ctx (lift ctx) S.skip identity - let special ctx r f args = lift_fun ctx (lift ctx) S.special ((|>) args % (|>) f % (|>) r) - 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 ~multiple lval f args = lift_fun ctx (List.map lift_start_level) (S.threadenter ~multiple) ((|>) 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 - | `Lifted x -> x <= 0L - | `Bot -> true - - let sub1 = function - | `Lifted x -> `Lifted (Int64.sub x 1L) - | x -> x - - let add1 = function - | `Lifted x -> `Lifted (Int64.add x 1L) - | x -> x - - let paths_as_set ctx = - let liftmap = List.map (fun x -> (x, snd ctx.local)) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) - - let event ctx e octx = - lift_fun ctx (lift ctx) S.event ((|>) (conv octx) % (|>) e) - - let enter ctx r f args = - let (d,l) = ctx.local in - if leq0 l then - [ctx.local, D.bot ()] - else - enter' {ctx with local=(d, sub1 l)} r f args - - let combine_env ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - let l = add1 l in - if leq0 l then - (d, l) - else - let d',_ = combine_env' ctx r fe f args fc es f_ask in - (d', l) - - let combine_assign ctx r fe f args fc es f_ask = - let (d,l) = ctx.local in - (* No need to add1 here, already done in combine_env. *) - if leq0 l then - (d, l) - else - let d',_ = combine_assign' ctx r fe f args fc es f_ask in - (d', l) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | Queries.EvalFunvar e -> - let (d,l) = ctx.local in - if leq0 l then - Queries.AD.empty () - else - query' ctx (Queries.EvalFunvar e) - | q -> query' ctx q -end - - -(** Limits the number of widenings per node. *) -module LimitLifter (S:Spec) = -struct - include (S : module type of S with module D := S.D and type marshal = S.marshal) - - let name () = S.name ()^" limited" - - let limit = ref 0 - - let init marshal = - limit := get_int "dbg.limit.widen"; - S.init marshal - - module H = MyCFG.NodeH - let h = H.create 13 - let incr k = - H.modify_def 1 k (fun v -> - if v >= !limit then failwith (GobPretty.sprintf "LimitLifter: Reached limit (%d) for node %a" !limit Node.pretty_plain_short (Option.get !MyCFG.current_node)); - v+1 - ) h; - module D = struct - include S.D - let widen x y = Option.may incr !MyCFG.current_node; widen x y (* when is this None? *) - end -end - - -(* widening on contexts, keeps contexts for calls only in D *) -module WidenContextLifterSide (S:Spec) -= -struct - module DD = - struct - include S.D - let printXml f d = BatPrintf.fprintf f "%a" printXml d - end - module M = MapDomain.MapBot (Basetype.Variables) (DD) (* should be CilFun -> S.C, but CilFun is not Groupable, and S.C is no Lattice *) - - module D = struct - include Lattice.Prod (S.D) (M) - let printXml f (d,m) = BatPrintf.fprintf f "\n%a\n%a\n" S.D.printXml d M.printXml m - end - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include S.P - let of_elt (x, _) = of_elt x - end - - - let name () = S.name ()^" with widened contexts" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - let inj f x = f x, M.bot () - - let startcontext () = S.startcontext () - let startstate = inj S.startstate - let exitstate = inj S.exitstate - let morphstate v (d,m) = S.morphstate v d, m - - - let conv ctx = - { ctx with local = fst ctx.local - ; split = (fun d es -> ctx.split (d, snd ctx.local) es ) - } - - let context ctx fd (d,m) = S.context (conv ctx) fd d (* just the child analysis' context *) - - let lift_fun ctx f g = g (f (conv ctx)), snd ctx.local - - let sync ctx reason = lift_fun ctx S.sync ((|>) reason) - let query ctx = S.query (conv ctx) - let assign ctx lv e = lift_fun ctx S.assign ((|>) e % (|>) lv) - let vdecl ctx v = lift_fun ctx S.vdecl ((|>) v) - let branch ctx e tv = lift_fun ctx S.branch ((|>) tv % (|>) e) - let body ctx f = lift_fun ctx S.body ((|>) f) - let return ctx r f = lift_fun ctx S.return ((|>) f % (|>) r) - let asm ctx = lift_fun ctx S.asm identity - let skip ctx = lift_fun ctx S.skip identity - let special ctx r f args = lift_fun ctx S.special ((|>) args % (|>) f % (|>) r) - - 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 ~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 - let d' v_cur = - if ContextUtil.should_keep ~isAttr:GobContext ~keepOption:"ana.context.widen" ~keepAttr:"widen" ~removeAttr:"no-widen" f then ( - let v_old = M.find f.svar m in (* S.D.bot () if not found *) - let v_new = S.D.widen v_old (S.D.join v_old v_cur) in - Messages.(if tracing && not (S.D.equal v_old v_new) then tracel "widen-context" "enter results in new context for function %s" f.svar.vname); - v_new, M.add f.svar v_new m - ) - else - v_cur, m - in - S.enter (conv ctx) r f args - |> List.map (fun (c,v) -> (c,m), d' v) (* c: caller, v: callee *) - - let paths_as_set ctx = - let m = snd ctx.local in - S.paths_as_set (conv ctx) |> List.map (fun v -> (v,m)) - - let combine_env ctx r fe f args fc es f_ask = lift_fun 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 S.combine_assign (fun p -> p r fe f args fc (fst es) f_ask) -end - - -(** Lifts a [Spec] with a special bottom element that represent unreachable code. *) -module DeadCodeLifter (S:Spec) - : Spec with module D = Dom (S.D) - and module G = S.G - and module C = S.C -= -struct - module D = Dom (S.D) - module G = S.G - module C = S.C - module V = S.V - module P = - struct - include Printable.Option (S.P) (struct let name = "None" end) - - let of_elt = function - | `Lifted x -> Some (S.P.of_elt x) - | _ -> None - end - - let name () = S.name ()^" lifted" - - type marshal = S.marshal - let init = S.init - let finalize = S.finalize - - - let startcontext () = S.startcontext () - let startstate v = `Lifted (S.startstate v) - let exitstate v = `Lifted (S.exitstate v) - let morphstate v d = try `Lifted (S.morphstate v (D.unlift d)) with Deadcode -> d - - - let conv ctx = - { ctx with local = D.unlift ctx.local - ; split = (fun d es -> ctx.split (D.lift d) es ) - } - - let context ctx fd = S.context (conv ctx) fd % D.unlift - - let lift_fun ctx f g h b = - try f @@ h (g (conv ctx)) - with Deadcode -> b - - let sync ctx reason = lift_fun ctx D.lift S.sync ((|>) reason) `Bot - - let enter ctx r f args = - let liftmap = List.map (fun (x,y) -> D.lift x, D.lift y) in - lift_fun ctx liftmap S.enter ((|>) args % (|>) f % (|>) r) [] - - let paths_as_set ctx = - let liftmap = List.map (fun x -> D.lift x) in - lift_fun ctx liftmap S.paths_as_set (Fun.id) [D.bot ()] (* One dead path instead of none, such that combine_env gets called for functions with dead normal return (and thus longjmpy returns can be correctly handled by lifter). *) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - lift_fun ctx identity S.query (fun (x) -> x q) (Queries.Result.bot q) - let assign ctx lv e = lift_fun ctx D.lift S.assign ((|>) e % (|>) lv) `Bot - let vdecl ctx v = lift_fun ctx D.lift S.vdecl ((|>) v) `Bot - let branch ctx e tv = lift_fun ctx D.lift S.branch ((|>) tv % (|>) e) `Bot - let body ctx f = lift_fun ctx D.lift S.body ((|>) f) `Bot - let return ctx r f = lift_fun ctx D.lift S.return ((|>) f % (|>) r) `Bot - let asm ctx = lift_fun ctx D.lift S.asm identity `Bot - let skip ctx = lift_fun ctx D.lift S.skip identity `Bot - let special ctx r f args = lift_fun ctx D.lift S.special ((|>) args % (|>) f % (|>) r) `Bot - 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 ~multiple lval f args = lift_fun ctx (List.map D.lift) (S.threadenter ~multiple) ((|>) args % (|>) f % (|>) lval) [] - 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 - - -(** Add path sensitivity to a analysis *) -module PathSensitive2 (Spec:Spec) - : Spec - with module G = Spec.G - and module C = Spec.C - and module V = Spec.V -= -struct - module D = - struct - (* TODO is it really worth it to check every time instead of just using sets and joining later? *) - module R = - struct - include Spec.P - type elt = Spec.D.t - end - module J = SetDomain.Joined (Spec.D) - include DisjointDomain.ProjectiveSet (Spec.D) (J) (R) - let name () = "PathSensitive (" ^ name () ^ ")" - - let printXml f x = - let print_one x = - BatPrintf.fprintf f "\n%a" Spec.D.printXml x - in - iter print_one x - end - - module G = Spec.G - module C = Spec.C - module V = Spec.V - module P = UnitP - - let name () = "PathSensitive2("^Spec.name ()^")" - - type marshal = Spec.marshal - let init = Spec.init - let finalize = Spec.finalize - - let startcontext () = Spec.startcontext () - let exitstate v = D.singleton (Spec.exitstate v) - let startstate v = D.singleton (Spec.startstate v) - let morphstate v d = D.map (Spec.morphstate v) d - - let conv ctx x = - let rec ctx' = { ctx with ask = (fun (type a) (q: a Queries.t) -> Spec.query ctx' q) - ; local = x - ; split = (ctx.split % D.singleton) } - in - ctx' - - let context ctx fd l = - if D.cardinal l <> 1 then - failwith "PathSensitive2.context must be called with a singleton set." - else - let x = D.choose l in - Spec.context (conv ctx x) fd x - - - let map ctx f g = - let h x xs = - try D.add (g (f (conv ctx x))) xs - with Deadcode -> xs - in - let d = D.fold h ctx.local (D.empty ()) in - if D.is_bot d then raise Deadcode else d - - let fold' ctx f g h a = - let k x a = - try h a @@ g @@ f @@ conv ctx x - with Deadcode -> a - in - D.fold k ctx.local a - - let assign ctx l e = map ctx Spec.assign (fun h -> h l e ) - let vdecl ctx v = map ctx Spec.vdecl (fun h -> h v) - let body ctx f = map ctx Spec.body (fun h -> h f ) - let return ctx e f = map ctx Spec.return (fun h -> h e f ) - let branch ctx e tv = map ctx Spec.branch (fun h -> h e tv) - let asm ctx = map ctx Spec.asm identity - let skip ctx = map ctx Spec.skip identity - let special ctx l f a = map ctx Spec.special (fun h -> h l f a) - - let event ctx e octx = - let fd1 = D.choose octx.local in - map ctx Spec.event (fun h -> h e (conv octx fd1)) - - 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 [] - - let threadspawn ctx ~multiple lval f args fctx = - let fd1 = D.choose fctx.local in - 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) - - let query ctx (type a) (q: a Queries.t): a Queries.result = - (* TODO: handle Invariant path like PathSensitive3? *) - (* join results so that they are sound for all paths *) - let module Result = (val Queries.Result.lattice q) in - fold' ctx Spec.query identity (fun x f -> Result.join x (f q)) (Result.bot ()) - - let enter ctx l f a = - let g xs ys = (List.map (fun (x,y) -> D.singleton x, D.singleton y) ys) @ xs in - fold' ctx Spec.enter (fun h -> h l f a) g [] - - let paths_as_set ctx = - (* Path-sensitivity is only here, not below! *) - let elems = D.elements ctx.local in - List.map (D.singleton) elems - - let combine_env ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_env (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d - - let combine_assign ctx l fe f a fc d f_ask = - assert (D.cardinal ctx.local = 1); - let cd = D.choose ctx.local in - let k x y = - if M.tracing then M.traceli "combine" "function: %a" Spec.D.pretty x; - try - let r = Spec.combine_assign (conv ctx cd) l fe f a fc x f_ask in - if M.tracing then M.traceu "combine" "combined function: %a" Spec.D.pretty r; - D.add r y - with Deadcode -> - if M.tracing then M.traceu "combine" "combined function: dead"; - y - in - let d = D.fold k d (D.bot ()) in - if D.is_bot d then raise Deadcode else d -end - -module DeadBranchLifter (S: Spec): Spec = -struct - include S - - let name () = "DeadBranch (" ^ S.name () ^ ")" - - (* Two global invariants: - 1. S.V -> S.G -- used for S - 2. node -> (exp -> flat bool) -- used for warnings *) - - module V = - struct - include Printable.EitherConf (struct let expand1 = false let expand2 = true end) (S.V) (Node) - let name () = "DeadBranch" - let s x = `Left x - let node x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | `Right _ -> true - end - - module EM = - struct - include MapDomain.MapBot (Basetype.CilExp) (BoolDomain.FlatBool) - let name () = "branches" - end - - module G = - struct - include Lattice.Lift2 (S.G) (EM) - let name () = "deadbranch" - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "DeadBranchLifter.s" - let node = function - | `Bot -> EM.bot () - | `Lifted2 x -> x - | _ -> failwith "DeadBranchLifter.node" - let create_s s = `Lifted1 s - let create_node node = `Lifted2 node - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" EM.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | `Right g -> - let em = G.node (ctx.global (V.node g)) in - EM.iter (fun exp tv -> - match tv with - | `Lifted tv -> - let loc = Node.location g in (* TODO: looking up location now doesn't work nicely with incremental *) - let cilinserted = if loc.synthetic then "(possibly inserted by CIL) " else "" in - M.warn ~loc:(Node g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' %sis always %B" d_exp exp cilinserted tv - | `Bot when not (CilType.Exp.equal exp one) -> (* all branches dead *) - M.msg_final Error ~category:Analyzer ~tags:[Category Unsound] "Both branches dead"; - M.error ~loc:(Node g) ~category:Analyzer ~tags:[Category Unsound] "both branches over condition '%a' are dead" d_exp exp - | `Bot (* all branches dead, fine at our inserted Neg(1)-s because no Pos(1) *) - | `Top -> (* may be both true and false *) - () - ) em; - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | `Right g -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - - (* node vars for dead branches *) - begin match vq with - | Node {node; _} -> - vf (Obj.repr (V.node node)) - | _ -> - () - end - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let context ctx = S.context (conv ctx) - - let branch ctx exp tv = - if !AnalysisState.postsolving then ( - try - let r = branch ctx exp tv in - (* branch is live *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp (`Lifted tv))); (* record expression with reached tv *) - r - with Deadcode -> - (* branch is dead *) - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.singleton exp `Bot)); (* record expression without reached tv *) - raise Deadcode - ) - else ( - ctx.sideg (V.node ctx.prev_node) (G.create_node (EM.bot ())); (* create global variable during solving, to allow postsolving leq hack to pass verify *) - branch ctx exp tv - ) - - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - 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 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end - module LongjmpLifter (S: Spec): Spec = struct include S From 7f4f5aa7081e9d00f685a813e391ee980b1ed271 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:27:25 +0300 Subject: [PATCH 517/689] Remove LongjmpLifter from SpecLifters --- src/lifters/specLifters.ml | 243 ------------------------------------- 1 file changed, 243 deletions(-) diff --git a/src/lifters/specLifters.ml b/src/lifters/specLifters.ml index 1be137cf8c..3286721bf0 100644 --- a/src/lifters/specLifters.ml +++ b/src/lifters/specLifters.ml @@ -782,246 +782,3 @@ struct let asm ctx = S.asm (conv ctx) let event ctx e octx = S.event (conv ctx) e (conv octx) end - -module LongjmpLifter (S: Spec): Spec = -struct - include S - - let name () = "Longjmp (" ^ S.name () ^ ")" - - module V = - struct - include Printable.Either3Conf (struct let expand1 = false let expand2 = true let expand3 = true end) (S.V) (Printable.Prod (Node) (C)) (Printable.Prod (CilType.Fundec) (C)) - let name () = "longjmp" - let s x = `Left x - let longjmpto x = `Middle x - let longjmpret x = `Right x - let is_write_only = function - | `Left x -> S.V.is_write_only x - | _ -> false - end - - module G = - struct - include Lattice.Lift2 (S.G) (S.D) - - let s = function - | `Bot -> S.G.bot () - | `Lifted1 x -> x - | _ -> failwith "LongjmpLifter.s" - let local = function - | `Bot -> S.D.bot () - | `Lifted2 x -> x - | _ -> failwith "LongjmpLifter.local" - let create_s s = `Lifted1 s - let create_local local = `Lifted2 local - - let printXml f = function - | `Lifted1 x -> S.G.printXml f x - | `Lifted2 x -> BatPrintf.fprintf f "%a" S.D.printXml x - | x -> BatPrintf.fprintf f "%a" printXml x - end - - let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = - { ctx with - global = (fun v -> G.s (ctx.global (V.s v))); - sideg = (fun v g -> ctx.sideg (V.s v) (G.create_s g)); - } - - let query ctx (type a) (q: a Queries.t): a Queries.result = - match q with - | WarnGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (WarnGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | InvariantGlobal g -> - let g: V.t = Obj.obj g in - begin match g with - | `Left g -> - S.query (conv ctx) (InvariantGlobal (Obj.repr g)) - | _ -> - Queries.Result.top q - end - | IterSysVars (vq, vf) -> - (* vars for S *) - let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in - S.query (conv ctx) (IterSysVars (vq, vf')); - (* TODO: vars? *) - | _ -> - S.query (conv ctx) q - - - let branch ctx = S.branch (conv ctx) - let assign ctx = S.assign (conv ctx) - let vdecl ctx = S.vdecl (conv ctx) - let enter ctx = S.enter (conv ctx) - let paths_as_set ctx = S.paths_as_set (conv ctx) - let body ctx = S.body (conv ctx) - let return ctx = S.return (conv ctx) - let context ctx = S.context (conv ctx) - - let combine_env ctx lv e f args fc fd f_ask = - let conv_ctx = conv ctx in - let current_fundec = Node.find_fundec ctx.node in - let handle_longjmp (cd, fc, longfd) = - (* This is called per-path. *) - let rec cd_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query cd_ctx q); - local = cd; - } - in - let longfd_ctx = - (* Inner scope to prevent unsynced longfd_ctx from being used. *) - (* Extra sync like with normal combine. *) - let rec sync_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query sync_ctx q); - local = longfd; - prev_node = Function f; - } - in - let synced = S.sync sync_ctx `Join in - let rec longfd_ctx = - { sync_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query longfd_ctx q); - local = synced; - } - in - longfd_ctx - in - let combined = lazy ( (* does not depend on target, do at most once *) - (* Globals are non-problematic here, as they are always carried around without any issues! *) - (* A combine call is mostly needed to ensure locals have appropriate values. *) - (* Using f from called function on purpose here! Needed? *) - S.combine_env cd_ctx None e f args fc longfd_ctx.local (Analyses.ask_of_ctx longfd_ctx) (* no lval because longjmp return skips return value assignment *) - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec combined_ctx = - { cd_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query combined_ctx q); - local = Lazy.force combined; - } - in - S.return combined_ctx None current_fundec - ) - in - let (active_targets, _) = longfd_ctx.ask ActiveJumpBuf in - let valid_targets = cd_ctx.ask ValidLongJmp in - let handle_target target = match target with - | JmpBufDomain.BufferEntryOrTop.AllTargets -> () (* The warning is already emitted at the point where the longjmp happens *) - | 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 ( - if M.tracing then Messages.tracel "longjmp" "Fun: Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force combined)) - (* No need to propagate this outwards here, the set of valid longjumps is part of the context, we can never have the same context setting the longjmp multiple times *) - ) - (* Appropriate setjmp is not in current function & current context *) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - else - (* It actually is not handled here but was propagated here spuriously, we already warned at the location where this issue is caused *) - (* As the validlongjumps inside the callee is a a superset of the ones inside the caller *) - () - in - JmpBufDomain.JmpBufSet.iter handle_target active_targets - in - if M.tracing then M.tracel "longjmp" "longfd getg %a" CilType.Fundec.pretty f; - let longfd = G.local (ctx.global (V.longjmpret (f, Option.get fc))) in - if M.tracing then M.tracel "longjmp" "longfd %a" D.pretty longfd; - if not (D.is_bot longfd) then - handle_longjmp (ctx.local, fc, longfd); - S.combine_env (conv_ctx) lv e f args fc fd f_ask - - let combine_assign ctx lv e f args fc fd f_ask = - S.combine_assign (conv ctx) lv e f args fc fd f_ask - - let special ctx lv f args = - let conv_ctx = conv ctx in - match (LibraryFunctions.find f).special args with - | Setjmp {env} -> - (* Handling of returning for the first time *) - let normal_return = S.special conv_ctx lv f args in - let jmp_return = G.local (ctx.global (V.longjmpto (ctx.prev_node, ctx.context ()))) in - if S.D.is_bot jmp_return then - normal_return - else ( - let rec jmp_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query jmp_ctx q); - local = jmp_return; - } - in - let longjmped = S.event jmp_ctx (Events.Longjmped {lval=lv}) jmp_ctx in - S.D.join normal_return longjmped - ) - | Longjmp {env; value} -> - let current_fundec = Node.find_fundec ctx.node in - let handle_path path = ( - let rec path_ctx = - { conv_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query path_ctx q); - local = path; - } - in - let specialed = lazy ( (* does not depend on target, do at most once *) - S.special path_ctx lv f args - ) - in - let returned = lazy ( (* does not depend on target, do at most once *) - let rec specialed_ctx = - { path_ctx with - ask = (fun (type a) (q: a Queries.t) -> S.query specialed_ctx q); - local = Lazy.force specialed; - } - in - S.return specialed_ctx None current_fundec - ) - in - (* Eval `env` again to avoid having to construct bespoke ctx to ask *) - let targets = path_ctx.ask (EvalJumpBuf env) in - let valid_targets = path_ctx.ask ValidLongJmp in - if M.tracing then Messages.tracel "longjmp" "Jumping to %a" 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.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 ( - if M.tracing then Messages.tracel "longjmp" "Potentially from same context, side-effect to %a" Node.pretty target_node; - ctx.sideg (V.longjmpto (target_node, ctx.context ())) (G.create_local (Lazy.force specialed)) - ) - else if JmpBufDomain.JmpBufSet.mem target valid_targets then ( - if M.tracing then Messages.tracel "longjmp" "Longjmp to somewhere else, side-effect to %i" (S.C.hash (ctx.context ())); - ctx.sideg (V.longjmpret (current_fundec, ctx.context ())) (G.create_local (Lazy.force returned)) - ) - else - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target! (Target %a in Function %a which may have already returned or is in a different thread)" Node.pretty target_node CilType.Fundec.pretty target_fundec - in - if JmpBufDomain.JmpBufSet.is_empty targets then - M.warn ~category:(Behavior (Undefined Other)) "Longjmp to potentially invalid target (%a is bot?!)" d_exp env - else - JmpBufDomain.JmpBufSet.iter handle_target targets - ) - in - List.iter handle_path (S.paths_as_set conv_ctx); - if !AnalysisState.should_warn && List.mem "termination" @@ get_string_list "ana.activated" then ( - AnalysisState.svcomp_may_not_terminate := true; - M.warn ~category:Termination "The program might not terminate! (Longjmp)" - ); - S.D.bot () - | _ -> S.special conv_ctx lv f args - let threadenter ctx = S.threadenter (conv ctx) - 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) - let event ctx e octx = S.event (conv ctx) e (conv octx) -end From 3b285e3d7f6cee1ff1159cc288ab7f39f3443411 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 24 Sep 2024 15:40:47 +0300 Subject: [PATCH 518/689] Document Spec lifter modules --- src/framework/control.ml | 4 ++-- src/lifters/longjmpLifter.ml | 2 +- src/lifters/longjmpLifter.mli | 3 +++ src/lifters/recursionTermLifter.ml | 3 +-- src/lifters/recursionTermLifter.mli | 3 +++ src/lifters/specLifters.ml | 2 ++ 6 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 src/lifters/longjmpLifter.mli create mode 100644 src/lifters/recursionTermLifter.mli diff --git a/src/framework/control.ml b/src/framework/control.ml index a2fb7c01e9..1d0ebb869b 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -40,8 +40,8 @@ let spec_module: (module Spec) Lazy.t = lazy ( (* Widening tokens must be outside of hashcons, because widening token domain ignores token sets for identity, so hashcons doesn't allow adding tokens. Also must be outside of deadcode, because deadcode splits (like mutex lock event) don't pass on tokens. *) |> lift (get_bool "ana.widen.tokens") (module WideningTokens.Lifter) - |> lift true (module LongjmpLifter.LongjmpLifter) - |> lift termination_enabled (module RecursionTermLifter.RecursionTermLifter) (* Always activate the recursion termination analysis, when the loop termination analysis is activated*) + |> lift true (module LongjmpLifter.Lifter) + |> lift termination_enabled (module RecursionTermLifter.Lifter) (* Always activate the recursion termination analysis, when the loop termination analysis is activated*) ) in GobConfig.building_spec := false; diff --git a/src/lifters/longjmpLifter.ml b/src/lifters/longjmpLifter.ml index 1150bc1bca..1a28085abe 100644 --- a/src/lifters/longjmpLifter.ml +++ b/src/lifters/longjmpLifter.ml @@ -3,7 +3,7 @@ open Analyses open GobConfig -module LongjmpLifter (S: Spec): Spec = +module Lifter (S: Spec): Spec = struct include S diff --git a/src/lifters/longjmpLifter.mli b/src/lifters/longjmpLifter.mli new file mode 100644 index 0000000000..5fd74907bc --- /dev/null +++ b/src/lifters/longjmpLifter.mli @@ -0,0 +1,3 @@ +(** Analysis lifter for [longjmp] and [setjmp] support. *) + +module Lifter: Analyses.Spec2Spec diff --git a/src/lifters/recursionTermLifter.ml b/src/lifters/recursionTermLifter.ml index 3de3810569..2d9f45de60 100644 --- a/src/lifters/recursionTermLifter.ml +++ b/src/lifters/recursionTermLifter.ml @@ -2,8 +2,7 @@ open GoblintCil open Analyses -(** Add cycle detection in the context-sensitive dynamic function call graph to an analysis *) -module RecursionTermLifter (S: Spec) +module Lifter (S: Spec) : Spec with module D = S.D and module C = S.C = diff --git a/src/lifters/recursionTermLifter.mli b/src/lifters/recursionTermLifter.mli new file mode 100644 index 0000000000..059cea658f --- /dev/null +++ b/src/lifters/recursionTermLifter.mli @@ -0,0 +1,3 @@ +(** Cycle detection in the context-sensitive dynamic function call graph of an analysis. *) + +module Lifter: Analyses.Spec2Spec diff --git a/src/lifters/specLifters.ml b/src/lifters/specLifters.ml index 3286721bf0..4ce158b8ac 100644 --- a/src/lifters/specLifters.ml +++ b/src/lifters/specLifters.ml @@ -1,3 +1,5 @@ +(** Various simple and old analysis lifters. *) + open Batteries open GoblintCil open Analyses From bcb15a1fa360ff8e8fca50deda55ae628fb3e51a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 25 Sep 2024 15:35:32 +0300 Subject: [PATCH 519/689] Bump CIL with potential opam install fix --- goblint.opam | 2 +- goblint.opam.locked | 2 +- goblint.opam.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/goblint.opam b/goblint.opam index 0346e78252..b1f1ee97d0 100644 --- a/goblint.opam +++ b/goblint.opam @@ -97,7 +97,7 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#73d02511a0366816d428853634fb939bd2f0a1b7" ] + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index dcf81b7a53..97a8385312 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -140,7 +140,7 @@ post-messages: [ pin-depends: [ [ "goblint-cil.2.0.4" - "git+https://github.com/goblint/cil.git#73d02511a0366816d428853634fb939bd2f0a1b7" + "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.template b/goblint.opam.template index 2a5d5690fc..a8a46aa108 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -2,7 +2,7 @@ # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#73d02511a0366816d428853634fb939bd2f0a1b7" ] + [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} From f7e4462dda207367138b259fe0751ee061e86032 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 25 Sep 2024 15:48:25 +0300 Subject: [PATCH 520/689] Add cram test for SV-COMP architecture --- tests/regression/29-svcomp/36-svcomp-arch.c | 8 ++++++++ tests/regression/29-svcomp/36-svcomp-arch.t | 22 +++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/regression/29-svcomp/36-svcomp-arch.c create mode 100644 tests/regression/29-svcomp/36-svcomp-arch.t diff --git a/tests/regression/29-svcomp/36-svcomp-arch.c b/tests/regression/29-svcomp/36-svcomp-arch.c new file mode 100644 index 0000000000..ea68ba187c --- /dev/null +++ b/tests/regression/29-svcomp/36-svcomp-arch.c @@ -0,0 +1,8 @@ +// CRAM +#include + +int main() { + long k = INT_MAX; + long n = k * k; + return 0; +} diff --git a/tests/regression/29-svcomp/36-svcomp-arch.t b/tests/regression/29-svcomp/36-svcomp-arch.t new file mode 100644 index 0000000000..a0715e3872 --- /dev/null +++ b/tests/regression/29-svcomp/36-svcomp-arch.t @@ -0,0 +1,22 @@ +There should be overflow on ILP32: + + $ goblint --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! overflow) )" --set exp.architecture 32bit 36-svcomp-arch.c + [Info] Setting "ana.int.interval" to true + [Info] SV-COMP specification: CHECK( init(main()), LTL(G ! overflow) ) + [Warning][Integer > Overflow][CWE-190] Signed integer overflow (36-svcomp-arch.c:6:8-6:17) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 4 + dead: 0 + total lines: 4 + SV-COMP result: unknown + +There shouldn't be an overflow on LP64: + + $ goblint --enable ana.sv-comp.enabled --set ana.specification "CHECK( init(main()), LTL(G ! overflow) )" --set exp.architecture 64bit 36-svcomp-arch.c + [Info] Setting "ana.int.interval" to true + [Info] SV-COMP specification: CHECK( init(main()), LTL(G ! overflow) ) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 4 + dead: 0 + total lines: 4 + SV-COMP result: true From 701f1aedfba5ba58be8d00cc245a76977a7cba70 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 26 Sep 2024 12:24:12 +0300 Subject: [PATCH 521/689] Document scope of regression test meta annotations --- docs/developer-guide/testing.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/developer-guide/testing.md b/docs/developer-guide/testing.md index a336228fde..9444a96007 100644 --- a/docs/developer-guide/testing.md +++ b/docs/developer-guide/testing.md @@ -79,6 +79,9 @@ Comments at the end of lines can also indicate metaproperties: | `NOTIMEOUT` | Analyer terminates | | `CRAM` | Automatic checks are only in corresponding Cram test | +These comments only document the intention of the test (if there are no other checks in the test). +Analyzer crash, fixpoint error and non-termination are checked even when there are other checks. + ## Cram Tests [Cram-style tests](https://dune.readthedocs.io/en/stable/tests.html#cram-tests) are also used to verify that existing functionality hasn't been broken. They check the complete standard output of running the Goblint binary with specified command-line arguments. From 8cce1c945213f10d2be0809dc4411ca644d4acb5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 26 Sep 2024 12:26:03 +0300 Subject: [PATCH 522/689] Comment on negative line numbers in update_suite --- scripts/update_suite.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/update_suite.rb b/scripts/update_suite.rb index e760cdd721..b21fb4b532 100755 --- a/scripts/update_suite.rb +++ b/scripts/update_suite.rb @@ -326,6 +326,7 @@ def parse_tests (lines) if obj =~ /#line ([0-9]+).*$/ then i = $1.to_i - 1 end + # test annotations are stored by line, use impossible line -42 for these metaproperties if obj =~ /NOCRASH/ then tests[-42] = "nocrash" elsif obj =~ /FIXPOINT/ then @@ -369,6 +370,7 @@ def parse_tests (lines) end end case lines[0] + # test annotations are stored by line, use impossible line -1 for these whole-program properties when /NONTERM/ tests[-1] = "nonterm" when /TERM/ From 54eb6f6bf318230182c12a56e5740ce654dd980f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 26 Sep 2024 12:27:15 +0300 Subject: [PATCH 523/689] Add CRAM annotation to 00-sanity/33-hoare-over-paths Although there are asserts, so update_suite doesn't complain about no checks. --- tests/regression/00-sanity/33-hoare-over-paths.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/00-sanity/33-hoare-over-paths.c b/tests/regression/00-sanity/33-hoare-over-paths.c index 4a809685ed..e3af40cbb3 100644 --- a/tests/regression/00-sanity/33-hoare-over-paths.c +++ b/tests/regression/00-sanity/33-hoare-over-paths.c @@ -1,7 +1,7 @@ // PARAM: --set ana.path_sens[+] mutex #include #include - +// CRAM pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; int main() { From f1b6157a3b0846d48a69529577a82045acd1d5cc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 27 Sep 2024 10:59:54 +0300 Subject: [PATCH 524/689] Add "ERROR (both branches dead)" verdict for SV-COMP (closes #1576) --- src/common/framework/analysisState.ml | 5 +++++ src/goblint.ml | 1 + src/lifters/specLifters.ml | 5 +++++ src/util/server.ml | 1 + src/witness/witness.ml | 7 ++++--- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/common/framework/analysisState.ml b/src/common/framework/analysisState.ml index d1764c839f..96816b8529 100644 --- a/src/common/framework/analysisState.ml +++ b/src/common/framework/analysisState.ml @@ -36,3 +36,8 @@ let postsolving = ref false (* None if verification is disabled, Some true if verification succeeded, Some false if verification failed *) let verified : bool option ref = ref None + +let unsound_both_branches_dead: bool option ref = ref None +(** [Some true] if unsound both branches dead occurs in analysis results. + [Some false] if it doesn't occur. + [None] if [ana.dead-code.branches] option is disabled and this isn't checked. *) \ No newline at end of file diff --git a/src/goblint.ml b/src/goblint.ml index 52b9bbdfc0..bdfcadd3d2 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -65,6 +65,7 @@ let main () = do_gobview file; do_stats (); Goblint_timing.teardown_tef (); + (* TODO: generalize exit codes for AnalysisState.unsound_both_branches_dead? *) if !AnalysisState.verified = Some false then exit 3 (* verifier failed! *) ) with diff --git a/src/lifters/specLifters.ml b/src/lifters/specLifters.ml index 4ce158b8ac..e8292bedc0 100644 --- a/src/lifters/specLifters.ml +++ b/src/lifters/specLifters.ml @@ -695,6 +695,10 @@ struct | x -> BatPrintf.fprintf f "%a" printXml x end + let init marshal = + init marshal; + AnalysisState.unsound_both_branches_dead := Some false + let conv (ctx: (_, G.t, _, V.t) ctx): (_, S.G.t, _, S.V.t) ctx = { ctx with global = (fun v -> G.s (ctx.global (V.s v))); @@ -717,6 +721,7 @@ struct let cilinserted = if loc.synthetic then "(possibly inserted by CIL) " else "" in M.warn ~loc:(Node g) ~tags:[CWE (if tv then 571 else 570)] ~category:Deadcode "condition '%a' %sis always %B" d_exp exp cilinserted tv | `Bot when not (CilType.Exp.equal exp one) -> (* all branches dead *) + AnalysisState.unsound_both_branches_dead := Some true; M.msg_final Error ~category:Analyzer ~tags:[Category Unsound] "Both branches dead"; M.error ~loc:(Node g) ~category:Analyzer ~tags:[Category Unsound] "both branches over condition '%a' are dead" d_exp exp | `Bot (* all branches dead, fine at our inserted Neg(1)-s because no Pos(1) *) diff --git a/src/util/server.ml b/src/util/server.ml index 7b603e7c6e..1bdc3e1ea9 100644 --- a/src/util/server.ml +++ b/src/util/server.ml @@ -320,6 +320,7 @@ let () = let process { reset } serve = try analyze serve ~reset; + (* TODO: generalize VerifyError for AnalysisState.unsound_both_branches_dead *) {status = if !AnalysisState.verified = Some false then VerifyError else Success} with | Sys.Break -> diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 7b0213b601..5da46a1011 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -691,9 +691,10 @@ struct ) let write yaml_validate_result entrystates = - match !AnalysisState.verified with - | Some false -> print_svcomp_result "ERROR (verify)" - | _ -> + match !AnalysisState.verified, !AnalysisState.unsound_both_branches_dead with + | _, Some true -> print_svcomp_result "ERROR (both branches dead)" + | Some false, _ -> print_svcomp_result "ERROR (verify)" + | _, _ -> match yaml_validate_result with | Some (Stdlib.Error msg) -> print_svcomp_result ("ERROR (" ^ msg ^ ")") From ea2f61645301663b54bbce800a258d9dc7a4cfc8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 27 Sep 2024 12:16:06 +0300 Subject: [PATCH 525/689] Use ptrdiff_ikind instead of ILong for ana.arrayoob checks --- src/cdomain/value/cdomains/arrayDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/arrayDomain.ml b/src/cdomain/value/cdomains/arrayDomain.ml index e1cfb96425..4192489c3a 100644 --- a/src/cdomain/value/cdomains/arrayDomain.ml +++ b/src/cdomain/value/cdomains/arrayDomain.ml @@ -834,7 +834,7 @@ end let array_oob_check ( type a ) (module Idx: IntDomain.Z with type t = a) (x, l) (e, v) = if GobConfig.get_bool "ana.arrayoob" then (* The purpose of the following 2 lines is to give the user extra info about the array oob *) let idx_before_end = Idx.to_bool (Idx.lt v l) (* check whether index is before the end of the array *) - and idx_after_start = Idx.to_bool (Idx.ge v (Idx.of_int Cil.ILong Z.zero)) in (* check whether the index is non-negative *) + and idx_after_start = Idx.to_bool (Idx.ge v (Idx.of_int (Cilfacade.ptrdiff_ikind ()) Z.zero)) in (* check whether the index is non-negative *) (* For an explanation of the warning types check the Pull Request #255 *) match(idx_after_start, idx_before_end) with | Some true, Some true -> (* Certainly in bounds on both sides.*) From e35cc3cdc2d04ec230c4b7325cd17cfeaccd0c09 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 18 Jun 2024 18:04:08 +0300 Subject: [PATCH 526/689] Log instead of printing to stderr --- src/util/loopUnrolling.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 07c20cb574..ad964974d0 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -274,8 +274,7 @@ let fixedLoopSize loopStatement func = else constBefore var loopStatement func >>= fun start -> assignmentDifference loopStatement var >>= fun diff -> - Logs.debug "comparison: "; - Pretty.fprint stderr (dn_exp () comparison) ~width:max_int; + Logs.debug "comparison: %a" CilType.Exp.pretty comparison; Logs.debug ""; Logs.debug "variable: "; Logs.debug "%s" var.vname; From 96b5d2024c6859371bb38e451a9111beb2189f8b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 18 Jun 2024 18:05:45 +0300 Subject: [PATCH 527/689] Move debug messages to one line instead of printing 2 separate msgs --- src/util/loopUnrolling.ml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index ad964974d0..7c59cc7473 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -275,21 +275,16 @@ let fixedLoopSize loopStatement func = constBefore var loopStatement func >>= fun start -> assignmentDifference loopStatement var >>= fun diff -> Logs.debug "comparison: %a" CilType.Exp.pretty comparison; - Logs.debug ""; - Logs.debug "variable: "; - Logs.debug "%s" var.vname; - Logs.debug "start:"; - Logs.debug "%s" @@ Z.to_string start; - Logs.debug "diff:"; - Logs.debug "%s" @@ Z.to_string diff; + Logs.debug "variable: %s" var.vname; + Logs.debug "start: %s" @@ Z.to_string start; + Logs.debug "diff: %s" @@ Z.to_string diff; let iterations = loopIterations start diff comparison in match iterations with | None -> Logs.debug "iterations failed"; None | Some s -> try let s' = Z.to_int s in - Logs.debug "iterations:"; - Logs.debug "%d" s'; + Logs.debug "iterations: %d" s'; Some s' with Z.Overflow -> Logs.debug "iterations too big for integer"; None From 8af3f8c92cd75f6f37b9481ecce8f6ea4863b0b6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter <44437975+karoliineh@users.noreply.github.com> Date: Thu, 20 Jun 2024 12:59:00 +0300 Subject: [PATCH 528/689] Use GobZ.pretty instead Z.to_string Co-authored-by: Simmo Saan --- src/util/loopUnrolling.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 7c59cc7473..80dd110e5f 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -276,8 +276,8 @@ let fixedLoopSize loopStatement func = assignmentDifference loopStatement var >>= fun diff -> Logs.debug "comparison: %a" CilType.Exp.pretty comparison; Logs.debug "variable: %s" var.vname; - Logs.debug "start: %s" @@ Z.to_string start; - Logs.debug "diff: %s" @@ Z.to_string diff; + Logs.debug "start: %a" GobZ.pretty start; + Logs.debug "diff: %a" GobZ.pretty diff; let iterations = loopIterations start diff comparison in match iterations with | None -> Logs.debug "iterations failed"; None From b3eaeda2e531d9960c069d3c4731c18b71e7f6b5 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 20:41:32 +0300 Subject: [PATCH 529/689] Make getLoopVar return loop bound goal in addition to the varinfo --- src/util/loopUnrolling.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 80dd110e5f..1a6f5d3344 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -250,9 +250,9 @@ let fixedLoopSize loopStatement func = !compOption with | WrongOrMultiple -> None in let getLoopVar = function - | BinOp (op, (Const (CInt _ )), Lval ((Var info), NoOffset), (TInt _)) - | BinOp (op, Lval ((Var info), NoOffset), (Const (CInt _ )), (TInt _)) when isCompare op && not info.vglob-> - Some info + | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var info), NoOffset), (TInt _)) + | BinOp (op, Lval ((Var info), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not info.vglob-> + Some (info, goal) | _ -> None in let getsPointedAt var = try let visitor = new isPointedAtVisitor(var) in @@ -268,7 +268,7 @@ let fixedLoopSize loopStatement func = in findBreakComparison >>= fun comparison -> - getLoopVar comparison >>= fun var -> + getLoopVar comparison >>= fun (var, goal) -> if getsPointedAt var then None else From 6ccd3c10be5ec2fa890ec3799b0b536dc5121b5b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 21:48:51 +0300 Subject: [PATCH 530/689] Make sure goal is found from the exact same comparison exp where the var was found --- src/util/loopUnrolling.ml | 64 ++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 1a6f5d3344..92d5dab50f 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -210,35 +210,27 @@ let constBefore var loop f = in fst @@ lastAssignmentToVarBeforeLoop (Some Z.zero) f.sbody.bstmts (*the top level call should never return false*) -let rec loopIterations start diff comp = - let flip = function - | Lt -> Gt - | Gt -> Lt - | Ge -> Le - | Le -> Ge - | s -> s - in let loopIterations' goal shouldBeExact = - let range = Z.sub goal start in - if Z.equal diff Z.zero || Z.equal range Z.zero || (Z.gt diff Z.zero && Z.lt range Z.zero) || (Z.lt diff Z.zero && Z.gt range Z.zero) then - None (*unfitting parameters*) - else ( - let roundedDown = Z.div range diff in - let isExact = Z.equal (Z.mul roundedDown diff) range in - if isExact then - Some roundedDown - else if shouldBeExact then - None - else - Some (Z.succ roundedDown) - ) - in - match comp with - | BinOp (op, (Const _ as c), var, t) -> loopIterations start diff (BinOp (flip op, var, c, t)) - | BinOp (Lt, _, (Const (CInt (cint,_,_) )), _) -> if Z.lt diff Z.zero then None else loopIterations' cint false - | BinOp (Gt, _, (Const (CInt (cint,_,_) )), _) -> if Z.gt diff Z.zero then None else loopIterations' cint false - | BinOp (Le, _, (Const (CInt (cint,_,_) )), _) -> if Z.lt diff Z.zero then None else loopIterations' (Z.succ cint) false - | BinOp (Ge, _, (Const (CInt (cint,_,_) )), _) -> if Z.gt diff Z.zero then None else loopIterations' (Z.pred cint) false - | BinOp (Ne, _, (Const (CInt (cint,_,_) )), _) -> loopIterations' cint true +let loopIterations start diff goal shouldBeExact = + let range = Z.sub goal start in + if Z.equal diff Z.zero || Z.equal range Z.zero || (Z.gt diff Z.zero && Z.lt range Z.zero) || (Z.lt diff Z.zero && Z.gt range Z.zero) then + None (*unfitting parameters*) + else ( + let roundedDown = Z.div range diff in + let isExact = Z.equal (Z.mul roundedDown diff) range in + if isExact then + Some roundedDown + else if shouldBeExact then + None + else + Some (Z.succ roundedDown) + ) +let adjustGoal diff goal op = + match op with + | Lt -> if Z.lt diff Z.zero then None else Some goal + | Gt -> if Z.gt diff Z.zero then None else Some goal + | Le -> if Z.lt diff Z.zero then None else Some (Z.succ goal) + | Ge -> if Z.gt diff Z.zero then None else Some (Z.pred goal) + | Ne -> Some goal | _ -> failwith "unexpected comparison in loopIterations" let ( >>= ) = Option.bind @@ -250,9 +242,12 @@ let fixedLoopSize loopStatement func = !compOption with | WrongOrMultiple -> None in let getLoopVar = function - | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var info), NoOffset), (TInt _)) - | BinOp (op, Lval ((Var info), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not info.vglob-> - Some (info, goal) + | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var varinfo), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob -> + (* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *) + let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in + Some (flip op, varinfo, goal) + | BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob -> + Some (op, varinfo, goal) | _ -> None in let getsPointedAt var = try let visitor = new isPointedAtVisitor(var) in @@ -268,7 +263,7 @@ let fixedLoopSize loopStatement func = in findBreakComparison >>= fun comparison -> - getLoopVar comparison >>= fun (var, goal) -> + getLoopVar comparison >>= fun (op, var, goal) -> if getsPointedAt var then None else @@ -278,7 +273,8 @@ let fixedLoopSize loopStatement func = Logs.debug "variable: %s" var.vname; Logs.debug "start: %a" GobZ.pretty start; Logs.debug "diff: %a" GobZ.pretty diff; - let iterations = loopIterations start diff comparison in + adjustGoal diff goal op >>= fun goal -> + let iterations = loopIterations start diff goal (op=Ne) in match iterations with | None -> Logs.debug "iterations failed"; None | Some s -> From cbf74aea86bbc760bf6efdb9bd80412ad65fd3a7 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 21:52:11 +0300 Subject: [PATCH 531/689] Add arguments to functions --- src/util/loopUnrolling.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 92d5dab50f..c480f26127 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -235,7 +235,7 @@ let adjustGoal diff goal op = let ( >>= ) = Option.bind let fixedLoopSize loopStatement func = - let findBreakComparison = try (*find a single break in the else branch of a toplevel if*) + let findBreakComparison loopStatement = try (*find a single break in the else branch of a toplevel if*) let compOption = ref None in let visitor = new findBreakVisitor(compOption) in ignore @@ visitCilBlock visitor (loopBody loopStatement); @@ -249,7 +249,7 @@ let fixedLoopSize loopStatement func = | BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob -> Some (op, varinfo, goal) | _ -> None - in let getsPointedAt var = try + in let getsPointedAt var func = try let visitor = new isPointedAtVisitor(var) in ignore @@ visitCilFunction visitor func; false @@ -262,9 +262,9 @@ let fixedLoopSize loopStatement func = with | WrongOrMultiple -> None in - findBreakComparison >>= fun comparison -> + findBreakComparison loopStatement >>= fun comparison -> getLoopVar comparison >>= fun (op, var, goal) -> - if getsPointedAt var then + if getsPointedAt var func then None else constBefore var loopStatement func >>= fun start -> From 1eeae94041379b6ecc4d335663b4b6555a8f3f8b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 22:03:13 +0300 Subject: [PATCH 532/689] Move functions defined in fixedLoopSize to top level --- src/util/loopUnrolling.ml | 84 ++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index c480f26127..ffd1c10418 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -210,6 +210,51 @@ let constBefore var loop f = in fst @@ lastAssignmentToVarBeforeLoop (Some Z.zero) f.sbody.bstmts (*the top level call should never return false*) +(*find a single break in the else branch of a toplevel if*) +let findBreakComparison loopStatement = + try + let compOption = ref None in + let visitor = new findBreakVisitor (compOption) in + ignore @@ visitCilBlock visitor (loopBody loopStatement); + !compOption + with WrongOrMultiple -> + None + +let getLoopVar = function + | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var varinfo), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob -> + (* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *) + let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in + Some (flip op, varinfo, goal) + | BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob -> + Some (op, varinfo, goal) + | _ -> None + +let getsPointedAt var func = + try + let visitor = new isPointedAtVisitor (var) in + ignore @@ visitCilFunction visitor func; + false + with Found -> + true + +let assignmentDifference loop var = + try + let diff = ref None in + let visitor = new findAssignmentConstDiff (diff, var) in + ignore @@ visitCilStmt visitor loop; + !diff + with WrongOrMultiple -> + None + +let adjustGoal diff goal op = + match op with + | Lt -> if Z.lt diff Z.zero then None else Some goal + | Gt -> if Z.gt diff Z.zero then None else Some goal + | Le -> if Z.lt diff Z.zero then None else Some (Z.succ goal) + | Ge -> if Z.gt diff Z.zero then None else Some (Z.pred goal) + | Ne -> Some goal + | _ -> failwith "unexpected comparison in loopIterations" + let loopIterations start diff goal shouldBeExact = let range = Z.sub goal start in if Z.equal diff Z.zero || Z.equal range Z.zero || (Z.gt diff Z.zero && Z.lt range Z.zero) || (Z.lt diff Z.zero && Z.gt range Z.zero) then @@ -224,44 +269,9 @@ let loopIterations start diff goal shouldBeExact = else Some (Z.succ roundedDown) ) -let adjustGoal diff goal op = - match op with - | Lt -> if Z.lt diff Z.zero then None else Some goal - | Gt -> if Z.gt diff Z.zero then None else Some goal - | Le -> if Z.lt diff Z.zero then None else Some (Z.succ goal) - | Ge -> if Z.gt diff Z.zero then None else Some (Z.pred goal) - | Ne -> Some goal - | _ -> failwith "unexpected comparison in loopIterations" let ( >>= ) = Option.bind let fixedLoopSize loopStatement func = - let findBreakComparison loopStatement = try (*find a single break in the else branch of a toplevel if*) - let compOption = ref None in - let visitor = new findBreakVisitor(compOption) in - ignore @@ visitCilBlock visitor (loopBody loopStatement); - !compOption - with | WrongOrMultiple -> None - in let getLoopVar = function - | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var varinfo), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob -> - (* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *) - let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in - Some (flip op, varinfo, goal) - | BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob -> - Some (op, varinfo, goal) - | _ -> None - in let getsPointedAt var func = try - let visitor = new isPointedAtVisitor(var) in - ignore @@ visitCilFunction visitor func; - false - with | Found -> true - in let assignmentDifference loop var = try - let diff = ref None in - let visitor = new findAssignmentConstDiff(diff, var) in - ignore @@ visitCilStmt visitor loop; - !diff - with | WrongOrMultiple -> None - in - findBreakComparison loopStatement >>= fun comparison -> getLoopVar comparison >>= fun (op, var, goal) -> if getsPointedAt var func then @@ -282,7 +292,9 @@ let fixedLoopSize loopStatement func = let s' = Z.to_int s in Logs.debug "iterations: %d" s'; Some s' - with Z.Overflow -> Logs.debug "iterations too big for integer"; None + with Z.Overflow -> + Logs.debug "iterations too big for integer"; + None class arrayVisitor = object From ee7734dec5bfe37dce5968c4aa0cb5f52443478a Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 22:13:55 +0300 Subject: [PATCH 533/689] Use let* option monad syntax from GobOption.Syntax in LoopUnrolling Co-authored-by: Simmo Saan --- src/util/loopUnrolling.ml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index ffd1c10418..f4e97e98bd 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -270,21 +270,21 @@ let loopIterations start diff goal shouldBeExact = Some (Z.succ roundedDown) ) -let ( >>= ) = Option.bind let fixedLoopSize loopStatement func = - findBreakComparison loopStatement >>= fun comparison -> - getLoopVar comparison >>= fun (op, var, goal) -> + let open GobOption.Syntax in + let* comparison = findBreakComparison loopStatement in + let* op, var, goal = getLoopVar comparison in if getsPointedAt var func then None else - constBefore var loopStatement func >>= fun start -> - assignmentDifference loopStatement var >>= fun diff -> + let* start = constBefore var loopStatement func in + let* diff = assignmentDifference loopStatement var in + let* goal = adjustGoal diff goal op in + let iterations = loopIterations start diff goal (op=Ne) in Logs.debug "comparison: %a" CilType.Exp.pretty comparison; Logs.debug "variable: %s" var.vname; Logs.debug "start: %a" GobZ.pretty start; Logs.debug "diff: %a" GobZ.pretty diff; - adjustGoal diff goal op >>= fun goal -> - let iterations = loopIterations start diff goal (op=Ne) in match iterations with | None -> Logs.debug "iterations failed"; None | Some s -> From da52931aef09c593278481bf6547e35d4cdcf9c5 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 18 Jun 2024 18:03:36 +0300 Subject: [PATCH 534/689] Call findAssignmentConstDiff on loops body instead the loop itself --- src/util/loopUnrolling.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 07c20cb574..ea92b0d1e6 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -262,7 +262,7 @@ let fixedLoopSize loopStatement func = in let assignmentDifference loop var = try let diff = ref None in let visitor = new findAssignmentConstDiff(diff, var) in - ignore @@ visitCilStmt visitor loop; + ignore @@ visitCilBlock visitor loop; !diff with | WrongOrMultiple -> None in @@ -273,7 +273,7 @@ let fixedLoopSize loopStatement func = None else constBefore var loopStatement func >>= fun start -> - assignmentDifference loopStatement var >>= fun diff -> + assignmentDifference (loopBody loopStatement) var >>= fun diff -> Logs.debug "comparison: "; Pretty.fprint stderr (dn_exp () comparison) ~width:max_int; Logs.debug ""; From 31c474cda6ad289e24df95f11865c0ea0dea7b73 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 20:04:50 +0300 Subject: [PATCH 535/689] Do not unroll loops in goblint stub functions --- src/util/loopUnrolling.ml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index ea92b0d1e6..390fb6f9a9 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -468,6 +468,8 @@ class loopUnrollingVisitor(func, totalLoops) = object end let unroll_loops fd totalLoops = - Cil.populateLabelAlphaTable fd; - let thisVisitor = new loopUnrollingVisitor(fd, totalLoops) in - ignore (visitCilFunction thisVisitor fd) + if not (Cil.hasAttribute "goblint_stub" fd.svar.vattr) then ( + Cil.populateLabelAlphaTable fd; + let thisVisitor = new loopUnrollingVisitor(fd, totalLoops) in + ignore (visitCilFunction thisVisitor fd) + ) From 446da4f340a3b456c9cb134380a9c45ca9a370b5 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 15:12:49 +0300 Subject: [PATCH 536/689] Simplify fixed loop size heuristics --- src/util/loopUnrolling.ml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index ea92b0d1e6..f8b53bed1c 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -347,15 +347,11 @@ let loop_unrolling_factor loopStatement func totalLoops = Found -> true in (*unroll up to near an instruction count, higher if the loop uses malloc/lock/threads *) - let targetInstructions = if unrollFunctionCalled then 50 else 25 in let loopStats = AutoTune0.collectFactors visitCilStmt loopStatement in if loopStats.instructions > 0 then - let fixedLoop = fixedLoopSize loopStatement func in - (* Unroll at least 10 times if there are only few (17?) loops *) - let unroll_min = if totalLoops < 17 && AutoTune0.isActivated "forceLoopUnrollForFewLoops" then 10 else 0 in - match fixedLoop with - | Some i -> if i * loopStats.instructions < 100 then (Logs.debug "fixed loop size"; i) else max unroll_min (100 / loopStats.instructions) - | _ -> max unroll_min (targetInstructions / loopStats.instructions) + match fixedLoopSize loopStatement func with + | Some i when i <= 20 -> Logs.debug "fixed loop size %d" i; i + | _ -> 4 else (* Don't unroll empty (= while(1){}) loops*) 0 From e8f51dcaa712c619b4e7b25c26081c6229a55a9f Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 19:53:38 +0300 Subject: [PATCH 537/689] Remove unused loopUnrollingCallVisitor --- src/util/loopUnrolling.ml | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index f8b53bed1c..0872eb9b1c 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -305,48 +305,9 @@ class arrayVisitor = object end let annotateArrays loopBody = ignore @@ visitCilBlock (new arrayVisitor) loopBody -(*unroll loops that handle locks, threads and mallocs, asserts and reach_error*) -class loopUnrollingCallVisitor = object - inherit nopCilVisitor - - method! vinst = function - | Call (_,Lval ((Var info), NoOffset),args,_,_) when LibraryFunctions.is_special info -> ( - Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo info) @@ fun () -> - let desc = LibraryFunctions.find info in - match desc.special args with - | Malloc _ - | Calloc _ - | Realloc _ - | Alloca _ - | Lock _ - | Unlock _ - | ThreadCreate _ - | Assert _ - | Bounded _ - | ThreadJoin _ -> - raise Found; - | _ -> - if List.mem "specification" @@ get_string_list "ana.autotune.activated" && get_string "ana.specification" <> "" then ( - if Svcomp.is_error_function' info (SvcompSpec.of_option ()) then - raise Found - ); - DoChildren - ) - | _ -> DoChildren - -end - let loop_unrolling_factor loopStatement func totalLoops = let configFactor = get_int "exp.unrolling-factor" in if AutoTune0.isActivated "loopUnrollHeuristic" then - let unrollFunctionCalled = try - let thisVisitor = new loopUnrollingCallVisitor in - ignore (visitCilStmt thisVisitor loopStatement); - false; - with - Found -> true - in - (*unroll up to near an instruction count, higher if the loop uses malloc/lock/threads *) let loopStats = AutoTune0.collectFactors visitCilStmt loopStatement in if loopStats.instructions > 0 then match fixedLoopSize loopStatement func with From 42c3f5a4274fcd868a5255c1393c880df21af4d3 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Mon, 30 Sep 2024 17:21:51 +0300 Subject: [PATCH 538/689] Do not turn on autotune loop unrolling when the only specification is NoDataRace --- src/util/loopUnrolling.ml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index a191e414f9..aea2a2cd92 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -307,6 +307,11 @@ class arrayVisitor = object end let annotateArrays loopBody = ignore @@ visitCilBlock (new arrayVisitor) loopBody +let max_default_unrolls_per_spec (spec: Svcomp.Specification.t) = + match spec with + | NoDataRace -> 0 + | _ -> 4 + let loop_unrolling_factor loopStatement func totalLoops = let configFactor = get_int "exp.unrolling-factor" in if AutoTune0.isActivated "loopUnrollHeuristic" then @@ -314,7 +319,10 @@ let loop_unrolling_factor loopStatement func totalLoops = if loopStats.instructions > 0 then match fixedLoopSize loopStatement func with | Some i when i <= 20 -> Logs.debug "fixed loop size %d" i; i - | _ -> 4 + | _ -> + match Svcomp.Specification.of_option () with + | [] -> 4 + | specs -> BatList.max @@ List.map max_default_unrolls_per_spec specs else (* Don't unroll empty (= while(1){}) loops*) 0 From c341c1cfbaaad52ff1282b08661e85334f383f9e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 2 Oct 2024 11:24:53 +0300 Subject: [PATCH 539/689] Add errors when architecture machdep not available --- src/common/util/cilfacade.ml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/common/util/cilfacade.ml b/src/common/util/cilfacade.ml index a71f2544e3..344d29d246 100644 --- a/src/common/util/cilfacade.ml +++ b/src/common/util/cilfacade.ml @@ -50,10 +50,16 @@ let init_options () = Cabs2cil.addNestedScopeAttr := get_bool "cil.addNestedScopeAttr"; if get_bool "ana.sv-comp.enabled" then ( - Cil.envMachine := match get_string "exp.architecture" with + let machine = match get_string "exp.architecture" with | "32bit" -> Machdep.gcc32 | "64bit" -> Machdep.gcc64 | _ -> assert false + in + match machine with + | Some _ -> Cil.envMachine := machine + | None -> + GobRef.wrap AnalysisState.should_warn true (fun () -> Messages.msg_final Error ~category:Unsound "Machine definition not available for selected architecture"); + Logs.error "Machine definition not available for selected architecture, defaulting to host" ) let init () = From 6d04b1ad5e4fc22db4a9df46bbfdbcd114c71124 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 2 Oct 2024 11:42:47 +0300 Subject: [PATCH 540/689] Disable 29-svcomp/36-svcomp-arch cram test on MacOS --- tests/regression/29-svcomp/dune | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/regression/29-svcomp/dune b/tests/regression/29-svcomp/dune index 2aede4e50b..95ac66a5ec 100644 --- a/tests/regression/29-svcomp/dune +++ b/tests/regression/29-svcomp/dune @@ -14,3 +14,7 @@ (cram (deps (glob_files *.c))) + +(cram + (applies_to 36-svcomp-arch) + (enabled_if (<> %{system} macosx))) ; https://dune.readthedocs.io/en/stable/reference/boolean-language.html From 5ba3996c496dca577cfeacc3a90f7872b81679c6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 2 Oct 2024 11:47:02 +0300 Subject: [PATCH 541/689] Default to unrolling 2 times for no-overflow spec --- src/util/loopUnrolling.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index aea2a2cd92..c883e121fc 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -310,6 +310,7 @@ let annotateArrays loopBody = ignore @@ visitCilBlock (new arrayVisitor) loopBod let max_default_unrolls_per_spec (spec: Svcomp.Specification.t) = match spec with | NoDataRace -> 0 + | NoOverflow -> 2 | _ -> 4 let loop_unrolling_factor loopStatement func totalLoops = From 8b35075f3f386e78111a18dc7cbbb7ca23858df9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 2 Oct 2024 16:51:56 +0300 Subject: [PATCH 542/689] Remove IntDomain.Booleans --- src/analyses/threadReturn.ml | 2 +- src/cdomain/value/cdomains/intDomain.ml | 6 ------ src/cdomain/value/cdomains/intDomain.mli | 4 ---- src/cdomains/lockDomain.ml | 2 +- .../00-sanity/33-hoare-over-paths.t | 20 +++++++++---------- tests/unit/maindomaintest.ml | 3 --- 6 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/analyses/threadReturn.ml b/src/analyses/threadReturn.ml index f3b9622b00..d72e2586e8 100644 --- a/src/analyses/threadReturn.ml +++ b/src/analyses/threadReturn.ml @@ -12,7 +12,7 @@ struct include Analyses.IdentitySpec let name () = "threadreturn" - module D = IntDomain.Booleans + module D = BoolDomain.MayBool include Analyses.ValueContexts(D) (* transfer functions *) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index a0e9a38f37..1e84e8365d 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2436,12 +2436,6 @@ struct let invariant _ _ = Invariant.none (* TODO *) end -module Booleans = MakeBooleans ( - struct - let truename = "True" - let falsename = "False" - end) - (* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) module Enums : S with type int_t = Z.t = struct module R = Interval32 (* range for exclusion *) diff --git a/src/cdomain/value/cdomains/intDomain.mli b/src/cdomain/value/cdomains/intDomain.mli index ca64692290..74588b94d8 100644 --- a/src/cdomain/value/cdomains/intDomain.mli +++ b/src/cdomain/value/cdomains/intDomain.mli @@ -452,10 +452,6 @@ end module MakeBooleans (Names: BooleansNames): IkindUnawareS with type t = bool (** Creates an abstract domain for integers represented by boolean values. *) -module Booleans: IkindUnawareS with type t = bool -(** Boolean abstract domain, where true is output "True" and false is output - * "False" *) - (* module None: S with type t = unit (** Domain with nothing in it. *) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 08353f4795..b71573d6f6 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -42,7 +42,7 @@ struct end (* true means exclusive lock and false represents reader lock*) -module RW = IntDomain.Booleans +module RW = BoolDomain.MayBool (* TODO: name booleans? *) (* pair Addr and RW; also change pretty printing*) module MakeRW (P: Printable.S) = diff --git a/tests/regression/00-sanity/33-hoare-over-paths.t b/tests/regression/00-sanity/33-hoare-over-paths.t index 5148f5e1f2..9f88f836b0 100644 --- a/tests/regression/00-sanity/33-hoare-over-paths.t +++ b/tests/regression/00-sanity/33-hoare-over-paths.t @@ -21,7 +21,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -44,7 +44,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -66,7 +66,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -88,7 +88,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -110,7 +110,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -132,7 +132,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -153,7 +153,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -172,7 +172,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -194,7 +194,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), @@ -215,7 +215,7 @@ }, {}, {}, {}), threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), threadflag:Singlethreaded, - threadreturn:True, + threadreturn:true, escape:{}, mutexEvents:(), access:(), diff --git a/tests/unit/maindomaintest.ml b/tests/unit/maindomaintest.ml index 8e1db76b83..4b379a252f 100644 --- a/tests/unit/maindomaintest.ml +++ b/tests/unit/maindomaintest.ml @@ -28,9 +28,6 @@ let domains: (module Lattice.S) list = [ (* (module IntDomainProperties.IntegerSet); (* TODO: top properties error *) *) (module IntDomain.Lifted); (* not abstraction of IntegerSet *) - (* TODO: move to intDomains if passing *) - (module IntDomain.Booleans); - (* TODO: fix *) (* (module IntDomain.Enums); *) (* (module IntDomain.IntDomTuple); *) From f4cc7503d47ae45e2076832150454289a8c28e1b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 2 Oct 2024 17:04:09 +0300 Subject: [PATCH 543/689] Remove Basetype.RawBools --- src/cdomain/value/cdomains/valueDomain.ml | 2 +- src/common/cdomains/basetype.ml | 11 ----------- src/domain/boolDomain.ml | 19 +++++++++++++------ 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/cdomain/value/cdomains/valueDomain.ml b/src/cdomain/value/cdomains/valueDomain.ml index 0fbfb50955..f9f4b06ffb 100644 --- a/src/cdomain/value/cdomains/valueDomain.ml +++ b/src/cdomain/value/cdomains/valueDomain.ml @@ -69,7 +69,7 @@ end (* ZeroInit is false if malloc was used to allocate memory and true if calloc was used *) module ZeroInit : ZeroInit = struct - include Lattice.Fake(Basetype.RawBools) + include Lattice.Fake (BoolDomain.Bool) let name () = "zeroinit" let is_malloc x = not x diff --git a/src/common/cdomains/basetype.ml b/src/common/cdomains/basetype.ml index 1b846309aa..bf832b1c3c 100644 --- a/src/common/cdomains/basetype.ml +++ b/src/common/cdomains/basetype.ml @@ -33,17 +33,6 @@ struct let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (XmlUtil.escape (show x)) end -module RawBools: Printable.S with type t = bool = -struct - include Printable.StdLeaf - open Pretty - type t = bool [@@deriving eq, ord, hash, to_yojson] - let show (x:t) = if x then "true" else "false" - let pretty () x = text (show x) - let name () = "raw bools" - let printXml f x = BatPrintf.fprintf f "\n\n%s\n\n\n" (show x) -end - module CilExp = struct include CilType.Exp diff --git a/src/domain/boolDomain.ml b/src/domain/boolDomain.ml index d92d716d7a..90337f1879 100644 --- a/src/domain/boolDomain.ml +++ b/src/domain/boolDomain.ml @@ -2,13 +2,20 @@ module Bool = struct - include Basetype.RawBools - (* type t = bool - let equal = Bool.equal - let compare = Bool.compare - let relift x = x - let arbitrary () = QCheck.bool *) + include Printable.StdLeaf + type t = bool [@@deriving eq, ord, hash] + let name () = "bool" + let show x = if x then "true" else "false" + include Printable.SimpleShow (struct + type nonrec t = t + let show = show + end) + let to_yojson = [%to_yojson: bool] (* override to_yojson from SimpleShow *) + + let arbitrary () = QCheck.bool + + (* For Lattice.S *) let pretty_diff () (x,y) = GoblintCil.Pretty.dprintf "%s: %a not leq %a" (name ()) pretty x pretty y end From 798a3d8098e8bd35a07882c5ded9b727ae5628d2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 2 Oct 2024 17:13:31 +0300 Subject: [PATCH 544/689] Remove IntDomain.MakeBooleans --- src/cdomain/value/cdomains/concDomain.ml | 18 +++---- src/cdomain/value/cdomains/intDomain.ml | 60 ------------------------ src/cdomain/value/cdomains/intDomain.mli | 20 -------- src/cdomains/threadFlagDomain.ml | 7 +-- src/domain/boolDomain.ml | 39 ++++++++++++--- 5 files changed, 47 insertions(+), 97 deletions(-) diff --git a/src/cdomain/value/cdomains/concDomain.ml b/src/cdomain/value/cdomains/concDomain.ml index 5f609a31d8..467159c9da 100644 --- a/src/cdomain/value/cdomains/concDomain.ml +++ b/src/cdomain/value/cdomains/concDomain.ml @@ -1,7 +1,7 @@ (** Domains for thread sets and their uniqueness. *) -module ThreadSet = -struct +module ThreadSet = +struct include SetDomain.Make (ThreadIdDomain.Thread) let is_top = mem UnknownThread @@ -27,10 +27,11 @@ module CreatedThreadSet = ThreadSet module ThreadCreation = struct module UNames = struct - let truename = "repeated" - let falsename = "unique" + let name = "unique" + let true_name = "repeated" + let false_name = "unique" end - module Uniqueness = IntDomain.MakeBooleans (UNames) + module Uniqueness = BoolDomain.MakeMayBool (UNames) module ParentThreadSet = struct include ThreadSet @@ -38,12 +39,13 @@ struct end module DirtyExitNames = struct - let truename = "dirty exit" - let falsename = "clean exit" + let name = "exit" + let true_name = "dirty exit" + let false_name = "clean exit" end (* A thread exits cleanly iff it joined all threads it started, and they also all exit cleanly *) - module DirtyExit = IntDomain.MakeBooleans (DirtyExitNames) + module DirtyExit = BoolDomain.MakeMayBool (DirtyExitNames) include Lattice.Prod3 (Uniqueness) (ParentThreadSet) (DirtyExit) end diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml index 1e84e8365d..e50b3f26cc 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -2376,66 +2376,6 @@ struct let project ik p t = t end -(* BOOLEAN DOMAINS *) - -module type BooleansNames = -sig - val truename: string - val falsename: string -end - -module MakeBooleans (N: BooleansNames) = -struct - type int_t = IntOps.Int64Ops.t - type t = bool [@@deriving eq, ord, hash, to_yojson] - let name () = "booleans" - let top () = true - let bot () = false - let top_of ik = top () - let bot_of ik = bot () - let show x = if x then N.truename else N.falsename - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - let is_top x = x (* override Std *) - - let equal_to i x = if x then `Top else failwith "unsupported: equal_to with bottom" - let cast_to ?(suppress_ovwarn=false) ?torg _ x = x (* ok since there's no smaller ikind to cast to *) - - let leq x y = not x || y - let join = (||) - let widen = join - let meet = (&&) - let narrow = meet - - let of_bool x = x - let to_bool x = Some x - let of_int x = x = Int64.zero - let to_int x = if x then None else Some Int64.zero - - let neg x = x - let add x y = x || y - let sub x y = x || y - let mul x y = x && y - let div x y = true - let rem x y = true - let lt n1 n2 = true - let gt n1 n2 = true - let le n1 n2 = true - let ge n1 n2 = true - let eq n1 n2 = true - let ne n1 n2 = true - let lognot x = true - let logand x y = x && y - let logor x y = x || y - let logxor x y = x && not y || not x && y - let shift_left n1 n2 = n1 - let shift_right n1 n2 = n1 - let c_lognot = (not) - let c_logand = (&&) - let c_logor = (||) - let arbitrary () = QCheck.bool - let invariant _ _ = Invariant.none (* TODO *) -end - (* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) module Enums : S with type int_t = Z.t = struct module R = Interval32 (* range for exclusion *) diff --git a/src/cdomain/value/cdomains/intDomain.mli b/src/cdomain/value/cdomains/intDomain.mli index 74588b94d8..e7667c9b14 100644 --- a/src/cdomain/value/cdomains/intDomain.mli +++ b/src/cdomain/value/cdomains/intDomain.mli @@ -436,23 +436,3 @@ module Reverse (Base: IkindUnawareS): IkindUnawareS with type t = Base.t and typ (* module IncExcInterval : S with type t = [ | `Excluded of Interval.t| `Included of Interval.t ] *) (** Inclusive and exclusive intervals. Warning: NOT A LATTICE *) module Enums : S with type int_t = Z.t - -(** {b Boolean domains} *) - -module type BooleansNames = -sig - val truename: string - (** The name of the [true] abstract value *) - - val falsename: string - (** The name of the [false] abstract value *) -end -(** Parameter signature for the [MakeBooleans] functor. *) - -module MakeBooleans (Names: BooleansNames): IkindUnawareS with type t = bool -(** Creates an abstract domain for integers represented by boolean values. *) - -(* -module None: S with type t = unit -(** Domain with nothing in it. *) -*) diff --git a/src/cdomains/threadFlagDomain.ml b/src/cdomains/threadFlagDomain.ml index 80ba9b7a52..42571656e7 100644 --- a/src/cdomains/threadFlagDomain.ml +++ b/src/cdomains/threadFlagDomain.ml @@ -15,10 +15,11 @@ module Trivial: S = struct module TrivialNames = struct - let truename = "Multithreaded" - let falsename = "Singlethreaded" + let name = "MT mode" + let true_name = "Multithreaded" + let false_name = "Singlethreaded" end - include IntDomain.MakeBooleans (TrivialNames) + include BoolDomain.MakeMayBool (TrivialNames) let is_multi x = x let is_not_main x = x diff --git a/src/domain/boolDomain.ml b/src/domain/boolDomain.ml index 90337f1879..18399365a5 100644 --- a/src/domain/boolDomain.ml +++ b/src/domain/boolDomain.ml @@ -1,17 +1,23 @@ (** Boolean domains. *) -module Bool = +module type Names = +sig + val name: string + val true_name: string + val false_name: string +end + +module MakeBool (Names: Names) = struct include Printable.StdLeaf type t = bool [@@deriving eq, ord, hash] - let name () = "bool" + let name () = Names.name - let show x = if x then "true" else "false" + let show x = if x then Names.true_name else Names.false_name include Printable.SimpleShow (struct type nonrec t = t let show = show end) - let to_yojson = [%to_yojson: bool] (* override to_yojson from SimpleShow *) let arbitrary () = QCheck.bool @@ -19,9 +25,22 @@ struct let pretty_diff () (x,y) = GoblintCil.Pretty.dprintf "%s: %a not leq %a" (name ()) pretty x pretty y end -module MayBool: Lattice.S with type t = bool = +module StdNames: Names = struct - include Bool + let name = "bool" + let true_name = "true" + let false_name = "false" +end + +module Bool = +struct + include MakeBool (StdNames) + let to_yojson = [%to_yojson: bool] (* override to_yojson from SimpleShow *) +end + +module MakeMayBool (Names: Names): Lattice.S with type t = bool = +struct + include MakeBool (Names) let bot () = false let is_bot x = x = false let top () = true @@ -33,6 +52,14 @@ struct let narrow = (&&) end +module MayBool: Lattice.S with type t = bool = +struct + include MakeMayBool (StdNames) + let to_yojson = [%to_yojson: bool] (* override to_yojson from SimpleShow *) +end + +(* TODO: MakeMustBool? *) + module MustBool: Lattice.S with type t = bool = struct include Bool From 09e02ce53d91a454badbd030dca43e04e802903c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 2 Oct 2024 17:14:18 +0300 Subject: [PATCH 545/689] Remove unused opens in ContextGasLifter --- src/lifters/contextGasLifter.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lifters/contextGasLifter.ml b/src/lifters/contextGasLifter.ml index adb55aa7a2..98974d81a1 100644 --- a/src/lifters/contextGasLifter.ml +++ b/src/lifters/contextGasLifter.ml @@ -3,9 +3,7 @@ open Batteries open GoblintCil -open MyCFG open Analyses -open ConstrSys open GobConfig module M = Messages From 25a1aca3e559e954bd45bfdeaa932eefe7728e9e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 20 Jun 2024 13:01:59 +0300 Subject: [PATCH 546/689] Assume var is 0 if there was no assign before loop --- src/util/loopUnrolling.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index c883e121fc..7347bca361 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -277,7 +277,8 @@ let fixedLoopSize loopStatement func = if getsPointedAt var func then None else - let* start = constBefore var loopStatement func in + (* Assume var value to be 0 if there was no constant assignment to the var before loop *) + let start = Option.value (constBefore var loopStatement func) ~default:Z.zero in let* diff = assignmentDifference (loopBody loopStatement) var in let* goal = adjustGoal diff goal op in let iterations = loopIterations start diff goal (op=Ne) in From 64b3baaec718a08698c505c052dee1c50e19bfdb Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 27 Sep 2024 15:12:01 +0300 Subject: [PATCH 547/689] Bugfix: do not assume loop start to be 0 in case of decreasing values --- src/util/loopUnrolling.ml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 7347bca361..905cc39e6a 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -277,9 +277,10 @@ let fixedLoopSize loopStatement func = if getsPointedAt var func then None else - (* Assume var value to be 0 if there was no constant assignment to the var before loop *) - let start = Option.value (constBefore var loopStatement func) ~default:Z.zero in - let* diff = assignmentDifference (loopBody loopStatement) var in + let diff = Option.value (assignmentDifference (loopBody loopStatement) var) ~default:Z.one in + (* Assume var start value if there was no constant assignment to the var before loop; + Assume it to be 0, if loop is increasing and 11 (TODO: can we do better than just 11?) if loop is decreasing *) + let start = Option.value (constBefore var loopStatement func) ~default:(if diff < Z.zero then Z.of_int 11 else Z.zero) in let* goal = adjustGoal diff goal op in let iterations = loopIterations start diff goal (op=Ne) in Logs.debug "comparison: %a" CilType.Exp.pretty comparison; From c439f7934ecc50a97a300b280aaa740187ee0aab Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 2 Oct 2024 22:18:05 +0300 Subject: [PATCH 548/689] Handle loop statement comparison between two variables in loopUnrolling --- src/util/loopUnrolling.ml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index c883e121fc..fe9fec6ce8 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -220,13 +220,21 @@ let findBreakComparison loopStatement = with WrongOrMultiple -> None -let getLoopVar = function +let getLoopVar loopStatement func = function | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var varinfo), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob -> (* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *) let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in Some (flip op, varinfo, goal) | BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob -> Some (op, varinfo, goal) + (* When loop condition has a comparison between variables, we assume that the left one is the counter and right one is the bound. + TODO: can we do something more meaningful instead of this assumption? *) + | BinOp (op, Lval ((Var varinfo), NoOffset), Lval ((Var varinfo2), NoOffset), (TInt _)) + | BinOp (op, CastE ((TInt _), (Lval ((Var varinfo), NoOffset))), Lval ((Var varinfo2), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob && not varinfo2.vglob -> + begin match constBefore varinfo2 loopStatement func with + | Some goal -> Logs.debug "const: %a %a" CilType.Varinfo.pretty varinfo2 GobZ.pretty goal; Some (op, varinfo, goal) + | None -> None + end; | _ -> None let getsPointedAt var func = @@ -273,7 +281,7 @@ let loopIterations start diff goal shouldBeExact = let fixedLoopSize loopStatement func = let open GobOption.Syntax in let* comparison = findBreakComparison loopStatement in - let* op, var, goal = getLoopVar comparison in + let* op, var, goal = getLoopVar loopStatement func comparison in if getsPointedAt var func then None else From e625b5604b212a210eac29fb86d7b55f6d3a3191 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 3 Oct 2024 23:09:06 +0300 Subject: [PATCH 549/689] Do not compute nr of instructions and unroll empty loops as unrolling and analyzing empty loops is cheaper than visiting loops for collecting the nr of the instructions --- src/util/loopUnrolling.ml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index c883e121fc..175493314f 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -316,17 +316,12 @@ let max_default_unrolls_per_spec (spec: Svcomp.Specification.t) = let loop_unrolling_factor loopStatement func totalLoops = let configFactor = get_int "exp.unrolling-factor" in if AutoTune0.isActivated "loopUnrollHeuristic" then - let loopStats = AutoTune0.collectFactors visitCilStmt loopStatement in - if loopStats.instructions > 0 then - match fixedLoopSize loopStatement func with - | Some i when i <= 20 -> Logs.debug "fixed loop size %d" i; i - | _ -> - match Svcomp.Specification.of_option () with - | [] -> 4 - | specs -> BatList.max @@ List.map max_default_unrolls_per_spec specs - else - (* Don't unroll empty (= while(1){}) loops*) - 0 + match fixedLoopSize loopStatement func with + | Some i when i <= 20 -> Logs.debug "fixed loop size %d" i; i + | _ -> + match Svcomp.Specification.of_option () with + | [] -> 4 + | specs -> BatList.max @@ List.map max_default_unrolls_per_spec specs else configFactor From 30a2ace5914bf496e1a81b72b146239daba41893 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 4 Oct 2024 10:23:23 +0300 Subject: [PATCH 550/689] Remove fixed malloc wrappers from svcomp conf --- conf/svcomp-validate.json | 21 --------------------- conf/svcomp.json | 21 --------------------- 2 files changed, 42 deletions(-) diff --git a/conf/svcomp-validate.json b/conf/svcomp-validate.json index a234aeb0d5..8e11fee7f5 100644 --- a/conf/svcomp-validate.json +++ b/conf/svcomp-validate.json @@ -46,27 +46,6 @@ "context": { "widen": false }, - "malloc": { - "wrappers": [ - "kmalloc", - "__kmalloc", - "usb_alloc_urb", - "__builtin_alloca", - "kzalloc", - - "ldv_malloc", - - "kzalloc_node", - "ldv_zalloc", - "kmalloc_array", - "kcalloc", - - "ldv_xmalloc", - "ldv_xzalloc", - "ldv_calloc", - "ldv_kzalloc" - ] - }, "base": { "arrays": { "domain": "partitioned" diff --git a/conf/svcomp.json b/conf/svcomp.json index 467d294bdd..12740a00ce 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -45,27 +45,6 @@ "context": { "widen": false }, - "malloc": { - "wrappers": [ - "kmalloc", - "__kmalloc", - "usb_alloc_urb", - "__builtin_alloca", - "kzalloc", - - "ldv_malloc", - - "kzalloc_node", - "ldv_zalloc", - "kmalloc_array", - "kcalloc", - - "ldv_xmalloc", - "ldv_xzalloc", - "ldv_calloc", - "ldv_kzalloc" - ] - }, "base": { "arrays": { "domain": "partitioned" From 50b0bddc78b07ca5bd9d6712f20fd9f9a5b78e51 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 4 Oct 2024 11:02:30 +0300 Subject: [PATCH 551/689] Remove witness exclude-vars from svcomp conf --- conf/svcomp.json | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/conf/svcomp.json b/conf/svcomp.json index 467d294bdd..682d524105 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -128,17 +128,7 @@ "after-lock": false, "other": false, "accessed": false, - "exact": true, - "exclude-vars": [ - "tmp\\(___[0-9]+\\)?", - "cond", - "RETURN", - "__\\(cil_\\)?tmp_?[0-9]*\\(_[0-9]+\\)?", - ".*____CPAchecker_TMP_[0-9]+", - "__VERIFIER_assert__cond", - "__ksymtab_.*", - "\\(ldv_state_variable\\|ldv_timer_state\\|ldv_timer_list\\|ldv_irq_\\(line_\\|data_\\)?[0-9]+\\|ldv_retval\\)_[0-9]+" - ] + "exact": true } }, "pre": { From 761282ba8f6b6d1d76df21097200dabf41edb65b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Fri, 4 Oct 2024 13:18:56 +0300 Subject: [PATCH 552/689] Do not unroll loops with a nesting higher than 3 --- src/util/loopUnrolling.ml | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 175493314f..8c812d598b 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -402,16 +402,19 @@ let copy_and_patch_labels break_target current_continue_target stmts = let patchLabelsVisitor = new patchLabelsGotosVisitor(StatementHashTable.find_opt gotos) in List.map (visitCilStmt patchLabelsVisitor) stmts' -class loopUnrollingVisitor(func, totalLoops) = object +class loopUnrollingVisitor (func, totalLoops) = object (* Labels are simply handled by giving them a fresh name. Jumps coming from outside will still always go to the original label! *) inherit nopCilVisitor - method! vstmt s = - let duplicate_and_rem_labels s = - match s.skind with - | Loop (b,loc, loc2, break , continue) -> - let factor = loop_unrolling_factor s func totalLoops in - if(factor > 0) then ( + val mutable nests = 0 + + method! vstmt stmt = + let duplicate_and_rem_labels stmt = + match stmt.skind with + | Loop (b, loc, loc2, break, continue) -> + nests <- nests - 1; Logs.debug "nests: %i" nests; + let factor = loop_unrolling_factor stmt func totalLoops in + if factor > 0 then ( Logs.info "unrolling loop at %a with factor %d" CilType.Location.pretty loc factor; annotateArrays b; (* top-level breaks should immediately go to the end of the loop, and not just break out of the current iteration *) @@ -423,11 +426,14 @@ class loopUnrollingVisitor(func, totalLoops) = object one_copy_stmts @ [current_continue_target] ) in - mkStmt (Block (mkBlock (List.flatten copies @ [s; break_target]))) - ) else s (*no change*) - | _ -> s + mkStmt (Block (mkBlock (List.flatten copies @ [stmt; break_target]))) + ) else stmt (*no change*) + | _ -> stmt in - ChangeDoChildrenPost(s, duplicate_and_rem_labels) + match stmt.skind with + | Loop _ when nests + 1 < 4 -> nests <- nests + 1; ChangeDoChildrenPost(stmt, duplicate_and_rem_labels) + | Loop _ -> SkipChildren + | _ -> ChangeDoChildrenPost(stmt, duplicate_and_rem_labels) end let unroll_loops fd totalLoops = From 67f8fe9195d3c6a96b01a0a5ceddf05a81fb1ff6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Oct 2024 10:28:06 +0300 Subject: [PATCH 553/689] Add test for invariant_set widening tokens (issue #1299) --- .../56-witness/64-apron-unassume-set-tokens.c | 18 ++++++ .../64-apron-unassume-set-tokens.yml | 59 +++++++++++++++++++ tests/regression/56-witness/dune | 3 +- 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tests/regression/56-witness/64-apron-unassume-set-tokens.c create mode 100644 tests/regression/56-witness/64-apron-unassume-set-tokens.yml diff --git a/tests/regression/56-witness/64-apron-unassume-set-tokens.c b/tests/regression/56-witness/64-apron-unassume-set-tokens.c new file mode 100644 index 0000000000..75a6b5eee5 --- /dev/null +++ b/tests/regression/56-witness/64-apron-unassume-set-tokens.c @@ -0,0 +1,18 @@ +// SKIP PARAM: --set ana.activated[+] apron --set ana.activated[+] unassume --set witness.yaml.unassume 64-apron-unassume-set-tokens.yml --set ana.apron.domain polyhedra --enable ana.widen.tokens +#include +// Uses polyhedra instead of octagon such that widening tokens are actually needed by test instead of narrowing. +// Copied & extended from 56-witness/12-apron-unassume-branch. +int main() { + int i = 0; + while (i < 100) { + i++; + } + assert(i == 100); + + int j = 0; + while (j < 100) { + j++; + } + assert(j == 100); + return 0; +} diff --git a/tests/regression/56-witness/64-apron-unassume-set-tokens.yml b/tests/regression/56-witness/64-apron-unassume-set-tokens.yml new file mode 100644 index 0000000000..8411ed045f --- /dev/null +++ b/tests/regression/56-witness/64-apron-unassume-set-tokens.yml @@ -0,0 +1,59 @@ +- entry_type: invariant_set + metadata: + format_version: "0.1" + uuid: 0a72f7b3-7826-4f68-bc7b-25425e95946e + creation_time: 2022-07-26T09:11:03Z + producer: + name: Goblint + version: heads/yaml-witness-unassume-0-g48503c690-dirty + command_line: '''./goblint'' ''--enable'' ''dbg.debug'' ''--enable'' ''dbg.regression'' + ''--html'' ''--set'' ''ana.activated[+]'' ''apron'' ''--enable'' ''witness.yaml.enabled'' + ''64-apron-unassume-set-tokens.c''' + task: + input_files: + - 64-apron-unassume-set-tokens.c + input_file_hashes: + 64-apron-unassume-set-tokens.c: 71e40ed99b5217343d0831e293e7207e5bd30ce53f6ab73f0c1ef6ced1afcc60 + data_model: LP64 + language: C + content: + - invariant: + type: location_invariant + location: + file_name: 64-apron-unassume-set-tokens.c + file_hash: 71e40ed99b5217343d0831e293e7207e5bd30ce53f6ab73f0c1ef6ced1afcc60 + line: 8 + column: 3 + function: main + value: 99LL - (long long )i >= 0LL + format: c_expression + - invariant: + type: location_invariant + location: + file_name: 64-apron-unassume-set-tokens.c + file_hash: 71e40ed99b5217343d0831e293e7207e5bd30ce53f6ab73f0c1ef6ced1afcc60 + line: 8 + column: 3 + function: main + value: (long long )i >= 0LL + format: c_expression + - invariant: + type: location_invariant + location: + file_name: 64-apron-unassume-set-tokens.c + file_hash: 71e40ed99b5217343d0831e293e7207e5bd30ce53f6ab73f0c1ef6ced1afcc60 + line: 14 + column: 3 + function: main + value: 99LL - (long long )j >= 0LL + format: c_expression + - invariant: + type: location_invariant + location: + file_name: 64-apron-unassume-set-tokens.c + file_hash: 71e40ed99b5217343d0831e293e7207e5bd30ce53f6ab73f0c1ef6ced1afcc60 + line: 14 + column: 3 + function: main + value: (long long )j >= 0LL + format: c_expression diff --git a/tests/regression/56-witness/dune b/tests/regression/56-witness/dune index 215e47deb2..f6694c60ec 100644 --- a/tests/regression/56-witness/dune +++ b/tests/regression/56-witness/dune @@ -21,7 +21,8 @@ (run %{update_suite} hh-ex3 -q) (run %{update_suite} bh-ex1-poly -q) (run %{update_suite} apron-unassume-precheck -q) - (run %{update_suite} apron-tracked-global-annot -q))))) + (run %{update_suite} apron-tracked-global-annot -q) + (run %{update_suite} apron-unassume-set-tokens -q))))) (cram (deps (glob_files *.c) (glob_files ??-*.yml))) From 7ec6b0578b6da2996114c8f9a60a75cb056fa231 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 8 Oct 2024 17:50:41 +0300 Subject: [PATCH 554/689] Add optional int indices to widening tokens --- src/analyses/apron/relationAnalysis.apron.ml | 4 ++-- src/analyses/base.ml | 4 ++-- src/analyses/unassumeAnalysis.ml | 12 ++++++------ src/domains/events.ml | 4 ++-- src/lifters/wideningTokens.ml | 3 +-- src/lifters/wideningTokens0.ml | 6 ++++++ 6 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 src/lifters/wideningTokens0.ml diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index da14dfff1d..f82bd37e33 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -701,7 +701,7 @@ struct Priv.escape ctx.node (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg st escaped | Assert exp -> assert_fn ctx exp true - | Events.Unassume {exp = e; uuids} -> + | Events.Unassume {exp = e; tokens} -> let e_orig = e in let ask = Analyses.ask_of_ctx ctx in let e = replace_deref_exps ctx.ask e in @@ -737,7 +737,7 @@ struct (* TODO: parallel write_global? *) let st = - WideningTokens.with_side_tokens (WideningTokens.TS.of_list uuids) (fun () -> + WideningTokens.with_side_tokens (WideningTokens.TS.of_list tokens) (fun () -> VH.fold (fun v v_in st -> (* TODO: is this sideg fine? *) write_global ask ctx.global ctx.sideg st v v_in diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 1699108394..a5a9fc150e 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -3091,8 +3091,8 @@ struct set ~ctx ctx.local (eval_lv ~ctx ctx.local lval) (Cilfacade.typeOfLval lval) (Thread (ValueDomain.Threads.singleton tid)) | Events.Assert exp -> assert_fn ctx exp true - | Events.Unassume {exp; uuids} -> - Timing.wrap "base unassume" (unassume ctx exp) uuids + | Events.Unassume {exp; tokens} -> + Timing.wrap "base unassume" (unassume ctx exp) tokens | Events.Longjmped {lval} -> begin match lval with | Some lval -> diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 8f8892b8be..348215993b 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -29,7 +29,7 @@ struct type inv = { exp: Cil.exp; - uuid: string; + token: WideningTokens.Token.t; } let invs: inv NH.t = NH.create 100 @@ -101,7 +101,7 @@ struct match InvariantParser.parse_cil inv_parser ~check:false ~fundec ~loc inv_cabs with | Ok inv_exp -> M.debug ~category:Witness ~loc:msgLoc "located invariant to %a: %a" Node.pretty n Cil.d_exp inv_exp; - NH.add invs n {exp = inv_exp; uuid} + NH.add invs n {exp = inv_exp; token = (uuid, None)} (* TODO: Some *) | Error e -> M.error ~category:Witness ~loc:msgLoc "CIL couldn't parse invariant: %s" inv; M.info ~category:Witness ~loc:msgLoc "invariant has undefined variables or side effects: %s" inv @@ -154,7 +154,7 @@ struct M.debug ~category:Witness ~loc:msgLoc "located invariant to %a: %a" Node.pretty n Cil.d_exp inv_exp; if not (NH.mem pre_invs n) then NH.replace pre_invs n (EH.create 10); - EH.add (NH.find pre_invs n) pre_exp {exp = inv_exp; uuid} + EH.add (NH.find pre_invs n) pre_exp {exp = inv_exp; token = (uuid, None)} (* TODO: Some *) | Error e -> M.error ~category:Witness ~loc:msgLoc "CIL couldn't parse invariant: %s" inv; M.info ~category:Witness ~loc:msgLoc "invariant has undefined variables or side effects: %s" inv @@ -262,9 +262,9 @@ struct M.info ~category:Witness "unassume invariant: %a" CilType.Exp.pretty e; if not !AnalysisState.postsolving then ( if not (GobConfig.get_bool "ana.unassume.precheck" && Queries.ID.to_bool (ctx.ask (EvalInt e)) = Some false) then ( - let uuids = x.uuid :: List.map (fun {uuid; _} -> uuid) xs in - ctx.emit (Unassume {exp = e; uuids}); - List.iter WideningTokens.add uuids + let tokens = x.token :: List.map (fun {token; _} -> token) xs in + ctx.emit (Unassume {exp = e; tokens}); + List.iter WideningTokens.add tokens ) ); ctx.local diff --git a/src/domains/events.ml b/src/domains/events.ml index b194847bac..b3054b8416 100644 --- a/src/domains/events.ml +++ b/src/domains/events.ml @@ -14,7 +14,7 @@ type t = | Assign of {lval: CilType.Lval.t; exp: CilType.Exp.t} (** Used to simulate old [ctx.assign]. *) (* TODO: unused *) | UpdateExpSplit of exp (** Used by expsplit analysis to evaluate [exp] on post-state. *) | Assert of exp - | Unassume of {exp: CilType.Exp.t; uuids: string list} + | Unassume of {exp: CilType.Exp.t; tokens: WideningTokens0.Token.t list} | Longjmped of {lval: CilType.Lval.t option} (** Should event be emitted after transfer function raises [Deadcode]? *) @@ -45,5 +45,5 @@ let pretty () = function | Assign {lval; exp} -> dprintf "Assign {lval=%a, exp=%a}" CilType.Lval.pretty lval CilType.Exp.pretty exp | UpdateExpSplit exp -> dprintf "UpdateExpSplit %a" d_exp exp | Assert exp -> dprintf "Assert %a" d_exp exp - | Unassume {exp; uuids} -> dprintf "Unassume {exp=%a; uuids=%a}" d_exp exp (docList Pretty.text) uuids + | Unassume {exp; tokens} -> dprintf "Unassume {exp=%a; tokens=%a}" d_exp exp (d_list ", " WideningTokens0.Token.pretty) tokens | Longjmped {lval} -> dprintf "Longjmped {lval=%a}" (docOpt (CilType.Lval.pretty ())) lval diff --git a/src/lifters/wideningTokens.ml b/src/lifters/wideningTokens.ml index 41bb5d8477..4d60099d7e 100644 --- a/src/lifters/wideningTokens.ml +++ b/src/lifters/wideningTokens.ml @@ -6,8 +6,7 @@ @see Mihaila, B., Sepp, A. & Simon, A. Widening as Abstract Domain. *) -(** Widening token. *) -module Token = Basetype.RawStrings (* Change to variant type if need other tokens than witness UUIDs. *) +include WideningTokens0 (** Widening token set. *) module TS = SetDomain.ToppedSet (Token) (struct let topname = "Top" end) diff --git a/src/lifters/wideningTokens0.ml b/src/lifters/wideningTokens0.ml new file mode 100644 index 0000000000..dcbf77424e --- /dev/null +++ b/src/lifters/wideningTokens0.ml @@ -0,0 +1,6 @@ +(** Widening token. *) +module Token = +struct + (* Change to variant type if need other tokens than witness UUIDs. *) + include Printable.Prod (Basetype.RawStrings) (Printable.Option (IntDomain.Integers (IntOps.NIntOps)) (struct let name = "None" end)) +end From 21c000c71bfae7e31fbc18d83d61a802dd854c03 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 8 Oct 2024 17:55:02 +0300 Subject: [PATCH 555/689] Add invariant_set index to widening token --- src/analyses/unassumeAnalysis.ml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 348215993b..6b5b495233 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -90,7 +90,7 @@ struct let uuid = entry.metadata.uuid in let target_type = YamlWitnessType.EntryType.entry_type entry.entry_type in - let unassume_nodes_invariant ~loc ~nodes inv = + let unassume_nodes_invariant ~loc ~nodes ?i inv = let msgLoc: M.Location.t = CilLocation loc in match InvariantParser.parse_cabs inv with | Ok inv_cabs -> @@ -101,7 +101,7 @@ struct match InvariantParser.parse_cil inv_parser ~check:false ~fundec ~loc inv_cabs with | Ok inv_exp -> M.debug ~category:Witness ~loc:msgLoc "located invariant to %a: %a" Node.pretty n Cil.d_exp inv_exp; - NH.add invs n {exp = inv_exp; token = (uuid, None)} (* TODO: Some *) + NH.add invs n {exp = inv_exp; token = (uuid, i)} | Error e -> M.error ~category:Witness ~loc:msgLoc "CIL couldn't parse invariant: %s" inv; M.info ~category:Witness ~loc:msgLoc "invariant has undefined variables or side effects: %s" inv @@ -154,7 +154,7 @@ struct M.debug ~category:Witness ~loc:msgLoc "located invariant to %a: %a" Node.pretty n Cil.d_exp inv_exp; if not (NH.mem pre_invs n) then NH.replace pre_invs n (EH.create 10); - EH.add (NH.find pre_invs n) pre_exp {exp = inv_exp; token = (uuid, None)} (* TODO: Some *) + EH.add (NH.find pre_invs n) pre_exp {exp = inv_exp; token = (uuid, None)} | Error e -> M.error ~category:Witness ~loc:msgLoc "CIL couldn't parse invariant: %s" inv; M.info ~category:Witness ~loc:msgLoc "invariant has undefined variables or side effects: %s" inv @@ -189,42 +189,42 @@ struct let unassume_invariant_set (invariant_set: YamlWitnessType.InvariantSet.t) = - let unassume_location_invariant (location_invariant: YamlWitnessType.InvariantSet.LocationInvariant.t) = + let unassume_location_invariant ~i (location_invariant: YamlWitnessType.InvariantSet.LocationInvariant.t) = let loc = YamlWitness.loc_of_location location_invariant.location in let inv = location_invariant.value in let msgLoc: M.Location.t = CilLocation loc in match Locator.find_opt location_locator loc with | Some nodes -> - unassume_nodes_invariant ~loc ~nodes inv + unassume_nodes_invariant ~loc ~nodes ~i inv | None -> M.warn ~category:Witness ~loc:msgLoc "couldn't locate invariant: %s" inv in - let unassume_loop_invariant (loop_invariant: YamlWitnessType.InvariantSet.LoopInvariant.t) = + let unassume_loop_invariant ~i (loop_invariant: YamlWitnessType.InvariantSet.LoopInvariant.t) = let loc = YamlWitness.loc_of_location loop_invariant.location in let inv = loop_invariant.value in let msgLoc: M.Location.t = CilLocation loc in match Locator.find_opt loop_locator loc with | Some nodes -> - unassume_nodes_invariant ~loc ~nodes inv + unassume_nodes_invariant ~loc ~nodes ~i inv | None -> M.warn ~category:Witness ~loc:msgLoc "couldn't locate invariant: %s" inv in - let validate_invariant (invariant: YamlWitnessType.InvariantSet.Invariant.t) = + let validate_invariant i (invariant: YamlWitnessType.InvariantSet.Invariant.t) = let target_type = YamlWitnessType.InvariantSet.InvariantType.invariant_type invariant.invariant_type in match YamlWitness.invariant_type_enabled target_type, invariant.invariant_type with | true, LocationInvariant x -> - unassume_location_invariant x + unassume_location_invariant ~i x | true, LoopInvariant x -> - unassume_loop_invariant x + unassume_loop_invariant ~i x | false, (LocationInvariant _ | LoopInvariant _) -> M.info_noloc ~category:Witness "disabled invariant of type %s" target_type in - List.iter validate_invariant invariant_set.content + List.iteri validate_invariant invariant_set.content in match YamlWitness.entry_type_enabled target_type, entry.entry_type with From 57a044713a03cd28d199fb16cd4c9b332b31f32d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Oct 2024 10:35:11 +0300 Subject: [PATCH 556/689] Rename widening token modules --- src/analyses/apron/relationAnalysis.apron.ml | 6 +++--- src/analyses/base.ml | 6 +++--- src/analyses/mCP.ml | 12 ++++++------ src/analyses/unassumeAnalysis.ml | 4 ++-- src/domains/events.ml | 4 ++-- src/framework/control.ml | 2 +- src/goblint_lib.ml | 3 ++- src/lifters/wideningToken.ml | 4 ++++ .../{wideningTokens.ml => wideningTokenLifter.ml} | 2 +- src/lifters/wideningTokens0.ml | 6 ------ 10 files changed, 24 insertions(+), 25 deletions(-) create mode 100644 src/lifters/wideningToken.ml rename src/lifters/{wideningTokens.ml => wideningTokenLifter.ml} (99%) delete mode 100644 src/lifters/wideningTokens0.ml diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index f82bd37e33..28e365bd97 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -690,7 +690,7 @@ struct Priv.lock ask ctx.global st m ) st addr | Events.Unlock addr when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) - WideningTokens.with_local_side_tokens (fun () -> + WideningTokenLifter.with_local_side_tokens (fun () -> CommonPriv.lift_unlock ask (fun st m -> Priv.unlock ask ctx.global ctx.sideg st m ) st addr @@ -737,7 +737,7 @@ struct (* TODO: parallel write_global? *) let st = - WideningTokens.with_side_tokens (WideningTokens.TS.of_list tokens) (fun () -> + WideningTokenLifter.with_side_tokens (WideningTokenLifter.TS.of_list tokens) (fun () -> VH.fold (fun v v_in st -> (* TODO: is this sideg fine? *) write_global ask ctx.global ctx.sideg st v v_in @@ -771,7 +771,7 @@ struct let new_value = RD.join old_value st in PCU.RH.replace results ctx.node new_value; end; - WideningTokens.with_local_side_tokens (fun () -> + WideningTokenLifter.with_local_side_tokens (fun () -> Priv.sync (Analyses.ask_of_ctx ctx) ctx.global ctx.sideg ctx.local (reason :> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return | `Init | `Thread]) ) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a5a9fc150e..fcf720e5eb 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -447,7 +447,7 @@ struct in if M.tracing then M.tracel "sync" "sync multi=%B earlyglobs=%B" multi !earlyglobs; if !earlyglobs || multi then - WideningTokens.with_local_side_tokens (fun () -> + WideningTokenLifter.with_local_side_tokens (fun () -> Priv.sync (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) (priv_sideg ctx.sideg) ctx.local reason ) else @@ -3058,7 +3058,7 @@ struct (* Perform actual [set]-s with final unassumed values. This invokes [Priv.write_global], which was suppressed above. *) let e_d' = - WideningTokens.with_side_tokens (WideningTokens.TS.of_list uuids) (fun () -> + WideningTokenLifter.with_side_tokens (WideningTokenLifter.TS.of_list uuids) (fun () -> CPA.fold (fun x v acc -> let addr: AD.t = AD.of_mval (x, `NoOffset) in set ~ctx ~invariant:false acc addr x.vtype v @@ -3077,7 +3077,7 @@ struct Priv.lock ask (priv_getg ctx.global) st m ) st addr | Events.Unlock addr when ThreadFlag.has_ever_been_multi ask -> (* TODO: is this condition sound? *) - WideningTokens.with_local_side_tokens (fun () -> + WideningTokenLifter.with_local_side_tokens (fun () -> CommonPriv.lift_unlock ask (fun st m -> Priv.unlock ask (priv_getg ctx.global) (priv_sideg ctx.sideg) st m ) st addr diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index 6212b6de90..742e796fbd 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -156,20 +156,20 @@ struct else iter (uncurry spawn_one) @@ group_assoc_eq Basetype.Variables.equal xs - let do_sideg ctx (xs:(V.t * (WideningTokens.TS.t * G.t)) list) = + let do_sideg ctx (xs:(V.t * (WideningTokenLifter.TS.t * G.t)) list) = let side_one v dts = let side_one_ts ts d = (* Do side effects with the tokens that were active at the time. Transfer functions have exited the with_side_token wrappers by now. *) - let old_side_tokens = !WideningTokens.side_tokens in - WideningTokens.side_tokens := ts; + let old_side_tokens = !WideningTokenLifter.side_tokens in + WideningTokenLifter.side_tokens := ts; Fun.protect (fun () -> ctx.sideg v @@ fold_left G.join (G.bot ()) d ) ~finally:(fun () -> - WideningTokens.side_tokens := old_side_tokens + WideningTokenLifter.side_tokens := old_side_tokens ) in - iter (uncurry side_one_ts) @@ group_assoc_eq WideningTokens.TS.equal dts + iter (uncurry side_one_ts) @@ group_assoc_eq WideningTokenLifter.TS.equal dts in iter (uncurry side_one) @@ group_assoc_eq V.equal xs @@ -355,7 +355,7 @@ struct | 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) + | Some sides -> (fun v g -> sides := (v, (!WideningTokenLifter.side_tokens, g)) :: !sides) | None -> (fun v g -> failwith ("Cannot \"sideg\" in " ^ tfname ^ " context.")) in let emit = match emits with diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 6b5b495233..615dbd3266 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -29,7 +29,7 @@ struct type inv = { exp: Cil.exp; - token: WideningTokens.Token.t; + token: WideningToken.t; } let invs: inv NH.t = NH.create 100 @@ -264,7 +264,7 @@ struct if not (GobConfig.get_bool "ana.unassume.precheck" && Queries.ID.to_bool (ctx.ask (EvalInt e)) = Some false) then ( let tokens = x.token :: List.map (fun {token; _} -> token) xs in ctx.emit (Unassume {exp = e; tokens}); - List.iter WideningTokens.add tokens + List.iter WideningTokenLifter.add tokens ) ); ctx.local diff --git a/src/domains/events.ml b/src/domains/events.ml index b3054b8416..cf12900c98 100644 --- a/src/domains/events.ml +++ b/src/domains/events.ml @@ -14,7 +14,7 @@ type t = | Assign of {lval: CilType.Lval.t; exp: CilType.Exp.t} (** Used to simulate old [ctx.assign]. *) (* TODO: unused *) | UpdateExpSplit of exp (** Used by expsplit analysis to evaluate [exp] on post-state. *) | Assert of exp - | Unassume of {exp: CilType.Exp.t; tokens: WideningTokens0.Token.t list} + | Unassume of {exp: CilType.Exp.t; tokens: WideningToken.t list} | Longjmped of {lval: CilType.Lval.t option} (** Should event be emitted after transfer function raises [Deadcode]? *) @@ -45,5 +45,5 @@ let pretty () = function | Assign {lval; exp} -> dprintf "Assign {lval=%a, exp=%a}" CilType.Lval.pretty lval CilType.Exp.pretty exp | UpdateExpSplit exp -> dprintf "UpdateExpSplit %a" d_exp exp | Assert exp -> dprintf "Assert %a" d_exp exp - | Unassume {exp; tokens} -> dprintf "Unassume {exp=%a; tokens=%a}" d_exp exp (d_list ", " WideningTokens0.Token.pretty) tokens + | Unassume {exp; tokens} -> dprintf "Unassume {exp=%a; tokens=%a}" d_exp exp (d_list ", " WideningToken.pretty) tokens | Longjmped {lval} -> dprintf "Longjmped {lval=%a}" (docOpt (CilType.Lval.pretty ())) lval diff --git a/src/framework/control.ml b/src/framework/control.ml index 1d0ebb869b..2566939817 100644 --- a/src/framework/control.ml +++ b/src/framework/control.ml @@ -39,7 +39,7 @@ let spec_module: (module Spec) Lazy.t = lazy ( |> lift (get_bool "ana.opt.hashcons") (module HashconsLifter) (* Widening tokens must be outside of hashcons, because widening token domain ignores token sets for identity, so hashcons doesn't allow adding tokens. Also must be outside of deadcode, because deadcode splits (like mutex lock event) don't pass on tokens. *) - |> lift (get_bool "ana.widen.tokens") (module WideningTokens.Lifter) + |> lift (get_bool "ana.widen.tokens") (module WideningTokenLifter.Lifter) |> lift true (module LongjmpLifter.Lifter) |> lift termination_enabled (module RecursionTermLifter.Lifter) (* Always activate the recursion termination analysis, when the loop termination analysis is activated*) ) diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index 91f9837419..d8fd408151 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -180,7 +180,8 @@ module SpecLifters = SpecLifters module LongjmpLifter = LongjmpLifter module RecursionTermLifter = RecursionTermLifter module ContextGasLifter = ContextGasLifter -module WideningTokens = WideningTokens +module WideningToken = WideningToken +module WideningTokenLifter = WideningTokenLifter module WitnessConstraints = WitnessConstraints diff --git a/src/lifters/wideningToken.ml b/src/lifters/wideningToken.ml new file mode 100644 index 0000000000..d780c4e793 --- /dev/null +++ b/src/lifters/wideningToken.ml @@ -0,0 +1,4 @@ +(** Widening token for {!WideningTokenLifter}. *) + +(* Change to variant type if need other tokens than witness UUIDs. *) +include Printable.Prod (Basetype.RawStrings) (Printable.Option (IntDomain.Integers (IntOps.NIntOps)) (struct let name = "None" end)) diff --git a/src/lifters/wideningTokens.ml b/src/lifters/wideningTokenLifter.ml similarity index 99% rename from src/lifters/wideningTokens.ml rename to src/lifters/wideningTokenLifter.ml index 4d60099d7e..634468a9ca 100644 --- a/src/lifters/wideningTokens.ml +++ b/src/lifters/wideningTokenLifter.ml @@ -6,7 +6,7 @@ @see Mihaila, B., Sepp, A. & Simon, A. Widening as Abstract Domain. *) -include WideningTokens0 +module Token = WideningToken (** Widening token set. *) module TS = SetDomain.ToppedSet (Token) (struct let topname = "Top" end) diff --git a/src/lifters/wideningTokens0.ml b/src/lifters/wideningTokens0.ml deleted file mode 100644 index dcbf77424e..0000000000 --- a/src/lifters/wideningTokens0.ml +++ /dev/null @@ -1,6 +0,0 @@ -(** Widening token. *) -module Token = -struct - (* Change to variant type if need other tokens than witness UUIDs. *) - include Printable.Prod (Basetype.RawStrings) (Printable.Option (IntDomain.Integers (IntOps.NIntOps)) (struct let name = "None" end)) -end From a2817445e67768d30ef86b2ece90b5f00d3ffee5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Oct 2024 10:38:14 +0300 Subject: [PATCH 557/689] Improve widening token output --- src/lifters/wideningToken.ml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/lifters/wideningToken.ml b/src/lifters/wideningToken.ml index d780c4e793..0639521038 100644 --- a/src/lifters/wideningToken.ml +++ b/src/lifters/wideningToken.ml @@ -1,4 +1,16 @@ (** Widening token for {!WideningTokenLifter}. *) +module Uuid = +struct + include Basetype.RawStrings + let name () = "uuid" +end + +module Index = +struct + include Printable.Option (IntDomain.Integers (IntOps.NIntOps)) (struct let name = "None" end) + let name () = "index" +end + (* Change to variant type if need other tokens than witness UUIDs. *) -include Printable.Prod (Basetype.RawStrings) (Printable.Option (IntDomain.Integers (IntOps.NIntOps)) (struct let name = "None" end)) +include Printable.Prod (Uuid) (Index) From a5bedf619a4c8aa42e0e64bc70d919748e23a1a4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Oct 2024 10:56:50 +0300 Subject: [PATCH 558/689] Pin unreleased camlidl and apron for stability (issue #1520) --- goblint.opam | 4 ++++ goblint.opam.locked | 8 ++++++++ goblint.opam.template | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/goblint.opam b/goblint.opam index b1f1ee97d0..44e5ccd2c2 100644 --- a/goblint.opam +++ b/goblint.opam @@ -98,6 +98,10 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] + # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release + [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] + # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release + [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} diff --git a/goblint.opam.locked b/goblint.opam.locked index 97a8385312..5f01f7915a 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -142,6 +142,14 @@ pin-depends: [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] + [ + "camlidl.1.12" + "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" + ] + [ + "apron.v0.9.15" + "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" + ] ] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} description: """\ diff --git a/goblint.opam.template b/goblint.opam.template index a8a46aa108..0a517fbfa0 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -3,6 +3,10 @@ available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] + # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release + [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] + # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release + [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} From 7898bc572ac38e2f58e908acde02aadbb9268fc8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 9 Oct 2024 16:51:20 +0300 Subject: [PATCH 559/689] Remove old unused exceptions --- src/analyses/base.ml | 2 -- src/analyses/symbLocks.ml | 2 -- src/analyses/varEq.ml | 2 -- src/solver/topDown_deprecated.ml | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 1699108394..e429155e4d 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -34,8 +34,6 @@ module MainFunctor (Priv:BasePriv.S) (RVEval:BaseDomain.ExpEvaluator with type t struct include Analyses.DefaultSpec - exception Top - module Dom = BaseDomain.DomFunctor (Priv.D) (RVEval) type t = Dom.t module D = Dom diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 0119f09288..ab116c525d 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -21,8 +21,6 @@ module Spec = struct include Analyses.DefaultSpec - exception Top - module D = SymbLocksDomain.Symbolic include Analyses.ValueContexts(D) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 8ece99d6e8..78013ec21d 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -11,8 +11,6 @@ open Analyses module Spec = struct - exception Top - include Analyses.DefaultSpec module D = diff --git a/src/solver/topDown_deprecated.ml b/src/solver/topDown_deprecated.ml index 16c45fcd16..a46da9e441 100644 --- a/src/solver/topDown_deprecated.ml +++ b/src/solver/topDown_deprecated.ml @@ -4,8 +4,6 @@ open Batteries open ConstrSys open Messages -exception SolverCannotDoGlobals - (** modified SLR3 as top down solver *) module TD3 = From 881532da16ecc8b9b8507f307c4ffdaa07421787 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 10 Oct 2024 12:00:23 +0300 Subject: [PATCH 560/689] Ignore labels inserted by loopunrolling when finding latest var assigns --- src/util/loopUnrolling.ml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index fe9fec6ce8..5739fd70e5 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -154,7 +154,17 @@ let constBefore var loop f = let targetLocation = loopLocation loop in let rec lastAssignmentToVarBeforeLoop (current: (Z.t option)) (statements: stmt list) = match statements with | st::stmts -> ( - let current' = if st.labels <> [] then (Logs.debug "has Label"; (None)) else current in + let current' = + (* If there exists labels that are not the ones inserted by loop unrolling, forget the found assigned constant value *) + if List.exists (function + | Label (s,_,_) -> not (String.starts_with ~prefix:"loop_continue" s || String.starts_with ~prefix:"loop_end" s) + | _ -> true) st.labels + then + (Logs.debug "has Label"; (None)) + else + current + in + (* let current' = current in *) match st.skind with | Instr list -> ( match lastAssignToVar var list with From 13bcf346fb15758de54947e13bfdd747e430d289 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 10 Oct 2024 12:02:13 +0300 Subject: [PATCH 561/689] Remove commented out code --- src/util/loopUnrolling.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 5739fd70e5..39e17d14d7 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -164,7 +164,6 @@ let constBefore var loop f = else current in - (* let current' = current in *) match st.skind with | Instr list -> ( match lastAssignToVar var list with From 3ed322d9c74e5e9f543828fa8af3121b20650df2 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 10 Oct 2024 12:46:27 +0300 Subject: [PATCH 562/689] Restore that empty loops are not unrolled but do it more efficiently --- src/util/loopUnrolling.ml | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 8c812d598b..dd34085d43 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -119,6 +119,20 @@ class findAssignmentConstDiff((diff: Z.t option ref), var) = object | _ -> SkipChildren end +class findStmtContainsInstructions = object + inherit nopCilVisitor + method! vinst = function + | Set _ + | Call _ -> raise Found + | _ -> DoChildren +end + +let containsInstructions stmt = + try + ignore @@ visitCilStmt (new findStmtContainsInstructions) stmt; false + with Found -> + true + let isCompare = function | Lt | Gt | Le | Ge | Ne -> true (*an loop that test for equality can not be of the type we look for*) | _ -> false @@ -315,15 +329,18 @@ let max_default_unrolls_per_spec (spec: Svcomp.Specification.t) = let loop_unrolling_factor loopStatement func totalLoops = let configFactor = get_int "exp.unrolling-factor" in - if AutoTune0.isActivated "loopUnrollHeuristic" then - match fixedLoopSize loopStatement func with - | Some i when i <= 20 -> Logs.debug "fixed loop size %d" i; i - | _ -> - match Svcomp.Specification.of_option () with - | [] -> 4 - | specs -> BatList.max @@ List.map max_default_unrolls_per_spec specs - else - configFactor + if containsInstructions loopStatement then + if AutoTune0.isActivated "loopUnrollHeuristic" then + match fixedLoopSize loopStatement func with + | Some i when i <= 20 -> Logs.debug "fixed loop size %d" i; i + | _ -> + match Svcomp.Specification.of_option () with + | [] -> 4 + | specs -> BatList.max @@ List.map max_default_unrolls_per_spec specs + else + configFactor + else (* Don't unroll empty (= while(1){}) loops*) + 0 (*actual loop unrolling*) From eb1fdedaff59992c966b8f5dfa2044891da1a220 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 10 Oct 2024 13:11:04 +0300 Subject: [PATCH 563/689] Cram tests: do not unroll empty loops even if unrolling factor is manually set --- tests/regression/55-loop-unrolling/08-bad.t | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/regression/55-loop-unrolling/08-bad.t b/tests/regression/55-loop-unrolling/08-bad.t index f49ad67b5b..a8d8d62522 100644 --- a/tests/regression/55-loop-unrolling/08-bad.t +++ b/tests/regression/55-loop-unrolling/08-bad.t @@ -1,6 +1,4 @@ $ goblint --set lib.activated '[]' --set exp.unrolling-factor 1 --enable justcil --set dbg.justcil-printer clean 08-bad.c - [Info] unrolling loop at 08-bad.c:9:7-9:23 with factor 1 - [Info] unrolling loop at 08-bad.c:15:8-15:24 with factor 1 int main(void) { int m ; @@ -8,11 +6,6 @@ { { goto switch_default; - { - if (! 0) { - goto loop_end; - } - loop_continue_0: /* CIL Label */ ; switch_default: /* CIL Label */ { while (1) { @@ -23,16 +16,9 @@ } while_break: /* CIL Label */ ; } - loop_end: /* CIL Label */ ; - } switch_break: /* CIL Label */ ; } goto lab; - { - if (! 0) { - goto loop_end___0; - } - loop_continue_0___0: /* CIL Label */ ; lab: { while (1) { @@ -43,8 +29,6 @@ } while_break___0: /* CIL Label */ ; } - loop_end___0: /* CIL Label */ ; - } return (0); } } From 8214807e0d4366fece13eff43c16c4c78ad84aab Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 11 Oct 2024 10:10:58 +0300 Subject: [PATCH 564/689] Replace most physical equality on immutable types It's implementation-defined behavior that differs between bytecode and native OCaml compilers. --- src/analyses/uninit.ml | 2 +- src/common/util/cilfacade.ml | 8 ++++---- src/domain/boolDomain.ml | 4 ++-- src/domain/lattice.ml | 10 +++++----- src/incremental/compareAST.ml | 2 +- src/incremental/compareCFG.ml | 2 +- src/incremental/compareCIL.ml | 2 +- src/util/loopUnrolling.ml | 4 ++-- src/witness/myARG.ml | 1 + 9 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/analyses/uninit.ml b/src/analyses/uninit.ml index a385d0a1cd..8c217cda4e 100644 --- a/src/analyses/uninit.ml +++ b/src/analyses/uninit.ml @@ -135,7 +135,7 @@ struct in let utar, uoth = unrollType target, unrollType other in match ofs, utar, uoth with - | `NoOffset, _ , _ when utar == uoth -> [v, rev cx] + | `NoOffset, _ , _ when CilType.Typ.equal utar uoth -> [v, rev cx] | `NoOffset, _ , TComp (c2,_) when not c2.cstruct -> (* unroll other (union) *) List.concat (List.rev_map (fun oth_f -> get_pfx v (`Field (oth_f, cx)) ofs utar oth_f.ftype) c2.cfields) diff --git a/src/common/util/cilfacade.ml b/src/common/util/cilfacade.ml index 344d29d246..6e86701858 100644 --- a/src/common/util/cilfacade.ml +++ b/src/common/util/cilfacade.ml @@ -474,8 +474,8 @@ let rec pretty_typsig_like_typ (nameOpt: Pretty.doc option) () ts = (* ignore the const attribute for arrays *) let a' = dropAttributes [ "pconst" ] a in let name' = - if a' == [] then name else - if nameOpt == None then printAttributes a' else + if a' = [] then name else + if nameOpt = None then printAttributes a' else text "(" ++ printAttributes a' ++ name ++ text ")" in pretty_typsig_like_typ @@ -488,8 +488,8 @@ let rec pretty_typsig_like_typ (nameOpt: Pretty.doc option) () ts = | TSFun (restyp, args, isvararg, a) -> let name' = - if a == [] then name else - if nameOpt == None then printAttributes a else + if a = [] then name else + if nameOpt = None then printAttributes a else text "(" ++ printAttributes a ++ name ++ text ")" in pretty_typsig_like_typ diff --git a/src/domain/boolDomain.ml b/src/domain/boolDomain.ml index 18399365a5..9298460c6a 100644 --- a/src/domain/boolDomain.ml +++ b/src/domain/boolDomain.ml @@ -45,7 +45,7 @@ struct let is_bot x = x = false let top () = true let is_top x = x = true - let leq x y = x == y || y + let leq x y = x = y || y let join = (||) let widen = (||) let meet = (&&) @@ -67,7 +67,7 @@ struct let is_bot x = x = true let top () = false let is_top x = x = false - let leq x y = x == y || x + let leq x y = x = y || x let join = (&&) let widen = (&&) let meet = (||) diff --git a/src/domain/lattice.ml b/src/domain/lattice.ml index f29cb8217d..37a4a2fef5 100644 --- a/src/domain/lattice.ml +++ b/src/domain/lattice.ml @@ -153,11 +153,11 @@ struct include Printable.HConsed (Base) let lift_f2 f x y = f (unlift x) (unlift y) - let narrow x y = if Arg.assume_idempotent && 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 Arg.assume_idempotent && 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 narrow x y = if Arg.assume_idempotent && 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 Arg.assume_idempotent && 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 let is_bot = lift_f Base.is_bot let top () = lift (Base.top ()) diff --git a/src/incremental/compareAST.ml b/src/incremental/compareAST.ml index 5ac7a90706..59adfe00be 100644 --- a/src/incremental/compareAST.ml +++ b/src/incremental/compareAST.ml @@ -91,7 +91,7 @@ and eq_exp (a: exp) (b: exp) ~(rename_mapping: rename_mapping) ~(acc: (typ * typ | AlignOf typ1, AlignOf typ2 -> eq_typ_acc typ1 typ2 ~rename_mapping ~acc | AlignOfE exp1, AlignOfE exp2 -> eq_exp exp1 exp2 ~rename_mapping ~acc | UnOp (op1, exp1, typ1), UnOp (op2, exp2, typ2) -> - ((op1 == op2), rename_mapping) &&>> eq_exp exp1 exp2 ~acc &&>> eq_typ_acc typ1 typ2 ~acc + (CilType.Unop.equal op1 op2, rename_mapping) &&>> eq_exp exp1 exp2 ~acc &&>> eq_typ_acc typ1 typ2 ~acc | BinOp (op1, left1, right1, typ1), BinOp (op2, left2, right2, typ2) -> (op1 = op2, rename_mapping) &&>> eq_exp left1 left2 ~acc &&>> eq_exp right1 right2 ~acc &&>> eq_typ_acc typ1 typ2 ~acc | CastE (typ1, exp1), CastE (typ2, exp2) -> eq_typ_acc typ1 typ2 ~rename_mapping ~acc &&>> eq_exp exp1 exp2 ~acc | AddrOf lv1, AddrOf lv2 -> eq_lval lv1 lv2 ~rename_mapping ~acc diff --git a/src/incremental/compareCFG.ml b/src/incremental/compareCFG.ml index 84b120b8e3..6c314ef7c9 100644 --- a/src/incremental/compareCFG.ml +++ b/src/incremental/compareCFG.ml @@ -18,7 +18,7 @@ let (&&<>) (prev_result: bool * rename_mapping) f : bool * rename_mapping = let eq_node (x, fun1) (y, fun2) ~rename_mapping = let isPseudoReturn f sid = let pid = Cilfacade.get_pseudo_return_id f in - sid == pid in + sid = pid in match x,y with | Statement s1, Statement s2 -> let p1 = isPseudoReturn fun1 s1.sid in diff --git a/src/incremental/compareCIL.ml b/src/incremental/compareCIL.ml index ea22e02a56..837bd65589 100644 --- a/src/incremental/compareCIL.ml +++ b/src/incremental/compareCIL.ml @@ -19,7 +19,7 @@ let name_of_global_col gc = match gc.def with | None -> raise (Failure "empty global record") let compare_global_col gc1 gc2 = compare (name_of_global_col gc1) (name_of_global_col gc2) -let equal_name_global_col gc1 gc2 = compare_global_col gc1 gc2 == 0 +let equal_name_global_col gc1 gc2 = compare_global_col gc1 gc2 = 0 let get_varinfo gc = match gc.decls, gc.def with | _, Some (Var v) -> v diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 905cc39e6a..26aaaa79e1 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -68,7 +68,7 @@ class isPointedAtVisitor(var) = object inherit nopCilVisitor method! vexpr = function - | AddrOf (Var info, NoOffset) when info.vid == var.vid -> raise Found + | AddrOf (Var info, NoOffset) when CilType.Varinfo.equal info var -> raise Found | _ -> DoChildren end @@ -76,7 +76,7 @@ class hasAssignmentVisitor(var) = object inherit nopCilVisitor method! vinst = function - | Set ((Var info, NoOffset),_,_,_) when info.vid == var.vid -> raise Found + | Set ((Var info, NoOffset),_,_,_) when CilType.Varinfo.equal info var -> raise Found | _ -> SkipChildren end diff --git a/src/witness/myARG.ml b/src/witness/myARG.ml index a4ab524a0e..6273ecdbd5 100644 --- a/src/witness/myARG.ml +++ b/src/witness/myARG.ml @@ -283,6 +283,7 @@ let partition_if_next if_next_n = module UnCilLogicIntra (Arg: SIntraOpt): SIntraOpt = struct open Cil + (* TODO: questionable (=) and (==) use here *) let is_equiv_stmtkind sk1 sk2 = match sk1, sk2 with | Instr is1, Instr is2 -> GobList.equal (=) is1 is2 From 8f5a891bedf6d029aedf00c02907f16b580756c0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 11 Oct 2024 12:11:01 +0300 Subject: [PATCH 565/689] Add parentheses to BoolDomain.leq-s to make precedence explicit It was already correct, but not obvious without looking up OCaml operator precedence. --- src/domain/boolDomain.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domain/boolDomain.ml b/src/domain/boolDomain.ml index 9298460c6a..77fcf7e108 100644 --- a/src/domain/boolDomain.ml +++ b/src/domain/boolDomain.ml @@ -45,7 +45,7 @@ struct let is_bot x = x = false let top () = true let is_top x = x = true - let leq x y = x = y || y + let leq x y = (x = y) || y let join = (||) let widen = (||) let meet = (&&) @@ -67,7 +67,7 @@ struct let is_bot x = x = true let top () = false let is_top x = x = false - let leq x y = x = y || x + let leq x y = (x = y) || x let join = (&&) let widen = (&&) let meet = (||) From 412a7ab0aa571af5b6bf0e3e3e4b2e729f0a1084 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 11 Oct 2024 12:17:23 +0300 Subject: [PATCH 566/689] Use ubuntu 22.04 in GitHub Actions To avoid https://github.com/ocaml/setup-ocaml/issues/872. --- .github/workflows/coverage.yml | 4 ++-- .github/workflows/docs.yml | 2 +- .github/workflows/indentation.yml | 2 +- .github/workflows/locked.yml | 10 +++++----- .github/workflows/unlocked.yml | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7f6d5a1cfb..fd2c55b84e 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used @@ -40,7 +40,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Install graph-easy # TODO: remove if depext --with-test works - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-22.04' }} run: sudo apt install -y libgraph-easy-perl - name: Install dependencies diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c5b414a741..0ada04e369 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used diff --git a/.github/workflows/indentation.yml b/.github/workflows/indentation.yml index 96ef5ee56a..1c788e7554 100644 --- a/.github/workflows/indentation.yml +++ b/.github/workflows/indentation.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 ocaml-compiler: - 4.14.x diff --git a/.github/workflows/locked.yml b/.github/workflows/locked.yml index 4f892ea419..16655bfdc7 100644 --- a/.github/workflows/locked.yml +++ b/.github/workflows/locked.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 - macos-13 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file @@ -42,7 +42,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Install graph-easy # TODO: remove if depext --with-test works - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-22.04' }} run: sudo apt install -y libgraph-easy-perl - name: Install dependencies @@ -70,7 +70,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used @@ -91,7 +91,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Install graph-easy # TODO: remove if depext --with-test works - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-22.04' }} run: sudo apt install -y libgraph-easy-perl - name: Install spin @@ -112,7 +112,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file # don't add any other because they won't be used diff --git a/.github/workflows/unlocked.yml b/.github/workflows/unlocked.yml index 0c4433d0af..f3fe6cc558 100644 --- a/.github/workflows/unlocked.yml +++ b/.github/workflows/unlocked.yml @@ -15,7 +15,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 - macos-13 ocaml-compiler: - 5.2.x @@ -30,7 +30,7 @@ jobs: - false include: - - os: ubuntu-latest + - os: ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 ocaml-compiler: 4.14.x z3: true - os: macos-latest @@ -52,7 +52,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Install graph-easy # TODO: remove if depext --with-test works - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-22.04' }} run: sudo apt install -y libgraph-easy-perl - name: Install dependencies @@ -90,7 +90,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 - macos-13 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file, downgrade deps step @@ -112,7 +112,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Install graph-easy # TODO: remove if depext --with-test works - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-22.04' }} run: sudo apt install -y libgraph-easy-perl - name: Install dependencies @@ -187,7 +187,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest + - ubuntu-22.04 # https://github.com/ocaml/setup-ocaml/issues/872 - macos-13 ocaml-compiler: - ocaml-variants.4.14.2+options,ocaml-option-flambda # matches opam lock file @@ -204,7 +204,7 @@ jobs: ocaml-compiler: ${{ matrix.ocaml-compiler }} - name: Install graph-easy # TODO: remove if depext --with-test works - if: ${{ matrix.os == 'ubuntu-latest' }} + if: ${{ matrix.os == 'ubuntu-22.04' }} run: sudo apt install -y libgraph-easy-perl - name: Install Goblint with test From 82729353e53b05422a883b2a724e35fc87948379 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 14 Oct 2024 12:49:18 +0200 Subject: [PATCH 567/689] Add example where per function gas with maximum leads to non-termination --- .../80-context_gas/25-per-fun-nonterm.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/regression/80-context_gas/25-per-fun-nonterm.c diff --git a/tests/regression/80-context_gas/25-per-fun-nonterm.c b/tests/regression/80-context_gas/25-per-fun-nonterm.c new file mode 100644 index 0000000000..4c3871688f --- /dev/null +++ b/tests/regression/80-context_gas/25-per-fun-nonterm.c @@ -0,0 +1,29 @@ +//PARAM: --enable ana.int.interval_set --set ana.context.gas_value 3 --set ana.context.gas_scope function +// NOTIMEOUT +void h(int n) { + int x; + + if(x) { + return; + } + + g(n+1); + h(n+1); +} + +void g(int n) { + int x; + + if(x) { + return; + } + + g(n+1); + h(n+1); +} + +int main() +{ + g(0); + h(0); +} From ce1866b6e61472957c13aac891b523712c2e46ae Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 14 Oct 2024 13:06:13 +0200 Subject: [PATCH 568/689] Fix per fundec gas --- src/lifters/contextGasLifter.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lifters/contextGasLifter.ml b/src/lifters/contextGasLifter.ml index 98974d81a1..75bd9f7641 100644 --- a/src/lifters/contextGasLifter.ml +++ b/src/lifters/contextGasLifter.ml @@ -121,12 +121,15 @@ let get_gas_lifter () = (module ContextGasLifter(GlobalGas):Spec2Spec) else let module PerFunctionGas:Gas = struct - module G = GasChain - module M = MapDomain.MapTop_LiftBot(CilType.Fundec)(G) + (* The order is reversed here to ensure that the minimum is used *) + (* 5 join 4 = 4 *) + module G = Lattice.Reverse(GasChain) + (* Missing bindings are bot, i.e., have maximal gas for this function *) + module M = MapDomain.MapBot_LiftTop(CilType.Fundec)(G) let startgas () = M.empty () let is_exhausted f v = GobOption.exists (fun g -> g <= 0) (M.find_opt f v) (* v <= 0 *) let callee_gas f v = - let c = Option.default (G.top ()) (M.find_opt f v) in + let c = Option.default (G.bot ()) (M.find_opt f v) in M.add f (max 0 c-1) v let thread_gas f v = match Cilfacade.find_varinfo_fundec f with From f54ce558d917fc59beb83f8db3a4d428d1be83e6 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 15 Oct 2024 13:15:07 +0300 Subject: [PATCH 569/689] Handle casts in loop statements for unrolling --- src/util/loopUnrolling.ml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 9ad6eb87d5..6639df61cb 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -244,16 +244,23 @@ let findBreakComparison loopStatement = None let getLoopVar loopStatement func = function - | BinOp (op, (Const (CInt (goal, _, _) )), Lval ((Var varinfo), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob -> + | BinOp (op, Const (CInt (goal, _, _)), Lval (Var varinfo, NoOffset), TInt _) + | BinOp (op, Const (CInt (goal, _, _)), CastE (TInt _, Lval (Var varinfo, NoOffset)), TInt _) + | BinOp (op, CastE (TInt _, Const (CInt (goal, _, _))), Lval (Var varinfo, NoOffset), TInt _) + | BinOp (op, CastE (TInt _, Const (CInt (goal, _, _))), CastE (TInt _, Lval (Var varinfo, NoOffset)), TInt _) when isCompare op && not varinfo.vglob -> (* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *) let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in Some (flip op, varinfo, goal) - | BinOp (op, Lval ((Var varinfo), NoOffset), (Const (CInt (goal, _, _) )), (TInt _)) when isCompare op && not varinfo.vglob -> + | BinOp (op, Lval (Var varinfo, NoOffset), Const (CInt (goal, _, _)), TInt _) + | BinOp (op, Lval (Var varinfo, NoOffset), CastE (TInt _, Const (CInt (goal, _, _))), TInt _) + | BinOp (op, CastE (TInt _, Lval (Var varinfo, NoOffset)), Const (CInt (goal, _, _)), TInt _) + | BinOp (op, CastE (TInt _, Lval (Var varinfo, NoOffset)), CastE (TInt _, Const (CInt (goal, _, _))), TInt _) when isCompare op && not varinfo.vglob -> Some (op, varinfo, goal) (* When loop condition has a comparison between variables, we assume that the left one is the counter and right one is the bound. TODO: can we do something more meaningful instead of this assumption? *) - | BinOp (op, Lval ((Var varinfo), NoOffset), Lval ((Var varinfo2), NoOffset), (TInt _)) - | BinOp (op, CastE ((TInt _), (Lval ((Var varinfo), NoOffset))), Lval ((Var varinfo2), NoOffset), (TInt _)) when isCompare op && not varinfo.vglob && not varinfo2.vglob -> + | BinOp (op, Lval (Var varinfo, NoOffset), Lval (Var varinfo2, NoOffset), TInt _) + | BinOp (op, Lval (Var varinfo, NoOffset), CastE (TInt _, Lval (Var varinfo2, NoOffset)), TInt _) + | BinOp (op, CastE (TInt _, Lval (Var varinfo, NoOffset)), Lval (Var varinfo2, NoOffset), TInt _) when isCompare op && not varinfo.vglob && not varinfo2.vglob -> begin match constBefore varinfo2 loopStatement func with | Some goal -> Logs.debug "const: %a %a" CilType.Varinfo.pretty varinfo2 GobZ.pretty goal; Some (op, varinfo, goal) | None -> None From 872b1597a3c96747dfce5b316210368b0189737e Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 15 Oct 2024 16:21:34 +0300 Subject: [PATCH 570/689] Refactor: Simplify pattern matching of casts by using Cil.stripCasts --- src/util/loopUnrolling.ml | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/util/loopUnrolling.ml b/src/util/loopUnrolling.ml index 6639df61cb..506337ac1b 100644 --- a/src/util/loopUnrolling.ml +++ b/src/util/loopUnrolling.ml @@ -243,30 +243,27 @@ let findBreakComparison loopStatement = with WrongOrMultiple -> None -let getLoopVar loopStatement func = function - | BinOp (op, Const (CInt (goal, _, _)), Lval (Var varinfo, NoOffset), TInt _) - | BinOp (op, Const (CInt (goal, _, _)), CastE (TInt _, Lval (Var varinfo, NoOffset)), TInt _) - | BinOp (op, CastE (TInt _, Const (CInt (goal, _, _))), Lval (Var varinfo, NoOffset), TInt _) - | BinOp (op, CastE (TInt _, Const (CInt (goal, _, _))), CastE (TInt _, Lval (Var varinfo, NoOffset)), TInt _) when isCompare op && not varinfo.vglob -> +let findLoopVarAndGoal loopStatement func (op, exp1, exp2) = + match Cil.stripCasts exp1, Cil.stripCasts exp2 with + | Const (CInt (goal, _, _)), Lval (Var varinfo, NoOffset) when not varinfo.vglob -> (* TODO: define isCompare and flip in cilfacade and refactor to use instead of the many separately defined similar functions *) let flip = function | Lt -> Gt | Gt -> Lt | Ge -> Le | Le -> Ge | s -> s in Some (flip op, varinfo, goal) - | BinOp (op, Lval (Var varinfo, NoOffset), Const (CInt (goal, _, _)), TInt _) - | BinOp (op, Lval (Var varinfo, NoOffset), CastE (TInt _, Const (CInt (goal, _, _))), TInt _) - | BinOp (op, CastE (TInt _, Lval (Var varinfo, NoOffset)), Const (CInt (goal, _, _)), TInt _) - | BinOp (op, CastE (TInt _, Lval (Var varinfo, NoOffset)), CastE (TInt _, Const (CInt (goal, _, _))), TInt _) when isCompare op && not varinfo.vglob -> + | Lval (Var varinfo, NoOffset), Const (CInt (goal, _, _)) when not varinfo.vglob -> Some (op, varinfo, goal) - (* When loop condition has a comparison between variables, we assume that the left one is the counter and right one is the bound. - TODO: can we do something more meaningful instead of this assumption? *) - | BinOp (op, Lval (Var varinfo, NoOffset), Lval (Var varinfo2, NoOffset), TInt _) - | BinOp (op, Lval (Var varinfo, NoOffset), CastE (TInt _, Lval (Var varinfo2, NoOffset)), TInt _) - | BinOp (op, CastE (TInt _, Lval (Var varinfo, NoOffset)), Lval (Var varinfo2, NoOffset), TInt _) when isCompare op && not varinfo.vglob && not varinfo2.vglob -> + | Lval (Var varinfo, NoOffset), Lval (Var varinfo2, NoOffset) when not varinfo.vglob && not varinfo2.vglob -> + (* When loop condition has a comparison between variables, we assume that the left one is the counter and right one is the bound. + TODO: can we do something more meaningful instead of this assumption? *) begin match constBefore varinfo2 loopStatement func with | Some goal -> Logs.debug "const: %a %a" CilType.Varinfo.pretty varinfo2 GobZ.pretty goal; Some (op, varinfo, goal) | None -> None end; | _ -> None +let getLoopVar loopStatement func = function + | BinOp (op, exp1, exp2, TInt _) when isCompare op -> findLoopVarAndGoal loopStatement func (op, exp1, exp2) + | _ -> None + let getsPointedAt var func = try let visitor = new isPointedAtVisitor (var) in From 2f5b50fa9081abda073a33b393ef33c282c1ebc4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 16 Oct 2024 16:51:40 +0300 Subject: [PATCH 571/689] Revert "Add hacky imaxabs sqrt refine support" This reverts commit f9765da81d64a99f77c385835c6c0a5c3db419da. --- src/analyses/baseInvariant.ml | 3 +-- tests/regression/39-signed-overflows/12-imaxabs-sqrt.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/baseInvariant.ml b/src/analyses/baseInvariant.ml index d5b65a95f4..51a27e19f8 100644 --- a/src/analyses/baseInvariant.ml +++ b/src/analyses/baseInvariant.ml @@ -785,8 +785,7 @@ struct | TFloat (fk, _), FLongDouble | TFloat (FDouble as fk, _), FDouble | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st - | TInt (ik, _), _ -> inv_exp (Int (FD.to_int ik c)) e st (* TODO: is this cast refinement correct? *) - | t, fk -> fallback (fun () -> Pretty.dprintf "CastE: incompatible types %a and %a" CilType.Typ.pretty t CilType.Fkind.pretty fk) st) + | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) | CastE ((TInt (ik, _)) as t, e), Int c | CastE ((TEnum ({ekind = ik; _ }, _)) as t, e), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) (match eval e st with diff --git a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c index 46512aed21..b121645b27 100644 --- a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c +++ b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c @@ -6,7 +6,7 @@ int main() { int64_t data; if (data > (-0x7fffffffffffffff - 1) && imaxabs((intmax_t)data) <= sqrtl(0x7fffffffffffffffLL)) { - int64_t result = data * data; // NOWARN + int64_t result = data * data; // TODO NOWARN } return 8; } From f7a5afa966d6dc4b62748fdb1738f2b2aef2f844 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 16 Oct 2024 17:39:07 +0300 Subject: [PATCH 572/689] Add 39-signed-overflows/13-imaxabs-macos test --- .../39-signed-overflows/13-imaxabs-macos.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/regression/39-signed-overflows/13-imaxabs-macos.c diff --git a/tests/regression/39-signed-overflows/13-imaxabs-macos.c b/tests/regression/39-signed-overflows/13-imaxabs-macos.c new file mode 100644 index 0000000000..745d5b74c4 --- /dev/null +++ b/tests/regression/39-signed-overflows/13-imaxabs-macos.c @@ -0,0 +1,25 @@ +//PARAM: --enable ana.int.interval --set ana.activated[+] tmpSpecial +// 39-signed-overflows/11-imaxabs, but with long long as int64_t instead (https://github.com/goblint/analyzer/pull/1519#issuecomment-2417032186). +#include +#include +#include +int main() { + long long data; + if (data > (-0x7fffffffffffffff - 1)) + { + if (imaxabs(data) < 100) + { + __goblint_check(data < 100); + __goblint_check(-100 < data); + long long result = data * data; // NOWARN + } + + if(imaxabs(data) <= 100) + { + __goblint_check(data <= 100); + __goblint_check(-100 <= data); + long long result = data * data; // NOWARN + } + } + return 8; +} From 62834684764e5e1bc88705f19c54fa22a0d35d64 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 16 Oct 2024 17:55:20 +0300 Subject: [PATCH 573/689] Unroll cast type in BaseInvariant --- src/analyses/baseInvariant.ml | 58 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/analyses/baseInvariant.ml b/src/analyses/baseInvariant.ml index 51a27e19f8..52f0888d3f 100644 --- a/src/analyses/baseInvariant.ml +++ b/src/analyses/baseInvariant.ml @@ -777,33 +777,37 @@ struct | _ -> assert false end | Const _ , _ -> st (* nothing to do *) - | CastE ((TFloat (_, _)), e), Float c -> - (match unrollType (Cilfacade.typeOf e), FD.get_fkind c with - | TFloat (FLongDouble as fk, _), FFloat - | TFloat (FDouble as fk, _), FFloat - | TFloat (FLongDouble as fk, _), FDouble - | TFloat (fk, _), FLongDouble - | TFloat (FDouble as fk, _), FDouble - | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st - | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) - | CastE ((TInt (ik, _)) as t, e), Int c - | CastE ((TEnum ({ekind = ik; _ }, _)) as t, e), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) - (match eval e st with - | Int i -> - (match unrollType (Cilfacade.typeOf e) with - | (TInt(ik_e, _) as t') - | (TEnum ({ekind = ik_e; _ }, _) as t') -> - if VD.is_dynamically_safe_cast t t' (Int i) then - (* let c' = ID.cast_to ik_e c in *) - (* Suppressing overflow warnings as this is not a computation that comes from the program *) - let res_range = (ID.cast_to ~suppress_ovwarn:true ik (ID.top_of ik_e)) in - let c' = ID.cast_to ik_e (ID.meet c res_range) in (* TODO: cast without overflow, is this right for normal invariant? *) - if M.tracing then M.tracel "inv" "cast: %a from %a to %a: i = %a; cast c = %a to %a = %a" d_exp e d_ikind ik_e d_ikind ik ID.pretty i ID.pretty c d_ikind ik_e ID.pretty c'; - inv_exp (Int c') e st - else - fallback (fun () -> Pretty.dprintf "CastE: %a evaluates to %a which is bigger than the type it is cast to which is %a" d_plainexp e ID.pretty i CilType.Typ.pretty t) st - | x -> fallback (fun () -> Pretty.dprintf "CastE: e did evaluate to Int, but the type did not match %a" CilType.Typ.pretty t) st) - | v -> fallback (fun () -> Pretty.dprintf "CastE: e did not evaluate to Int, but %a" VD.pretty v) st) + | CastE (t, e), c_typed -> + begin match Cil.unrollType t, c_typed with + | TFloat (_, _), Float c -> + (match unrollType (Cilfacade.typeOf e), FD.get_fkind c with + | TFloat (FLongDouble as fk, _), FFloat + | TFloat (FDouble as fk, _), FFloat + | TFloat (FLongDouble as fk, _), FDouble + | TFloat (fk, _), FLongDouble + | TFloat (FDouble as fk, _), FDouble + | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st + | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) + | (TInt (ik, _) as t), Int c + | (TEnum ({ekind = ik; _ }, _) as t), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) + (match eval e st with + | Int i -> + (match unrollType (Cilfacade.typeOf e) with + | (TInt(ik_e, _) as t') + | (TEnum ({ekind = ik_e; _ }, _) as t') -> + if VD.is_dynamically_safe_cast t t' (Int i) then + (* let c' = ID.cast_to ik_e c in *) + (* Suppressing overflow warnings as this is not a computation that comes from the program *) + let res_range = (ID.cast_to ~suppress_ovwarn:true ik (ID.top_of ik_e)) in + let c' = ID.cast_to ik_e (ID.meet c res_range) in (* TODO: cast without overflow, is this right for normal invariant? *) + if M.tracing then M.tracel "inv" "cast: %a from %a to %a: i = %a; cast c = %a to %a = %a" d_exp e d_ikind ik_e d_ikind ik ID.pretty i ID.pretty c d_ikind ik_e ID.pretty c'; + inv_exp (Int c') e st + else + fallback (fun () -> Pretty.dprintf "CastE: %a evaluates to %a which is bigger than the type it is cast to which is %a" d_plainexp e ID.pretty i CilType.Typ.pretty t) st + | x -> fallback (fun () -> Pretty.dprintf "CastE: e did evaluate to Int, but the type did not match %a" CilType.Typ.pretty t) st) + | v -> fallback (fun () -> Pretty.dprintf "CastE: e did not evaluate to Int, but %a" VD.pretty v) st) + | _, _ -> fallback (fun () -> Pretty.dprintf "CastE: %a not implemented" d_plainexp (CastE (t, e))) st + end | e, _ -> fallback (fun () -> Pretty.dprintf "%a not implemented" d_plainexp e) st in if eval_bool exp st = Some (not tv) then contra st (* we already know that the branch is dead *) From 732b69a8ea5a3002fa68491ea0b24c1dede49761 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 17 Oct 2024 15:17:35 +0300 Subject: [PATCH 574/689] Lock zarith 1.14 for better hash (issue #1594) --- goblint.opam.locked | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goblint.opam.locked b/goblint.opam.locked index 5f01f7915a..9fbee1e02b 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -110,7 +110,7 @@ depends: [ "uutf" {= "1.0.3" & with-doc} "yaml" {= "3.2.0"} "yojson" {= "2.2.1"} - "zarith" {= "1.13"} + "zarith" {= "1.14"} ] build: [ ["dune" "subst"] {dev} From e12d6df901069f353c7a2a9ff08dfd6130a6507b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 17 Oct 2024 15:26:28 +0300 Subject: [PATCH 575/689] Copy svcomp confs to svcomp25 --- conf/svcomp25-validate.json | 122 ++++++++++++++++++++++++++++++++++++ conf/svcomp25.json | 117 ++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 conf/svcomp25-validate.json create mode 100644 conf/svcomp25.json diff --git a/conf/svcomp25-validate.json b/conf/svcomp25-validate.json new file mode 100644 index 0000000000..f0e99057d1 --- /dev/null +++ b/conf/svcomp25-validate.json @@ -0,0 +1,122 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless", + "unassume" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "termination", + "tmpSpecialAnalysis" + ] + }, + "widen": { + "tokens": true + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": false + }, + "yaml": { + "enabled": false, + "strict": true, + "format-version": "2.0", + "entry-types": [ + "location_invariant", + "loop_invariant", + "invariant_set", + "violation_sequence" + ], + "invariant-types": [ + "location_invariant", + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": true, + "other": true + } + }, + "pre": { + "enabled": false + } +} diff --git a/conf/svcomp25.json b/conf/svcomp25.json new file mode 100644 index 0000000000..aa3f625da9 --- /dev/null +++ b/conf/svcomp25.json @@ -0,0 +1,117 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true, + "evaluate_math_functions": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "abortUnless" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": true, + "id": "enumerate", + "unknown": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "invariant_set" + ], + "invariant-types": [ + "loop_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": false, + "other": false, + "accessed": false, + "exact": true + } + }, + "pre": { + "enabled": false + } +} From 6a973802a229367f7112637c0b37d5e979560a8d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 17 Oct 2024 15:28:42 +0300 Subject: [PATCH 576/689] Update sv-comp/archive.sh for 2025 --- scripts/sv-comp/archive.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/sv-comp/archive.sh b/scripts/sv-comp/archive.sh index 37fa2758d9..aefac8f769 100755 --- a/scripts/sv-comp/archive.sh +++ b/scripts/sv-comp/archive.sh @@ -4,7 +4,7 @@ make clean -git tag -m "SV-COMP 2024" svcomp24 +git tag -m "SV-COMP 2025" svcomp25 dune build --profile=release src/goblint.exe rm -f goblint @@ -32,8 +32,8 @@ zip goblint/scripts/sv-comp/goblint.zip \ goblint/lib/libboxD.so \ goblint/lib/libpolkaMPQ.so \ goblint/lib/LICENSE.APRON \ - goblint/conf/svcomp24.json \ - goblint/conf/svcomp24-validate.json \ + goblint/conf/svcomp25.json \ + goblint/conf/svcomp25-validate.json \ goblint/lib/libc/stub/include/assert.h \ goblint/lib/goblint/runtime/include/goblint.h \ goblint/lib/libc/stub/src/stdlib.c \ From d3c5d353cec4b9b875c5a3f12bc09647f4c03bcf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 18 Oct 2024 12:20:55 +0300 Subject: [PATCH 577/689] Document SV-COMP bench-defs MR --- docs/developer-guide/releasing.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/developer-guide/releasing.md b/docs/developer-guide/releasing.md index 7530d9ad20..aca0749eb9 100644 --- a/docs/developer-guide/releasing.md +++ b/docs/developer-guide/releasing.md @@ -77,6 +77,8 @@ This includes: git tag name, git tag message and zipped conf file. +5. Open MR with conf file name to the [bench-defs](https://gitlab.com/sosy-lab/sv-comp/bench-defs) repository. + ### For each prerun 1. Update opam pins: From eed1e27067c47b2c86015d6fb1402f23ee7ffa22 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 18 Oct 2024 12:32:44 +0300 Subject: [PATCH 578/689] Improve flat string domain hash --- src/cdomain/value/cdomains/stringDomain.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/stringDomain.ml b/src/cdomain/value/cdomains/stringDomain.ml index 2b968b0321..5ed704ce69 100644 --- a/src/cdomain/value/cdomains/stringDomain.ml +++ b/src/cdomain/value/cdomains/stringDomain.ml @@ -20,9 +20,10 @@ let reset_lazy () = type t = string option [@@deriving eq, ord, hash] +(** [None] means top. *) let hash x = - if get_string_domain () = Disjoint then + if get_string_domain () <> Unit then hash x else 13859 From 2284da8ed5f909c39f204f9b123c3ce3d9149fee Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 18 Oct 2024 12:36:26 +0300 Subject: [PATCH 579/689] Improve StringDomain type safety by matching all domains This is more robust against changes to the possible choices of domain. It would have avoided issue #1594. --- src/cdomain/value/cdomains/stringDomain.ml | 35 +++++++++++----------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/cdomain/value/cdomains/stringDomain.ml b/src/cdomain/value/cdomains/stringDomain.ml index 5ed704ce69..35054590f9 100644 --- a/src/cdomain/value/cdomains/stringDomain.ml +++ b/src/cdomain/value/cdomains/stringDomain.ml @@ -23,10 +23,9 @@ type t = string option [@@deriving eq, ord, hash] (** [None] means top. *) let hash x = - if get_string_domain () <> Unit then - hash x - else - 13859 + match get_string_domain () with + | Disjoint | Flat -> hash x + | Unit -> 13859 let show = function | Some x -> "\"" ^ x ^ "\"" @@ -40,10 +39,9 @@ include Printable.SimpleShow ( ) let of_string x = - if get_string_domain () = Unit then - None - else - Some x + match get_string_domain () with + | Unit -> None + | Disjoint | Flat -> Some x let to_string x = x (* only keep part before first null byte *) @@ -92,10 +90,10 @@ let join x y = | _, None -> None | Some a, Some b when a = b -> Some a | Some a, Some b (* when a <> b *) -> - if get_string_domain () = Disjoint then - raise Lattice.Uncomparable - else - None + match get_string_domain () with + | Disjoint -> raise Lattice.Uncomparable + | Flat -> None + | Unit -> assert false let meet x y = match x, y with @@ -103,13 +101,14 @@ let meet x y = | a, None -> a | Some a, Some b when a = b -> Some a | Some a, Some b (* when a <> b *) -> - if get_string_domain () = Disjoint then - raise Lattice.Uncomparable - else - raise Lattice.BotValue + match get_string_domain () with + | Disjoint -> raise Lattice.Uncomparable + | Flat -> raise Lattice.BotValue + | Unit -> assert false let repr x = - if get_string_domain () = Disjoint then + match get_string_domain () with + | Disjoint -> x (* everything else is kept separate, including strings if not limited *) - else + | Flat | Unit -> None (* all strings together if limited *) From bf0c28fd0ef83f3202b27e9b7a982dfa2b48b0cf Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 23 Oct 2024 16:48:07 +0300 Subject: [PATCH 580/689] Revert "Work around old LibraryFunctions spawning even with sem.unknown_function.spawn disabled" This reverts commit e5799bcb81dd50bea45bc36657fe0b28a703c95d. --- src/analyses/base.ml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index e429155e4d..cea2c8bcee 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2172,11 +2172,7 @@ struct in List.filter_map (create_thread ~multiple (Some (Mem id, NoOffset)) (Some ptc_arg)) start_funvars_with_unknown 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. - But here we consider all non-ThreadCreate functions also unknown, so old-style LibraryFunctions access - definitions using `Write would still spawn because they are not truly unknown functions (missing from LibraryFunctions). - Need this to not have memmove spawn in SV-COMP. *) + | _, _ -> let shallow_args = LibraryDesc.Accesses.find desc.accs { kind = Spawn; deep = false } args in let deep_args = LibraryDesc.Accesses.find desc.accs { kind = Spawn; deep = true } args in let shallow_flist = collect_invalidate ~deep:false ~ctx ctx.local shallow_args in @@ -2185,7 +2181,6 @@ struct let addrs = List.concat_map AD.to_var_may flist in 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 ~multiple:true None None) addrs - | _, _ -> [] let assert_fn ctx e refine = (* make the state meet the assertion in the rest of the code *) From 4d4de22cad91068002242a2942bad0c300da772b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 23 Oct 2024 17:05:36 +0300 Subject: [PATCH 581/689] Add option sem.atexit.ignore --- src/config/options.schema.json | 13 +++++++++++++ src/util/library/libraryFunctions.ml | 2 +- tests/regression/41-stdlib/08-atexit-no-spawn.c | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 447290b44d..5d87eb51f6 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1544,6 +1544,19 @@ } }, "additionalProperties": false + }, + "atexit": { + "title": "sem.atexit", + "type": "object", + "properties": { + "ignore": { + "title": "sem.atexit.ignore", + "description": "Ignore atexit callbacks (unsound).", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 25a90da2d3..31fcf0510e 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -145,7 +145,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("_setjmp", special [__ "env" [w]] @@ fun env -> Setjmp { env }); (* only has one underscore *) ("setjmp", special [__ "env" [w]] @@ fun env -> Setjmp { env }); ("longjmp", special [__ "env" [r]; __ "value" []] @@ fun env value -> Longjmp { env; value }); - ("atexit", unknown [drop "function" [s]]); + ("atexit", unknown [drop "function" [if_ (fun () -> not (get_bool "sem.atexit.ignore")) s]]); ("atoi", unknown [drop "nptr" [r]]); ("atol", unknown [drop "nptr" [r]]); ("atoll", unknown [drop "nptr" [r]]); diff --git a/tests/regression/41-stdlib/08-atexit-no-spawn.c b/tests/regression/41-stdlib/08-atexit-no-spawn.c index 7f25f42183..3bbba82634 100644 --- a/tests/regression/41-stdlib/08-atexit-no-spawn.c +++ b/tests/regression/41-stdlib/08-atexit-no-spawn.c @@ -1,4 +1,4 @@ -// PARAM: --disable sem.unknown_function.spawn +// PARAM: --enable sem.atexit.ignore #include #include From 6b77fb3298d2d6f716510767d3a6411a91382348 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 23 Oct 2024 17:15:14 +0300 Subject: [PATCH 582/689] Generalize AutoTune.hasFunction predicate --- src/autoTune.ml | 10 ++++++---- src/util/autoSoundConfig.ml | 7 ++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 0def6021fa..843c977ae2 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -157,7 +157,7 @@ let hasFunction pred = Goblint_backtrace.wrap_val ~mark:(Cilfacade.FunVarinfo var) @@ fun () -> if LibraryFunctions.is_special var then let desc = LibraryFunctions.find var in - GobOption.exists (fun args -> pred (desc.special args)) (functionArgs var) + GobOption.exists (fun args -> pred desc args) (functionArgs var) else false in @@ -169,7 +169,7 @@ let hasFunction pred = match unrollType var.vtype with | TFun (_, args, _, _) -> let args = BatOption.map_default (List.map (fun (x,_,_) -> MyCFG.unknown_exp)) [] args in - pred (desc.special args) + pred desc args | _ -> false else false @@ -191,7 +191,8 @@ let enableAnalyses anas = let notNeccessaryThreadAnalyses = ["race"; "deadlock"; "maylocks"; "symb_locks"; "thread"; "threadid"; "threadJoins"; "threadreturn"; "mhp"; "region"; "pthreadMutexType"] let reduceThreadAnalyses () = - let isThreadCreate = function + let isThreadCreate (desc: LibraryDesc.t) args = + match desc.special args with | LibraryDesc.ThreadCreate _ -> true | _ -> false in @@ -446,7 +447,8 @@ let wideningOption factors file = } let activateTmpSpecialAnalysis () = - let isMathFun = function + let isMathFun (desc: LibraryDesc.t) args = + match desc.special args with | LibraryDesc.Math _ -> true | _ -> false in diff --git a/src/util/autoSoundConfig.ml b/src/util/autoSoundConfig.ml index 7a30bdf5ce..0bb67e768e 100644 --- a/src/util/autoSoundConfig.ml +++ b/src/util/autoSoundConfig.ml @@ -12,8 +12,8 @@ let enableSpecAnalyses spec analyses = Logs.info "Specification: %s -> enabling soundness analyses \"%s\"" (Svcomp.Specification.to_string [spec]) (String.concat ", " analyses); enableAnalyses analyses -let enableOptions options = - let enableOpt option = +let enableOptions options = + let enableOpt option = Logs.info "Setting \"%s\" to true" option; set_bool option true in @@ -60,7 +60,8 @@ let enableAnalysesForSpecification () = let longjmpAnalyses = ["activeLongjmp"; "activeSetjmp"; "taintPartialContexts"; "modifiedSinceSetjmp"; "poisonVariables"; "expsplit"; "vla"] let activateLongjmpAnalysesWhenRequired () = - let isLongjmp = function + let isLongjmp (desc: LibraryDesc.t) args = + match desc.special args with | LibraryDesc.Longjmp _ -> true | _ -> false in From b00c608f70c115bc442d8c355653655541527d37 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 23 Oct 2024 17:19:48 +0300 Subject: [PATCH 583/689] Consider all spawning functions in autotuner (closes #1181) --- src/autoTune.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 843c977ae2..f59a10ee8a 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -194,7 +194,7 @@ let reduceThreadAnalyses () = let isThreadCreate (desc: LibraryDesc.t) args = match desc.special args with | LibraryDesc.ThreadCreate _ -> true - | _ -> false + | _ -> LibraryDesc.Accesses.find_kind desc.accs Spawn args <> [] in let hasThreadCreate = hasFunction isThreadCreate in if not @@ hasThreadCreate then ( From 3bb17bc06fd9901d6476a5db72f9af0be805e7e5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 24 Oct 2024 17:24:37 +0300 Subject: [PATCH 584/689] Add cram tests for some solvers --- tests/regression/00-sanity/01-assert.t | 130 +++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/tests/regression/00-sanity/01-assert.t b/tests/regression/00-sanity/01-assert.t index 9142f805f9..2f81310ada 100644 --- a/tests/regression/00-sanity/01-assert.t +++ b/tests/regression/00-sanity/01-assert.t @@ -9,3 +9,133 @@ live: 7 dead: 2 total lines: 9 + + +Test ancient solvers: + + $ goblint --enable warn.deterministic --set solver WL 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver effectWConEq 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + +Test topdown solvers: + + $ goblint --enable warn.deterministic --set solver topdown_deprecated 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver topdown 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver topdown_term 01-assert.c + [Error] Fixpoint not reached at L:entry state of main (299) on 01-assert.c:4:1-15:1 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), + mallocWrapper:(wrapper call:Unknown node, unique calls:{}), + base:({ + }, {}, {}, {}), + threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), + threadflag:Singlethreaded, + threadreturn:true, + escape:{}, + mutexEvents:(), + access:(), + mutex:(lockset:{}, multiplicity:{}), + race:(), + mhp:(), + assert:(), + pthreadMutexType:()], map:{})} + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), + mallocWrapper:(wrapper call:Unknown node, unique calls:{}), + base:({ + }, {}, {}, {}), + threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), + threadflag:Singlethreaded, + threadreturn:true, + escape:{}, + mutexEvents:(), + access:(), + mutex:(lockset:{}, multiplicity:{}), + race:(), + mhp:(), + assert:(), + pthreadMutexType:()], map:{})} instead of bot + + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 4..7 (01-assert.c:4-7) + on lines 10..14 (01-assert.c:10-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 0 + dead: 9 + total lines: 9 + [Error][Unsound] Fixpoint not reached + [3] + + $ goblint --enable warn.deterministic --set solver topdown_space_cache_term 01-assert.c + [Error] Cannot find value 'solvers.wp.restore' in + {"files":["01-assert.c"],"outfile":"","justcil":false,"justcfg":false,"verify":true,"mainfun":["main"],"exitfun":[],"otherfun":[],"allglobs":false,"kernel":false,"dump_globs":false,"result":"none","solver":"topdown_space_cache_term","comparesolver":"","allfuns":false,"nonstatic":false,"colors":"auto","g2html":false,"save_run":"","load_run":"","compare_runs":[],"warn_at":"post","gobview":false,"jobs":1,"goblint-dir":".goblint","pre":{"enabled":true,"keep":false,"exist":false,"includes":[],"kernel_includes":[],"custom_includes":[],"kernel-root":"","cppflags":[],"compdb":{"original-path":"","split":false},"transform-paths":true},"cil":{"merge":{"inlines":true},"cstd":"c99","gnu89inline":false,"addNestedScopeAttr":false},"server":{"enabled":false,"mode":"stdio","unix-socket":"goblint.sock","reparse":false},"ana":{"activated":["expRelation","base","threadid","threadflag","threadreturn","escape","mutexEvents","mutex","access","race","mallocWrapper","mhp","assert","pthreadMutexType"],"path_sens":["mutex","malloc_null","uninit","expsplit","activeSetjmp","memLeak","apron","affeq","lin2vareq"],"ctx_insens":["stack_loc","stack_trace_set"],"ctx_sens":[],"setjmp":{"split":"precise"},"int":{"def_exc":true,"interval":false,"interval_set":false,"enums":false,"congruence":false,"refinement":"never","def_exc_widen_by_join":false,"interval_narrow_by_meet":false,"interval_threshold_widening":false,"interval_threshold_widening_constants":"all"},"float":{"interval":false,"evaluate_math_functions":false},"pml":{"debug":true},"opt":{"hashcons":true,"equal":true},"autotune":{"enabled":false,"activated":["congruence","singleThreaded","specification","mallocWrappers","noRecursiveIntervals","enums","loopUnrollHeuristic","arrayDomain","octagon","wideningThresholds","memsafetySpecification","termination","tmpSpecialAnalysis"]},"sv-comp":{"enabled":false,"functions":false},"specification":"","wp":false,"arrayoob":false,"base":{"context":{"non-ptr":true,"int":true,"interval":true,"interval_set":true},"strings":{"domain":"flat"},"partition-arrays":{"keep-expr":"first","partition-by-const-on-return":false,"smart-join":false},"arrays":{"domain":"trivial","unrolling-factor":0,"nullbytes":false},"structs":{"domain":"simple","key":{"forward":true,"avoid-ints":true,"prefer-ptrs":true}},"privatization":"protection-read","priv":{"not-started":true,"must-joined":true},"invariant":{"enabled":true,"blobs":false,"unassume":"once","int":{"simplify":"all"}},"eval":{"deep-query":true}},"malloc":{"wrappers":["kmalloc","__kmalloc","usb_alloc_urb","__builtin_alloca","kzalloc"],"unique_address_count":0},"apron":{"strengthening":false,"domain":"octagon","threshold_widening":false,"threshold_widening_constants":"all","invariant":{"diff-box":false}},"relation":{"context":true,"privatization":"mutex-meet","priv":{"not-started":true,"must-joined":true},"invariant":{"one-var":false,"local":true,"global":true}},"context":{"widen":false,"gas_value":-1,"gas_scope":"global","callString_length":2},"thread":{"domain":"history","include-node":true,"wrappers":[],"unique_thread_id_count":0,"context":{"create-edges":true}},"race":{"free":true,"call":true,"direct-arithmetic":false,"volatile":true},"dead-code":{"lines":true,"branches":true,"functions":true},"extract-pthread":{"assume_success":true,"ignore_assign":true},"widen":{"tokens":false},"unassume":{"precheck":false}},"incremental":{"load":false,"load-dir":"incremental_data","only-rename":false,"save":false,"save-dir":"incremental_data","stable":true,"wpoint":false,"reluctant":{"enabled":false},"compare":"ast","detect-renames":true,"force-reanalyze":{"funs":[]},"restart":{"sided":{"enabled":false,"vars":"all","fuel":-1,"fuel-only-global":false},"list":[],"write-only":true},"postsolver":{"enabled":true,"superstable-reached":false}},"lib":{"activated":["c","posix","pthread","gcc","glibc","linux-userspace","goblint","ncurses","legacy"]},"sem":{"unknown_function":{"spawn":true,"call":true,"invalidate":{"globals":true,"args":true},"read":{"args":true}},"builtin_unreachable":{"dead_code":false},"noreturn":{"dead_code":false},"int":{"signed_overflow":"assume_top"},"null-pointer":{"dereference":"assume_none"},"malloc":{"fail":false},"lock":{"fail":false},"assert":{"refine":true},"atexit":{"ignore":false}},"trans":{"activated":[],"expeval":{"query_file_name":""},"output":"transformed.c","assert":{"function":"__VERIFIER_assert","wrap-atomic":true}},"annotation":{"int":{"enabled":false,"privglobs":true},"float":{"enabled":false},"goblint_context":{"__additional__":[]},"goblint_precision":{"__additional__":[]},"goblint_array_domain":false,"goblint_relation_track":false},"exp":{"priv-prec-dump":"","priv-distr-init":false,"relation":{"prec-dump":""},"cfgdot":false,"mincfg":false,"earlyglobs":false,"region-offsets":false,"unique":[],"forward":false,"volatiles_are_top":true,"single-threaded":false,"globs_are_top":false,"exclude_from_earlyglobs":[],"exclude_from_invalidation":[],"g2html_path":"","extraspecials":[],"no-narrow":false,"basic-blocks":false,"fast_global_inits":true,"architecture":"64bit","gcc_path":"/usr/bin/gcc","cpp-path":"","unrolling-factor":0,"hide-std-globals":true,"arg":{"enabled":false,"dot":{"path":"","node-label":"node"}}},"dbg":{"level":"info","timing":{"enabled":false,"tef":""},"trace":{"context":false},"dump":"","cilout":"","justcil-printer":"default","timeout":"0","solver-stats-interval":10,"solver-signal":"sigusr1","backtrace-signal":"sigusr2","solver-progress":false,"print_wpoints":false,"slice":{"on":false,"n":10},"limit":{"widen":0},"warn_with_context":false,"regression":false,"test":{"domain":false},"cilcfgdot":false,"cfg":{"loop-clusters":false,"loop-unrolling":false},"compare_runs":{"globsys":false,"eqsys":true,"global":false,"node":false,"diff":false},"print_tids":false,"print_protection":false,"run_cil_check":false,"full-output":false},"warn":{"assert":true,"behavior":true,"call":true,"integer":true,"float":true,"cast":true,"race":true,"deadlock":true,"deadcode":true,"analyzer":true,"unsound":true,"imprecise":true,"witness":true,"program":true,"termination":true,"unknown":true,"error":true,"warning":true,"info":true,"debug":false,"success":true,"quote-code":false,"race-threshold":0,"deterministic":true,"memleak":{"memcleanup":false,"memtrack":false}},"solvers":{"td3":{"term":true,"side_widen":"sides","space":false,"space_cache":true,"space_restore":true,"narrow-reuse":true,"remove-wpoint":true,"skip-unchanged-rhs":false,"restart":{"wpoint":{"enabled":false,"once":false}},"verify":false},"slr4":{"restart_count":1}},"witness":{"graphml":{"enabled":false,"path":"witness.graphml","id":"node","minimize":false,"uncil":false,"stack":true,"unknown":true},"invariant":{"loop-head":true,"after-lock":true,"other":true,"split-conjunction":true,"accessed":false,"full":true,"exact":true,"inexact-type-bounds":false,"exclude-vars":["tmp\\(___[0-9]+\\)?","cond","RETURN"],"all-locals":true,"goblint":false,"typedefs":true},"yaml":{"enabled":false,"format-version":"0.1","entry-types":["location_invariant","loop_invariant","flow_insensitive_invariant","loop_invariant_certificate","precondition_loop_invariant_certificate","invariant_set"],"invariant-types":["location_invariant","loop_invariant"],"path":"witness.yml","validate":"","strict":false,"unassume":"","certificate":""}}} + Did You forget to add default values to options.schema.json? + + [Info] runtime: 00:00:00.061 + [Info] vars: 2, evals: 12 + [Info] max updates: 1 for var L:call of main (299) on 01-assert.c:4:1-15:1 + + + Memory statistics: total=23.99MB, max=7.06MB, minor=21.98MB, major=6.53MB, promoted=4.52MB + minor collections=10 major collections=1 compactions=0 + + + Fatal error: exception Failure("get_path_string") + [2] + + $ goblint --enable warn.deterministic --set solver td3 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 From e57072f7560c7a5f060087be37b041c3206aa224 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 24 Oct 2024 17:26:12 +0300 Subject: [PATCH 585/689] Fix option name in topdown_space_cache_term --- src/solver/topDown_space_cache_term.ml | 2 +- tests/regression/00-sanity/01-assert.t | 25 ++++++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/solver/topDown_space_cache_term.ml b/src/solver/topDown_space_cache_term.ml index 0022756a31..df44c376e1 100644 --- a/src/solver/topDown_space_cache_term.ml +++ b/src/solver/topDown_space_cache_term.ml @@ -170,7 +170,7 @@ module WP = ) in (* restore values for non-widening-points *) - if GobConfig.get_bool "solvers.wp.restore" then ( + if GobConfig.get_bool "solvers.td3.space_restore" then ( Logs.debug "Restoring missing values."; let restore () = let get x = diff --git a/tests/regression/00-sanity/01-assert.t b/tests/regression/00-sanity/01-assert.t index 2f81310ada..159fd5a932 100644 --- a/tests/regression/00-sanity/01-assert.t +++ b/tests/regression/00-sanity/01-assert.t @@ -112,21 +112,16 @@ Test topdown solvers: [3] $ goblint --enable warn.deterministic --set solver topdown_space_cache_term 01-assert.c - [Error] Cannot find value 'solvers.wp.restore' in - {"files":["01-assert.c"],"outfile":"","justcil":false,"justcfg":false,"verify":true,"mainfun":["main"],"exitfun":[],"otherfun":[],"allglobs":false,"kernel":false,"dump_globs":false,"result":"none","solver":"topdown_space_cache_term","comparesolver":"","allfuns":false,"nonstatic":false,"colors":"auto","g2html":false,"save_run":"","load_run":"","compare_runs":[],"warn_at":"post","gobview":false,"jobs":1,"goblint-dir":".goblint","pre":{"enabled":true,"keep":false,"exist":false,"includes":[],"kernel_includes":[],"custom_includes":[],"kernel-root":"","cppflags":[],"compdb":{"original-path":"","split":false},"transform-paths":true},"cil":{"merge":{"inlines":true},"cstd":"c99","gnu89inline":false,"addNestedScopeAttr":false},"server":{"enabled":false,"mode":"stdio","unix-socket":"goblint.sock","reparse":false},"ana":{"activated":["expRelation","base","threadid","threadflag","threadreturn","escape","mutexEvents","mutex","access","race","mallocWrapper","mhp","assert","pthreadMutexType"],"path_sens":["mutex","malloc_null","uninit","expsplit","activeSetjmp","memLeak","apron","affeq","lin2vareq"],"ctx_insens":["stack_loc","stack_trace_set"],"ctx_sens":[],"setjmp":{"split":"precise"},"int":{"def_exc":true,"interval":false,"interval_set":false,"enums":false,"congruence":false,"refinement":"never","def_exc_widen_by_join":false,"interval_narrow_by_meet":false,"interval_threshold_widening":false,"interval_threshold_widening_constants":"all"},"float":{"interval":false,"evaluate_math_functions":false},"pml":{"debug":true},"opt":{"hashcons":true,"equal":true},"autotune":{"enabled":false,"activated":["congruence","singleThreaded","specification","mallocWrappers","noRecursiveIntervals","enums","loopUnrollHeuristic","arrayDomain","octagon","wideningThresholds","memsafetySpecification","termination","tmpSpecialAnalysis"]},"sv-comp":{"enabled":false,"functions":false},"specification":"","wp":false,"arrayoob":false,"base":{"context":{"non-ptr":true,"int":true,"interval":true,"interval_set":true},"strings":{"domain":"flat"},"partition-arrays":{"keep-expr":"first","partition-by-const-on-return":false,"smart-join":false},"arrays":{"domain":"trivial","unrolling-factor":0,"nullbytes":false},"structs":{"domain":"simple","key":{"forward":true,"avoid-ints":true,"prefer-ptrs":true}},"privatization":"protection-read","priv":{"not-started":true,"must-joined":true},"invariant":{"enabled":true,"blobs":false,"unassume":"once","int":{"simplify":"all"}},"eval":{"deep-query":true}},"malloc":{"wrappers":["kmalloc","__kmalloc","usb_alloc_urb","__builtin_alloca","kzalloc"],"unique_address_count":0},"apron":{"strengthening":false,"domain":"octagon","threshold_widening":false,"threshold_widening_constants":"all","invariant":{"diff-box":false}},"relation":{"context":true,"privatization":"mutex-meet","priv":{"not-started":true,"must-joined":true},"invariant":{"one-var":false,"local":true,"global":true}},"context":{"widen":false,"gas_value":-1,"gas_scope":"global","callString_length":2},"thread":{"domain":"history","include-node":true,"wrappers":[],"unique_thread_id_count":0,"context":{"create-edges":true}},"race":{"free":true,"call":true,"direct-arithmetic":false,"volatile":true},"dead-code":{"lines":true,"branches":true,"functions":true},"extract-pthread":{"assume_success":true,"ignore_assign":true},"widen":{"tokens":false},"unassume":{"precheck":false}},"incremental":{"load":false,"load-dir":"incremental_data","only-rename":false,"save":false,"save-dir":"incremental_data","stable":true,"wpoint":false,"reluctant":{"enabled":false},"compare":"ast","detect-renames":true,"force-reanalyze":{"funs":[]},"restart":{"sided":{"enabled":false,"vars":"all","fuel":-1,"fuel-only-global":false},"list":[],"write-only":true},"postsolver":{"enabled":true,"superstable-reached":false}},"lib":{"activated":["c","posix","pthread","gcc","glibc","linux-userspace","goblint","ncurses","legacy"]},"sem":{"unknown_function":{"spawn":true,"call":true,"invalidate":{"globals":true,"args":true},"read":{"args":true}},"builtin_unreachable":{"dead_code":false},"noreturn":{"dead_code":false},"int":{"signed_overflow":"assume_top"},"null-pointer":{"dereference":"assume_none"},"malloc":{"fail":false},"lock":{"fail":false},"assert":{"refine":true},"atexit":{"ignore":false}},"trans":{"activated":[],"expeval":{"query_file_name":""},"output":"transformed.c","assert":{"function":"__VERIFIER_assert","wrap-atomic":true}},"annotation":{"int":{"enabled":false,"privglobs":true},"float":{"enabled":false},"goblint_context":{"__additional__":[]},"goblint_precision":{"__additional__":[]},"goblint_array_domain":false,"goblint_relation_track":false},"exp":{"priv-prec-dump":"","priv-distr-init":false,"relation":{"prec-dump":""},"cfgdot":false,"mincfg":false,"earlyglobs":false,"region-offsets":false,"unique":[],"forward":false,"volatiles_are_top":true,"single-threaded":false,"globs_are_top":false,"exclude_from_earlyglobs":[],"exclude_from_invalidation":[],"g2html_path":"","extraspecials":[],"no-narrow":false,"basic-blocks":false,"fast_global_inits":true,"architecture":"64bit","gcc_path":"/usr/bin/gcc","cpp-path":"","unrolling-factor":0,"hide-std-globals":true,"arg":{"enabled":false,"dot":{"path":"","node-label":"node"}}},"dbg":{"level":"info","timing":{"enabled":false,"tef":""},"trace":{"context":false},"dump":"","cilout":"","justcil-printer":"default","timeout":"0","solver-stats-interval":10,"solver-signal":"sigusr1","backtrace-signal":"sigusr2","solver-progress":false,"print_wpoints":false,"slice":{"on":false,"n":10},"limit":{"widen":0},"warn_with_context":false,"regression":false,"test":{"domain":false},"cilcfgdot":false,"cfg":{"loop-clusters":false,"loop-unrolling":false},"compare_runs":{"globsys":false,"eqsys":true,"global":false,"node":false,"diff":false},"print_tids":false,"print_protection":false,"run_cil_check":false,"full-output":false},"warn":{"assert":true,"behavior":true,"call":true,"integer":true,"float":true,"cast":true,"race":true,"deadlock":true,"deadcode":true,"analyzer":true,"unsound":true,"imprecise":true,"witness":true,"program":true,"termination":true,"unknown":true,"error":true,"warning":true,"info":true,"debug":false,"success":true,"quote-code":false,"race-threshold":0,"deterministic":true,"memleak":{"memcleanup":false,"memtrack":false}},"solvers":{"td3":{"term":true,"side_widen":"sides","space":false,"space_cache":true,"space_restore":true,"narrow-reuse":true,"remove-wpoint":true,"skip-unchanged-rhs":false,"restart":{"wpoint":{"enabled":false,"once":false}},"verify":false},"slr4":{"restart_count":1}},"witness":{"graphml":{"enabled":false,"path":"witness.graphml","id":"node","minimize":false,"uncil":false,"stack":true,"unknown":true},"invariant":{"loop-head":true,"after-lock":true,"other":true,"split-conjunction":true,"accessed":false,"full":true,"exact":true,"inexact-type-bounds":false,"exclude-vars":["tmp\\(___[0-9]+\\)?","cond","RETURN"],"all-locals":true,"goblint":false,"typedefs":true},"yaml":{"enabled":false,"format-version":"0.1","entry-types":["location_invariant","loop_invariant","flow_insensitive_invariant","loop_invariant_certificate","precondition_loop_invariant_certificate","invariant_set"],"invariant-types":["location_invariant","loop_invariant"],"path":"witness.yml","validate":"","strict":false,"unassume":"","certificate":""}}} - Did You forget to add default values to options.schema.json? - - [Info] runtime: 00:00:00.061 - [Info] vars: 2, evals: 12 - [Info] max updates: 1 for var L:call of main (299) on 01-assert.c:4:1-15:1 - - - Memory statistics: total=23.99MB, max=7.06MB, minor=21.98MB, major=6.53MB, promoted=4.52MB - minor collections=10 major collections=1 compactions=0 - - - Fatal error: exception Failure("get_path_string") - [2] + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 $ goblint --enable warn.deterministic --set solver td3 01-assert.c [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) From f0a15f65850b2ec295cb91c9005cca8265f479d9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 24 Oct 2024 17:28:39 +0300 Subject: [PATCH 586/689] Fix basic functionality of topdown_term --- src/solver/topDown_term.ml | 6 ++-- tests/regression/00-sanity/01-assert.t | 47 ++++---------------------- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/src/solver/topDown_term.ml b/src/solver/topDown_term.ml index 9d89a42898..0099ec2115 100644 --- a/src/solver/topDown_term.ml +++ b/src/solver/topDown_term.ml @@ -24,8 +24,8 @@ module WP = let stable = HM.create 10 in let infl = HM.create 10 in (* y -> xs *) let called = HM.create 10 in - let rho = HM.create 10 in - let rho' = HM.create 10 in + let rho = HM.create 10 in (* rho for right-hand side values *) + let rho' = HM.create 10 in (* rho for start and side effect values *) let wpoint = HM.create 10 in let add_infl y x = @@ -101,7 +101,7 @@ module WP = let set_start (x,d) = if tracing then trace "sol2" "set_start %a ## %a" S.Var.pretty_trace x S.Dom.pretty d; init x; - HM.replace rho x d; + HM.replace rho' x d; solve x Widen in diff --git a/tests/regression/00-sanity/01-assert.t b/tests/regression/00-sanity/01-assert.t index 159fd5a932..60340fbd6e 100644 --- a/tests/regression/00-sanity/01-assert.t +++ b/tests/regression/00-sanity/01-assert.t @@ -65,51 +65,16 @@ Test topdown solvers: total lines: 9 $ goblint --enable warn.deterministic --set solver topdown_term 01-assert.c - [Error] Fixpoint not reached at L:entry state of main (299) on 01-assert.c:4:1-15:1 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), - mallocWrapper:(wrapper call:Unknown node, unique calls:{}), - base:({ - }, {}, {}, {}), - threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), - threadflag:Singlethreaded, - threadreturn:true, - escape:{}, - mutexEvents:(), - access:(), - mutex:(lockset:{}, multiplicity:{}), - race:(), - mhp:(), - assert:(), - pthreadMutexType:()], map:{})} - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), - mallocWrapper:(wrapper call:Unknown node, unique calls:{}), - base:({ - }, {}, {}, {}), - threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), - threadflag:Singlethreaded, - threadreturn:true, - escape:{}, - mutexEvents:(), - access:(), - mutex:(lockset:{}, multiplicity:{}), - race:(), - mhp:(), - assert:(), - pthreadMutexType:()], map:{})} instead of bot - + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) [Warning][Deadcode] Function 'main' does not return [Warning][Deadcode] Function 'main' has dead code: - on lines 4..7 (01-assert.c:4-7) - on lines 10..14 (01-assert.c:10-14) + on lines 13..14 (01-assert.c:13-14) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 0 - dead: 9 + live: 7 + dead: 2 total lines: 9 - [Error][Unsound] Fixpoint not reached - [3] $ goblint --enable warn.deterministic --set solver topdown_space_cache_term 01-assert.c [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) From 1eb63b9ad85ade6bdbf268340a718bf2b00e27cd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 24 Oct 2024 17:31:27 +0300 Subject: [PATCH 587/689] Fix invalid widen call in topdown_term for side effects --- src/solver/sLR.ml | 2 +- src/solver/topDown_term.ml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solver/sLR.ml b/src/solver/sLR.ml index 3b46f36f5e..0cf87caeee 100644 --- a/src/solver/sLR.ml +++ b/src/solver/sLR.ml @@ -66,7 +66,7 @@ module SLR3 = if tracing then trace "sol" "Contrib:%a" S.Dom.pretty tmp; let tmp = if wpx then - if HM.mem globals x then S.Dom.widen old tmp + if HM.mem globals x then S.Dom.widen old tmp (* TODO: no join in second argument, can call widen incorrectly? *) else box old tmp else tmp in diff --git a/src/solver/topDown_term.ml b/src/solver/topDown_term.ml index 0099ec2115..5560c50f4f 100644 --- a/src/solver/topDown_term.ml +++ b/src/solver/topDown_term.ml @@ -85,7 +85,7 @@ module WP = and side y d = let old = try HM.find rho' y with Not_found -> S.Dom.bot () in if not (S.Dom.leq d old) then ( - HM.replace rho' y (S.Dom.widen old d); + HM.replace rho' y (S.Dom.widen old (S.Dom.join old d)); HM.remove stable y; init y; solve y Widen; From c348dd6101acee5dcab78278f98b27e550072576 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 24 Oct 2024 17:38:36 +0300 Subject: [PATCH 588/689] Add cram tests for remaining solvers --- src/solver/sLR.ml | 2 +- tests/regression/00-sanity/01-assert.t | 297 +++++++++++++++++++++++++ 2 files changed, 298 insertions(+), 1 deletion(-) diff --git a/src/solver/sLR.ml b/src/solver/sLR.ml index 0cf87caeee..69d415307a 100644 --- a/src/solver/sLR.ml +++ b/src/solver/sLR.ml @@ -527,7 +527,7 @@ let _ = Selector.add_solver ("widen2", (module PostSolver.EqIncrSolverFromEqSolver (W2))); Selector.add_solver ("widen3", (module PostSolver.EqIncrSolverFromEqSolver (W3))); let module S2 = TwoPhased (struct let ver = 1 end) in - Selector.add_solver ("two", (module PostSolver.EqIncrSolverFromEqSolver (S2))); + Selector.add_solver ("two", (module PostSolver.EqIncrSolverFromEqSolver (S2))); (* TODO: broken even on 00-sanity/01-assert *) let module S1 = Make (struct let ver = 1 end) in Selector.add_solver ("new", (module PostSolver.EqIncrSolverFromEqSolver (S1))); Selector.add_solver ("slr+", (module PostSolver.EqIncrSolverFromEqSolver (S1))) diff --git a/tests/regression/00-sanity/01-assert.t b/tests/regression/00-sanity/01-assert.t index 60340fbd6e..cd8c4c06f8 100644 --- a/tests/regression/00-sanity/01-assert.t +++ b/tests/regression/00-sanity/01-assert.t @@ -99,3 +99,300 @@ Test topdown solvers: live: 7 dead: 2 total lines: 9 + + +Test SLR solvers: + + $ goblint --enable warn.deterministic --set solver widen1 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver widen2 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver widen3 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver two 01-assert.c + [Error] Fixpoint not reached at L:entry state of main (299) on 01-assert.c:4:1-15:1 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), + mallocWrapper:(wrapper call:Unknown node, unique calls:{}), + base:({ + }, {}, {}, {}), + threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), + threadflag:Singlethreaded, + threadreturn:true, + escape:{}, + mutexEvents:(), + access:(), + mutex:(lockset:{}, multiplicity:{}), + race:(), + mhp:(), + assert:(), + pthreadMutexType:()], map:{})} + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), + mallocWrapper:(wrapper call:Unknown node, unique calls:{}), + base:({ + }, {}, {}, {}), + threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), + threadflag:Singlethreaded, + threadreturn:true, + escape:{}, + mutexEvents:(), + access:(), + mutex:(lockset:{}, multiplicity:{}), + race:(), + mhp:(), + assert:(), + pthreadMutexType:()], map:{})} instead of bot + + [Error] Fixpoint not reached at L:node 1 "success = 1;" on 01-assert.c:5:7-5:18 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 2 "silence = 1;" on 01-assert.c:6:7-6:18 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 3 "fail = 0;" on 01-assert.c:7:7-7:15 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 4 "__goblint_assert(success);" on 01-assert.c:10:3-10:28 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 5 "__goblint_assert(unknown == 4);" on 01-assert.c:11:3-11:33 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 6 "__goblint_assert(fail);" on 01-assert.c:12:3-12:25 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 7 "return (0);" on 01-assert.c:13:10-13:11 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node 9 "__goblint_assert(silence);" on 01-assert.c:14:3-14:28 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:node -299 "return;" on 01-assert.c:15:1-15:1 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Error] Fixpoint not reached at L:call of main (299) on 01-assert.c:4:1-15:1 + Solver computed: + bot + Right-Hand-Side: + HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code + Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot + + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' is uncalled: 8 LLoC (01-assert.c:4:1-15:1) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 0 + dead: 8 (8 in uncalled functions) + total lines: 8 + [Error][Unsound] Fixpoint not reached + [3] + + $ goblint --enable warn.deterministic --set solver new 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr+ 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr1 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr2 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr3 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr4 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr1p 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + $ goblint --enable warn.deterministic --set solver slr2p 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr3p 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr4p 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr3t 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 + + $ goblint --enable warn.deterministic --set solver slr3tp 01-assert.c + [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) + [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33) + [Success][Assert] Assertion "success" will succeed (01-assert.c:10:3-10:28) + [Warning][Deadcode] Function 'main' does not return + [Warning][Deadcode] Function 'main' has dead code: + on lines 13..14 (01-assert.c:13-14) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 7 + dead: 2 + total lines: 9 From bfeaa22ae99fadfa916c35b96aa77e694ae1d8a9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:45:30 +0300 Subject: [PATCH 589/689] Rename IntDomain -> IntDomain0 for split Adds signatures to implementation to fix "contains type variables that cannot be generalized" errors. --- src/cdomain/value/cdomains/{intDomain.ml => intDomain0.ml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/cdomain/value/cdomains/{intDomain.ml => intDomain0.ml} (99%) diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain0.ml similarity index 99% rename from src/cdomain/value/cdomains/intDomain.ml rename to src/cdomain/value/cdomains/intDomain0.ml index e50b3f26cc..f4639d4522 100644 --- a/src/cdomain/value/cdomains/intDomain.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -1681,7 +1681,7 @@ struct let meet x y = if equal x y then x else bot () end -module Flat (Base: IkindUnawareS) = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) +module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) struct type int_t = Base.int_t include Lattice.FlatConf (struct @@ -1762,7 +1762,7 @@ struct | `Top | `Bot -> Invariant.none end -module Lift (Base: IkindUnawareS) = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) +module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) struct include Lattice.LiftPO (struct include Printable.DefaultConf From 6502779b680e7cf0d8331180968f4fcce5521592 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:46:20 +0300 Subject: [PATCH 590/689] Add intDomain.ml to redirect to IntDomain0 --- src/cdomain/value/cdomains/intDomain.ml | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/cdomain/value/cdomains/intDomain.ml diff --git a/src/cdomain/value/cdomains/intDomain.ml b/src/cdomain/value/cdomains/intDomain.ml new file mode 100644 index 0000000000..5fa56f5b51 --- /dev/null +++ b/src/cdomain/value/cdomains/intDomain.ml @@ -0,0 +1 @@ +include IntDomain0 From 727c6bf418e07451930f3cf6429b4f03955beed5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:47:48 +0300 Subject: [PATCH 591/689] Rename IntDomain0 -> IntDomTuple for split --- src/cdomain/value/cdomains/{intDomain0.ml => int/intDomTuple.ml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cdomain/value/cdomains/{intDomain0.ml => int/intDomTuple.ml} (100%) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/int/intDomTuple.ml similarity index 100% rename from src/cdomain/value/cdomains/intDomain0.ml rename to src/cdomain/value/cdomains/int/intDomTuple.ml From 227eb70a17e9729296778a7c3fcc8b9cf3fd44a5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:49:03 +0300 Subject: [PATCH 592/689] Remove non-IntDomTuple parts --- src/cdomain/value/cdomains/int/intDomTuple.ml | 3271 +---------------- 1 file changed, 1 insertion(+), 3270 deletions(-) diff --git a/src/cdomain/value/cdomains/int/intDomTuple.ml b/src/cdomain/value/cdomains/int/intDomTuple.ml index f4639d4522..7420c989fc 100644 --- a/src/cdomain/value/cdomains/int/intDomTuple.ml +++ b/src/cdomain/value/cdomains/int/intDomTuple.ml @@ -1,3273 +1,4 @@ -open GobConfig -open GoblintCil -open Pretty -open PrecisionUtil - -module M = Messages - -let (%) = Batteries.(%) -let (|?) = Batteries.(|?) - -exception IncompatibleIKinds of string -exception Unknown -exception Error -exception ArithmeticOnIntegerBot of string - - - - -(** Define records that hold mutable variables representing different Configuration values. - * These values are used to keep track of whether or not the corresponding Config values are en-/disabled *) -type ana_int_config_values = { - mutable interval_threshold_widening : bool option; - mutable interval_narrow_by_meet : bool option; - mutable def_exc_widen_by_join : bool option; - mutable interval_threshold_widening_constants : string option; - mutable refinement : string option; -} - -let ana_int_config: ana_int_config_values = { - interval_threshold_widening = None; - interval_narrow_by_meet = None; - def_exc_widen_by_join = None; - interval_threshold_widening_constants = None; - refinement = None; -} - -let get_interval_threshold_widening () = - if ana_int_config.interval_threshold_widening = None then - ana_int_config.interval_threshold_widening <- Some (get_bool "ana.int.interval_threshold_widening"); - Option.get ana_int_config.interval_threshold_widening - -let get_interval_narrow_by_meet () = - if ana_int_config.interval_narrow_by_meet = None then - ana_int_config.interval_narrow_by_meet <- Some (get_bool "ana.int.interval_narrow_by_meet"); - Option.get ana_int_config.interval_narrow_by_meet - -let get_def_exc_widen_by_join () = - if ana_int_config.def_exc_widen_by_join = None then - ana_int_config.def_exc_widen_by_join <- Some (get_bool "ana.int.def_exc_widen_by_join"); - Option.get ana_int_config.def_exc_widen_by_join - -let get_interval_threshold_widening_constants () = - if ana_int_config.interval_threshold_widening_constants = None then - ana_int_config.interval_threshold_widening_constants <- Some (get_string "ana.int.interval_threshold_widening_constants"); - Option.get ana_int_config.interval_threshold_widening_constants - -let get_refinement () = - if ana_int_config.refinement = None then - ana_int_config.refinement <- Some (get_string "ana.int.refinement"); - Option.get ana_int_config.refinement - - - -(** Whether for a given ikind, we should compute with wrap-around arithmetic. - * Always for unsigned types, for signed types if 'sem.int.signed_overflow' is 'assume_wraparound' *) -let should_wrap ik = not (Cil.isSigned ik) || get_string "sem.int.signed_overflow" = "assume_wraparound" - -(** Whether for a given ikind, we should assume there are no overflows. - * Always false for unsigned types, true for signed types if 'sem.int.signed_overflow' is 'assume_none' *) -let should_ignore_overflow ik = Cil.isSigned ik && get_string "sem.int.signed_overflow" = "assume_none" - -let widening_thresholds = ResettableLazy.from_fun WideningThresholds.thresholds -let widening_thresholds_desc = ResettableLazy.from_fun (List.rev % WideningThresholds.thresholds) - -type overflow_info = { overflow: bool; underflow: bool;} - -let set_overflow_flag ~cast ~underflow ~overflow ik = - if !AnalysisState.executing_speculative_computations then - (* Do not produce warnings when the operations are not actually happening in code *) - () - else - let signed = Cil.isSigned ik in - if !AnalysisState.postsolving && signed && not cast then - AnalysisState.svcomp_may_overflow := true; - let sign = if signed then "Signed" else "Unsigned" in - match underflow, overflow with - | true, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190; CWE 191] "%s integer overflow and underflow" sign - | true, false -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 191] "%s integer underflow" sign - | false, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190] "%s integer overflow" sign - | false, false -> assert false - -let reset_lazy () = - ResettableLazy.reset widening_thresholds; - ResettableLazy.reset widening_thresholds_desc; - ana_int_config.interval_threshold_widening <- None; - ana_int_config.interval_narrow_by_meet <- None; - ana_int_config.def_exc_widen_by_join <- None; - ana_int_config.interval_threshold_widening_constants <- None; - ana_int_config.refinement <- None - -module type Arith = -sig - type t - val neg: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div: t -> t -> t - val rem: t -> t -> t - - val lt: t -> t -> t - val gt: t -> t -> t - val le: t -> t -> t - val ge: t -> t -> t - val eq: t -> t -> t - val ne: t -> t -> t - - val lognot: t -> t - val logand: t -> t -> t - val logor : t -> t -> t - val logxor: t -> t -> t - - val shift_left : t -> t -> t - val shift_right: t -> t -> t - - val c_lognot: t -> t - val c_logand: t -> t -> t - val c_logor : t -> t -> t - -end - -module type ArithIkind = -sig - type t - val neg: Cil.ikind -> t -> t - val add: Cil.ikind -> t -> t -> t - val sub: Cil.ikind -> t -> t -> t - val mul: Cil.ikind -> t -> t -> t - val div: Cil.ikind -> t -> t -> t - val rem: Cil.ikind -> t -> t -> t - - val lt: Cil.ikind -> t -> t -> t - val gt: Cil.ikind -> t -> t -> t - val le: Cil.ikind -> t -> t -> t - val ge: Cil.ikind -> t -> t -> t - val eq: Cil.ikind -> t -> t -> t - val ne: Cil.ikind -> t -> t -> t - - val lognot: Cil.ikind -> t -> t - val logand: Cil.ikind -> t -> t -> t - val logor : Cil.ikind -> t -> t -> t - val logxor: Cil.ikind -> t -> t -> t - - val shift_left : Cil.ikind -> t -> t -> t - val shift_right: Cil.ikind -> t -> t -> t - - val c_lognot: Cil.ikind -> t -> t - val c_logand: Cil.ikind -> t -> t -> t - val c_logor : Cil.ikind -> t -> t -> t - -end - -(* Shared functions between S and Z *) -module type B = -sig - include Lattice.S - type int_t - val bot_of: Cil.ikind -> t - val top_of: Cil.ikind -> t - val to_int: t -> int_t option - val equal_to: int_t -> t -> [`Eq | `Neq | `Top] - - val to_bool: t -> bool option - val to_excl_list: t -> (int_t list * (int64 * int64)) option - val of_excl_list: Cil.ikind -> int_t list -> t - val is_excl_list: t -> bool - - val to_incl_list: t -> int_t list option - - val maximal : t -> int_t option - val minimal : t -> int_t option - - val cast_to: ?suppress_ovwarn:bool -> ?torg:Cil.typ -> Cil.ikind -> t -> t -end - -(** Interface of IntDomain implementations that do not take ikinds for arithmetic operations yet. TODO: Should be ported to S in the future. *) -module type IkindUnawareS = -sig - include B - include Arith with type t := t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: int_t -> t - val of_bool: bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val arbitrary: unit -> t QCheck.arbitrary - val invariant: Cil.exp -> t -> Invariant.t -end - -(** Interface of IntDomain implementations taking an ikind for arithmetic operations *) -module type S = -sig - include B - include ArithIkind with type t:= t - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val neg : ?no_ov:bool -> Cil.ikind -> t -> t - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t - - val join: Cil.ikind -> t -> t -> t - val meet: Cil.ikind -> t -> t -> t - val narrow: Cil.ikind -> t -> t -> t - val widen: Cil.ikind -> t -> t -> t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val is_top_of: Cil.ikind -> t -> bool - val invariant_ikind : Cil.exp -> Cil.ikind -> t -> Invariant.t - - val refine_with_congruence: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_interval: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_excl_list: Cil.ikind -> t -> (int_t list * (int64 * int64)) option -> t - val refine_with_incl_list: Cil.ikind -> t -> int_t list option -> t - - val project: Cil.ikind -> int_precision -> t -> t - val arbitrary: Cil.ikind -> t QCheck.arbitrary -end - -module type SOverflow = -sig - - include S - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val neg : ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val of_int : Cil.ikind -> int_t -> t * overflow_info - - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t * overflow_info - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - - val shift_left : Cil.ikind -> t -> t -> t * overflow_info - - val shift_right : Cil.ikind -> t -> t -> t * overflow_info -end - -module type Y = -sig - (* include B *) - include B - include Arith with type t:= t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val is_top_of: Cil.ikind -> t -> bool - - val project: int_precision -> t -> t - val invariant: Cil.exp -> t -> Invariant.t -end - -module type Z = Y with type int_t = Z.t - - -module IntDomLifter (I : S) = -struct - open Cil - type int_t = I.int_t - type t = { v : I.t; ikind : CilType.Ikind.t } [@@deriving eq, ord, hash] - - let ikind {ikind; _} = ikind - - (* Helper functions *) - let check_ikinds x y = if x.ikind <> y.ikind then raise (IncompatibleIKinds (GobPretty.sprintf "ikinds %a and %a are incompatible. Values: %a and %a" CilType.Ikind.pretty x.ikind CilType.Ikind.pretty y.ikind I.pretty x.v I.pretty y.v)) - let lift op x = {x with v = op x.ikind x.v } - (* For logical operations the result is of type int *) - let lift_logical op x = {v = op x.ikind x.v; ikind = Cil.IInt} - let lift2 op x y = check_ikinds x y; {x with v = op x.ikind x.v y.v } - let lift2_cmp op x y = check_ikinds x y; {v = op x.ikind x.v y.v; ikind = Cil.IInt} - - let bot_of ikind = { v = I.bot_of ikind; ikind} - let bot () = failwith "bot () is not implemented for IntDomLifter." - let is_bot x = I.is_bot x.v - let top_of ikind = { v = I.top_of ikind; ikind} - let top () = failwith "top () is not implemented for IntDomLifter." - let is_top x = I.is_top x.v - - (* Leq does not check for ikind, because it is used in invariant with arguments of different type. - TODO: check ikinds here and fix invariant to work with right ikinds *) - let leq x y = I.leq x.v y.v - let join = lift2 I.join - let meet = lift2 I.meet - let widen = lift2 I.widen - let narrow = lift2 I.narrow - - let show x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - "⊤" - else - I.show x.v (* TODO add ikind to output *) - let pretty () x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - Pretty.text "⊤" - else - I.pretty () x.v (* TODO add ikind to output *) - let pretty_diff () (x, y) = I.pretty_diff () (x.v, y.v) (* TODO check ikinds, add them to output *) - let printXml o x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - BatPrintf.fprintf o "\n\n⊤\n\n\n" - else - I.printXml o x.v (* TODO add ikind to output *) - (* This is for debugging *) - let name () = "IntDomLifter(" ^ (I.name ()) ^ ")" - let to_yojson x = I.to_yojson x.v - let invariant e x = - let e' = Cilfacade.mkCast ~e ~newt:(TInt (x.ikind, [])) in - I.invariant_ikind e' x.ikind x.v - let tag x = I.tag x.v - let arbitrary ik = failwith @@ "Arbitrary not implement for " ^ (name ()) ^ "." - let to_int x = I.to_int x.v - let of_int ikind x = { v = I.of_int ikind x; ikind} - let equal_to i x = I.equal_to i x.v - let to_bool x = I.to_bool x.v - let of_bool ikind b = { v = I.of_bool ikind b; ikind} - let to_excl_list x = I.to_excl_list x.v - let of_excl_list ikind is = {v = I.of_excl_list ikind is; ikind} - let is_excl_list x = I.is_excl_list x.v - let to_incl_list x = I.to_incl_list x.v - let of_interval ?(suppress_ovwarn=false) ikind (lb,ub) = {v = I.of_interval ~suppress_ovwarn ikind (lb,ub); ikind} - let of_congruence ikind (c,m) = {v = I.of_congruence ikind (c,m); ikind} - let starting ?(suppress_ovwarn=false) ikind i = {v = I.starting ~suppress_ovwarn ikind i; ikind} - let ending ?(suppress_ovwarn=false) ikind i = {v = I.ending ~suppress_ovwarn ikind i; ikind} - let maximal x = I.maximal x.v - let minimal x = I.minimal x.v - - let neg = lift I.neg - let add = lift2 I.add - let sub = lift2 I.sub - let mul = lift2 I.mul - let div = lift2 I.div - let rem = lift2 I.rem - let lt = lift2_cmp I.lt - let gt = lift2_cmp I.gt - let le = lift2_cmp I.le - let ge = lift2_cmp I.ge - let eq = lift2_cmp I.eq - let ne = lift2_cmp I.ne - let lognot = lift I.lognot - let logand = lift2 I.logand - let logor = lift2 I.logor - let logxor = lift2 I.logxor - let shift_left x y = {x with v = I.shift_left x.ikind x.v y.v } (* TODO check ikinds*) - let shift_right x y = {x with v = I.shift_right x.ikind x.v y.v } (* TODO check ikinds*) - let c_lognot = lift_logical I.c_lognot - let c_logand = lift2 I.c_logand - let c_logor = lift2 I.c_logor - - let cast_to ?(suppress_ovwarn=false) ?torg ikind x = {v = I.cast_to ~suppress_ovwarn ~torg:(TInt(x.ikind,[])) ikind x.v; ikind} - - let is_top_of ik x = ik = x.ikind && I.is_top_of ik x.v - - let relift x = { v = I.relift x.v; ikind = x.ikind } - - let project p v = { v = I.project v.ikind p v.v; ikind = v.ikind } -end - -module type Ikind = -sig - val ikind: unit -> Cil.ikind -end - -module PtrDiffIkind : Ikind = -struct - let ikind = Cilfacade.ptrdiff_ikind -end - -module IntDomWithDefaultIkind (I: Y) (Ik: Ikind) : Y with type t = I.t and type int_t = I.int_t = -struct - include I - let top () = I.top_of (Ik.ikind ()) - let bot () = I.bot_of (Ik.ikind ()) -end - -module Size = struct (* size in bits as int, range as int64 *) - open Cil - let sign x = if Z.compare x Z.zero < 0 then `Signed else `Unsigned - - let top_typ = TInt (ILongLong, []) - let min_for x = intKindForValue x (sign x = `Unsigned) - let bit = function (* bits needed for representation *) - | IBool -> 1 - | ik -> bytesSizeOfInt ik * 8 - let is_int64_big_int x = Z.fits_int64 x - let card ik = (* cardinality *) - let b = bit ik in - Z.shift_left Z.one b - let bits ik = (* highest bits for neg/pos values *) - let s = bit ik in - if isSigned ik then s-1, s-1 else 0, s - let bits_i64 ik = BatTuple.Tuple2.mapn Int64.of_int (bits ik) - let range ik = - let a,b = bits ik in - let x = if isSigned ik then Z.neg (Z.shift_left Z.one a) (* -2^a *) else Z.zero in - let y = Z.pred (Z.shift_left Z.one b) in (* 2^b - 1 *) - x,y - - let is_cast_injective ~from_type ~to_type = - let (from_min, from_max) = range (Cilfacade.get_ikind from_type) in - let (to_min, to_max) = range (Cilfacade.get_ikind to_type) in - if M.tracing then M.trace "int" "is_cast_injective %a (%a, %a) -> %a (%a, %a)" CilType.Typ.pretty from_type GobZ.pretty from_min GobZ.pretty from_max CilType.Typ.pretty to_type GobZ.pretty to_min GobZ.pretty to_max; - Z.compare to_min from_min <= 0 && Z.compare from_max to_max <= 0 - - let cast t x = (* TODO: overflow is implementation-dependent! *) - if t = IBool then - (* C11 6.3.1.2 Boolean type *) - if Z.equal x Z.zero then Z.zero else Z.one - else - let a,b = range t in - let c = card t in - let y = Z.erem x c in - let y = if Z.gt y b then Z.sub y c - else if Z.lt y a then Z.add y c - else y - in - if M.tracing then M.tracel "cast" "Cast %a to range [%a, %a] (%a) = %a (%s in int64)" GobZ.pretty x GobZ.pretty a GobZ.pretty b GobZ.pretty c GobZ.pretty y (if is_int64_big_int y then "fits" else "does not fit"); - y - - let min_range_sign_agnostic x = - let size ik = - let a,b = bits_i64 ik in - Int64.neg a,b - in - if sign x = `Signed then - size (min_for x) - else - let a, b = size (min_for x) in - if b <= 64L then - let upper_bound_less = Int64.sub b 1L in - let max_one_less = Z.(pred @@ shift_left Z.one (Int64.to_int upper_bound_less)) in - if x <= max_one_less then - a, upper_bound_less - else - a,b - else - a, b - - (* From the number of bits used to represent a positive value, determines the maximal representable value *) - let max_from_bit_range pos_bits = Z.(pred @@ shift_left Z.one (to_int (Z.of_int64 pos_bits))) - - (* From the number of bits used to represent a non-positive value, determines the minimal representable value *) - let min_from_bit_range neg_bits = Z.(if neg_bits = 0L then Z.zero else neg @@ shift_left Z.one (to_int (neg (Z.of_int64 neg_bits)))) - -end - - -module StdTop (B: sig type t val top_of: Cil.ikind -> t end) = struct - open B - (* these should be overwritten for better precision if possible: *) - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ik x = top_of ik - let ending ?(suppress_ovwarn=false) ik x = top_of ik - let maximal x = None - let minimal x = None -end - -module Std (B: sig - type t - val name: unit -> string - val top_of: Cil.ikind -> t - val bot_of: Cil.ikind -> t - val show: t -> string - val equal: t -> t -> bool - end) = struct - include Printable.StdLeaf - let name = B.name (* overwrite the one from Printable.Std *) - open B - let is_top x = failwith "is_top not implemented for IntDomain.Std" - let is_bot x = B.equal x (bot_of Cil.IInt) (* Here we assume that the representation of bottom is independent of the ikind - This may be true for intdomain implementations, but not e.g. for IntDomLifter. *) - let is_top_of ik x = B.equal x (top_of ik) - - (* all output is based on B.show *) - include Printable.SimpleShow ( - struct - type nonrec t = t - let show = show - end - ) - let pretty_diff () (x,y) = dprintf "%s: %a instead of %a" (name ()) pretty x pretty y - - include StdTop (B) -end - -(* Textbook interval arithmetic, without any overflow handling etc. *) -module IntervalArith (Ints_t : IntOps.IntOps) = struct - let min4 a b c d = Ints_t.min (Ints_t.min a b) (Ints_t.min c d) - let max4 a b c d = Ints_t.max (Ints_t.max a b) (Ints_t.max c d) - - let mul (x1, x2) (y1, y2) = - let x1y1 = (Ints_t.mul x1 y1) in - let x1y2 = (Ints_t.mul x1 y2) in - let x2y1 = (Ints_t.mul x2 y1) in - let x2y2 = (Ints_t.mul x2 y2) in - (min4 x1y1 x1y2 x2y1 x2y2, max4 x1y1 x1y2 x2y1 x2y2) - - let shift_left (x1,x2) (y1,y2) = - let y1p = Ints_t.shift_left Ints_t.one y1 in - let y2p = Ints_t.shift_left Ints_t.one y2 in - mul (x1, x2) (y1p, y2p) - - let div (x1, x2) (y1, y2) = - let x1y1n = (Ints_t.div x1 y1) in - let x1y2n = (Ints_t.div x1 y2) in - let x2y1n = (Ints_t.div x2 y1) in - let x2y2n = (Ints_t.div x2 y2) in - let x1y1p = (Ints_t.div x1 y1) in - let x1y2p = (Ints_t.div x1 y2) in - let x2y1p = (Ints_t.div x2 y1) in - let x2y2p = (Ints_t.div x2 y2) in - (min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p) - - let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2) - let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1) - - let neg (x1, x2) = (Ints_t.neg x2, Ints_t.neg x1) - - let one = (Ints_t.one, Ints_t.one) - let zero = (Ints_t.zero, Ints_t.zero) - let top_bool = (Ints_t.zero, Ints_t.one) - - let to_int (x1, x2) = - if Ints_t.equal x1 x2 then Some x1 else None - - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let max_ik' = Ints_t.to_bigint max_ik in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let min_ik' = Ints_t.to_bigint min_ik in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let is_upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - List.exists (Z.equal u) ts - let is_lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - List.exists (Z.equal l) ts -end - -module IntInvariant = -struct - let of_int e ik x = - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.none - - let of_incl_list e ik ps = - match ps with - | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> - assert (List.mem Z.zero ps); - assert (List.mem Z.one ps); - Invariant.none - | [_] when get_bool "witness.invariant.exact" -> - Invariant.none - | _ :: _ :: _ - | [_] | [] -> - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) (Invariant.bot ()) ps - - let of_interval_opt e ik = function - | (Some x1, Some x2) when Z.equal x1 x2 -> - of_int e ik x1 - | x1_opt, x2_opt -> - let (min_ik, max_ik) = Size.range ik in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = - match x1_opt, inexact_type_bounds with - | Some x1, false when Z.equal min_ik x1 -> Invariant.none - | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) - | None, _ -> Invariant.none - in - let i2 = - match x2_opt, inexact_type_bounds with - | Some x2, false when Z.equal x2 max_ik -> Invariant.none - | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) - | None, _ -> Invariant.none - in - Invariant.(i1 && i2) - - let of_interval e ik (x1, x2) = - of_interval_opt e ik (Some x1, Some x2) - - let of_excl_list e ik ns = - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) (Invariant.top ()) ns -end - -module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = -struct - let name () = "intervals" - type int_t = Ints_t.t - type t = (Ints_t.t * Ints_t.t) option [@@deriving eq, ord, hash] - module IArith = IntervalArith (Ints_t) - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - let top_of ik = Some (range ik) - let bot () = None - let bot_of ik = bot () (* TODO: improve *) - - let show = function None -> "bottom" | Some (x,y) -> "["^Ints_t.to_string x^","^Ints_t.to_string y^"]" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) -> - if a = b && b = i then `Eq else if Ints_t.compare a i <= 0 && Ints_t.compare i b <=0 then `Top else `Neq - - let norm ?(suppress_ovwarn=false) ?(cast=false) ik : (t -> t * overflow_info) = function None -> (None, {underflow=false; overflow=false}) | Some (x,y) -> - if Ints_t.compare x y > 0 then - (None,{underflow=false; overflow=false}) - else ( - let (min_ik, max_ik) = range ik in - let underflow = Ints_t.compare min_ik x > 0 in - let overflow = Ints_t.compare max_ik y < 0 in - let ov_info = { underflow = underflow && not suppress_ovwarn; overflow = overflow && not suppress_ovwarn } in - let v = - if underflow || overflow then - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (Ints_t.sub max_ik min_ik) in - let resdiff = Ints_t.abs (Ints_t.sub y x) in - if Ints_t.compare resdiff diff > 0 then - top_of ik - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if Ints_t.compare l u <= 0 then - Some (l, u) - else - (* Interval that wraps around (begins to the right of its end). We can not represent such intervals *) - top_of ik - else if not cast && should_ignore_overflow ik then - let tl, tu = BatOption.get @@ top_of ik in - Some (Ints_t.max tl x, Ints_t.min tu y) - else - top_of ik - else - Some (x,y) - in - (v, ov_info) - ) - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0 - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst - - let meet ik (x:t) y = - match x, y with - | None, z | z, None -> None - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.max x1 y1, Ints_t.min x2 y2) |> fst - - (* TODO: change to_int signature so it returns a big_int *) - let to_int x = Option.bind x (IArith.to_int) - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm ~suppress_ovwarn ik @@ Some (x,y) - let of_int ik (x: int_t) = of_interval ik (x,x) - let zero = Some IArith.zero - let one = Some IArith.one - let top_bool = Some IArith.top_bool - - let of_bool _ik = function true -> one | false -> zero - let to_bool (a: t) = match a with - | None -> None - | Some (l, u) when Ints_t.compare l Ints_t.zero = 0 && Ints_t.compare u Ints_t.zero = 0 -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (fst (range ik), n) - - (* TODO: change signature of maximal, minimal to return big_int*) - let maximal = function None -> None | Some (x,y) -> Some y - let minimal = function None -> None | Some (x,y) -> Some x - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - - let widen ik x y = - match x, y with - | None, z | z, None -> z - | Some (l0,u0), Some (l1,u1) -> - let (min_ik, max_ik) = range ik in - let threshold = get_interval_threshold_widening () in - let l2 = - if Ints_t.compare l0 l1 = 0 then l0 - else if threshold then IArith.lower_threshold l1 min_ik - else min_ik - in - let u2 = - if Ints_t.compare u0 u1 = 0 then u0 - else if threshold then IArith.upper_threshold u1 max_ik - else max_ik - in - norm ik @@ Some (l2,u2) |> fst - let widen ik x y = - let r = widen ik x y in - if M.tracing && not (equal x y) then M.tracel "int" "interval widen %a %a -> %a" pretty x pretty y pretty r; - assert (leq x y); (* TODO: remove for performance reasons? *) - r - - let narrow ik x y = - match x, y with - | _,None | None, _ -> None - | Some (x1,x2), Some (y1,y2) -> - let threshold = get_interval_threshold_widening () in - let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in - norm ik @@ Some (lr,ur) |> fst - - - let narrow ik x y = - if get_interval_narrow_by_meet () then - meet ik x y - else - narrow ik x y - - let log f ~annihilator ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, _ when x = annihilator -> of_bool ik annihilator - | _, Some y when y = annihilator -> of_bool ik annihilator - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) ~annihilator:true - let c_logand = log (&&) ~annihilator:false - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let bit f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - let bitcomp f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{underflow=false; overflow=false})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let logxor = bit (fun _ik -> Ints_t.logxor) - - let logand ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (Ints_t.logand x y) |> fst with Division_by_zero -> top_of ik) - | _, Some y when Ints_t.equal y Ints_t.zero -> of_int ik Ints_t.zero |> fst - | _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst - | _ -> top_of ik - - let logor = bit (fun _ik -> Ints_t.logor) - - let bit1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_int i1 with - | Some x -> of_int ik (f ik x) |> fst - | _ -> top_of ik - - let lognot = bit1 (fun _ik -> Ints_t.lognot) - let shift_right = bitcomp (fun _ik x y -> Ints_t.shift_right x (Ints_t.to_int y)) - - let neg ?no_ov ik = function None -> (None,{underflow=false; overflow=false}) | Some x -> norm ik @@ Some (IArith.neg x) - - let binary_op_with_norm ?no_ov op ik x y = match x, y with - | None, None -> (None, {overflow=false; underflow= false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some x, Some y -> norm ik @@ Some (op x y) - - let add ?no_ov = binary_op_with_norm IArith.add - let mul ?no_ov = binary_op_with_norm IArith.mul - let sub ?no_ov = binary_op_with_norm IArith.sub - - let shift_left ik a b = - match is_bot a, is_bot b with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show a) (show b))) - | _ -> - match a, minimal b, maximal b with - | Some a, Some bl, Some bu when (Ints_t.compare bl Ints_t.zero >= 0) -> - (try - let r = IArith.shift_left a (Ints_t.to_int bl, Ints_t.to_int bu) in - norm ik @@ Some r - with Z.Overflow -> (top_of ik,{underflow=false; overflow=true})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let rem ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (xl, xu), Some (yl, yu) -> - if is_top_of ik x && is_top_of ik y then - (* This is needed to preserve soundness also on things bigger than int32 e.g. *) - (* x: 3803957176L -> T in Interval32 *) - (* y: 4209861404L -> T in Interval32 *) - (* x % y: 3803957176L -> T in Interval32 *) - (* T in Interval32 is [-2147483648,2147483647] *) - (* the code below computes [-2147483647,2147483647] for this though which is unsound *) - top_of ik - else - (* If we have definite values, Ints_t.rem will give a definite result. - * Otherwise we meet with a [range] the result can be in. - * This range is [0, min xu b] if x is positive, and [max xl -b, min xu b] if x can be negative. - * The precise bound b is one smaller than the maximum bound. Negative y give the same result as positive. *) - let pos x = if Ints_t.compare x Ints_t.zero < 0 then Ints_t.neg x else x in - let b = Ints_t.sub (Ints_t.max (pos yl) (pos yu)) Ints_t.one in - let range = if Ints_t.compare xl Ints_t.zero>= 0 then Some (Ints_t.zero, Ints_t.min xu b) else Some (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit (fun _ik -> Ints_t.rem) ik x y) range - - let rec div ?no_ov ik x y = - match x, y with - | None, None -> (bot (),{underflow=false; overflow=false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | (Some (x1,x2) as x), (Some (y1,y2) as y) -> - begin - let is_zero v = Ints_t.compare v Ints_t.zero = 0 in - match y1, y2 with - | l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false}) (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2)) - | _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one))) - | _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false}) - | _ -> binary_op_with_norm IArith.div ik x y - end - - let ne ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik true - else if Ints_t.compare x2 y1 <= 0 && Ints_t.compare y2 x1 <= 0 then - of_bool ik false - else top_bool - - let eq ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 && Ints_t.compare x2 y1 <= 0 then - of_bool ik true - else if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik false - else top_bool - - let ge ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 then of_bool ik true - else if Ints_t.compare x2 y1 < 0 then of_bool ik false - else top_bool - - let le ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 <= 0 then of_bool ik true - else if Ints_t.compare y2 x1 < 0 then of_bool ik false - else top_bool - - let gt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 then of_bool ik true - else if Ints_t.compare x2 y1 <= 0 then of_bool ik false - else top_bool - - let lt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 < 0 then of_bool ik true - else if Ints_t.compare y2 x1 <= 0 then of_bool ik false - else top_bool - - let invariant_ikind e ik = function - | Some (x1, x2) -> - let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in - IntInvariant.of_interval e ik (x1', x2') - | None -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let shrink = function - | Some (l, u) -> (return None) <+> (GobQCheck.shrink pair_arb (l, u) >|= of_interval ik >|= fst) - | None -> empty - in - QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) (fun x -> of_interval ik x |> fst ) pair_arb) - - let modulo n k = - let result = Ints_t.rem n k in - if Ints_t.compare result Ints_t.zero >= 0 then result - else Ints_t.add result k - - let refine_with_congruence ik (intv : t) (cong : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if Ints_t.equal m Ints_t.zero && (Ints_t.compare c x < 0 || Ints_t.compare c y > 0) then None - else if Ints_t.equal m Ints_t.zero then - Some (c, c) - else - let (min_ik, max_ik) = range ik in - let rcx = - if Ints_t.equal x min_ik then x else - Ints_t.add x (modulo (Ints_t.sub c x) (Ints_t.abs m)) in - let lcy = - if Ints_t.equal y max_ik then y else - Ints_t.sub y (modulo (Ints_t.sub y c) (Ints_t.abs m)) in - if Ints_t.compare rcx lcy > 0 then None - else if Ints_t.equal rcx lcy then norm ik @@ Some (rcx, rcx) |> fst - else norm ik @@ Some (rcx, lcy) |> fst - | _ -> None - - let refine_with_congruence ik x y = - let refn = refine_with_congruence ik x y in - if M.tracing then M.trace "refine" "int_refine_with_congruence %a %a -> %a" pretty x pretty y pretty refn; - refn - - let refine_with_interval ik a b = meet ik a b - - let refine_with_excl_list ik (intv : t) (excl : (int_t list * (int64 * int64)) option) : t = - match intv, excl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls, (rl, rh)) -> - let rec shrink op b = - let new_b = (op b (Ints_t.of_int(Bool.to_int(BatList.mem_cmp Ints_t.compare b ls)))) in - if not (Ints_t.equal b new_b) then shrink op new_b else new_b - in - let (min_ik, max_ik) = range ik in - let l' = if Ints_t.equal l min_ik then l else shrink Ints_t.add l in - let u' = if Ints_t.equal u max_ik then u else shrink Ints_t.sub u in - let intv' = norm ik @@ Some (l', u') |> fst in - let range = norm ~suppress_ovwarn:true ik (Some (Ints_t.of_bigint (Size.min_from_bit_range rl), Ints_t.of_bigint (Size.max_from_bit_range rh))) |> fst in - meet ik intv' range - - let refine_with_incl_list ik (intv: t) (incl : (int_t list) option) : t = - match intv, incl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls) -> - let rec min m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> min (Some x) xs | Some m -> if Ints_t.compare m x < 0 then min (Some m) xs else min (Some x) xs in - let rec max m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> max (Some x) xs | Some m -> if Ints_t.compare m x > 0 then max (Some m) xs else max (Some x) xs in - match min None ls, max None ls with - | Some m1, Some m2 -> refine_with_interval ik (Some(l, u)) (Some (m1, m2)) - | _, _-> intv - - let project ik p t = t -end - -(** IntervalSetFunctor that is not just disjunctive completion of intervals, but attempts to be precise for wraparound arithmetic for unsigned types *) -module IntervalSetFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) list = -struct - - module Interval = IntervalFunctor (Ints_t) - module IArith = IntervalArith (Ints_t) - - - let name () = "interval_sets" - - type int_t = Ints_t.t - - let (>.) a b = Ints_t.compare a b > 0 - let (=.) a b = Ints_t.compare a b = 0 - let (<.) a b = Ints_t.compare a b < 0 - let (>=.) a b = Ints_t.compare a b >= 0 - let (<=.) a b = Ints_t.compare a b <= 0 - let (+.) a b = Ints_t.add a b - let (-.) a b = Ints_t.sub a b - - (* - Each domain's element is guaranteed to be in canonical form. That is, each interval contained - inside the set does not overlap with each other and they are not adjacent. - *) - type t = (Ints_t.t * Ints_t.t) list [@@deriving eq, hash, ord] - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - - let top_of ik = [range ik] - - let bot () = [] - - let bot_of ik = bot () - - let show (x: t) = - let show_interval i = Printf.sprintf "[%s, %s]" (Ints_t.to_string (fst i)) (Ints_t.to_string (snd i)) in - List.fold_left (fun acc i -> (show_interval i) :: acc) [] x |> List.rev |> String.concat ", " |> Printf.sprintf "[%s]" - - (* New type definition for the sweeping line algorithm used for implementing join/meet functions. *) - type event = Enter of Ints_t.t | Exit of Ints_t.t - - let unbox_event = function Enter x -> x | Exit x -> x - - let cmp_events x y = - (* Deliberately comparing ints first => Cannot be derived *) - let res = Ints_t.compare (unbox_event x) (unbox_event y) in - if res <> 0 then res - else - begin - match (x, y) with - | (Enter _, Exit _) -> -1 - | (Exit _, Enter _) -> 1 - | (_, _) -> 0 - end - - let interval_set_to_events (xs: t) = - List.concat_map (fun (a, b) -> [Enter a; Exit b]) xs - - let two_interval_sets_to_events (xs: t) (ys: t) = - let xs = interval_set_to_events xs in - let ys = interval_set_to_events ys in - List.merge cmp_events xs ys - - (* Using the sweeping line algorithm, combined_event_list returns a new event list representing the intervals in which at least n intervals in xs overlap - This function is used for both join and meet operations with different parameter n: 1 for join, 2 for meet *) - let combined_event_list lattice_op (xs:event list) = - let l = match lattice_op with `Join -> 1 | `Meet -> 2 in - let aux (interval_count, acc) = function - | Enter x -> (interval_count + 1, if (interval_count + 1) >= l && interval_count < l then (Enter x)::acc else acc) - | Exit x -> (interval_count - 1, if interval_count >= l && (interval_count - 1) < l then (Exit x)::acc else acc) - in - List.fold_left aux (0, []) xs |> snd |> List.rev - - let rec events_to_intervals = function - | [] -> [] - | (Enter x)::(Exit y)::xs -> (x, y)::(events_to_intervals xs) - | _ -> failwith "Invalid events list" - - let remove_empty_gaps (xs: t) = - let aux acc (l, r) = match acc with - | ((a, b)::acc') when (b +. Ints_t.one) >=. l -> (a, r)::acc' - | _ -> (l, r)::acc - in - List.fold_left aux [] xs |> List.rev - - let canonize (xs: t) = - interval_set_to_events xs |> - List.sort cmp_events |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let unop (x: t) op = match x with - | [] -> [] - | _ -> canonize @@ List.concat_map op x - - let binop (x: t) (y: t) op : t = match x, y with - | [], _ -> [] - | _, [] -> [] - | _, _ -> canonize @@ List.concat_map op (BatList.cartesian_product x y) - - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let minimal = function - | [] -> None - | (x, _)::_ -> Some x - - let maximal = function - | [] -> None - | xs -> Some (BatList.last xs |> snd) - - let equal_to_interval i (a, b) = - if a =. b && b =. i then - `Eq - else if a <=. i && i <=. b then - `Top - else - `Neq - - let equal_to i xs = match List.map (equal_to_interval i) xs with - | [] -> failwith "unsupported: equal_to with bottom" - | [`Eq] -> `Eq - | ys when List.for_all ((=) `Neq) ys -> `Neq - | _ -> `Top - - let norm_interval ?(suppress_ovwarn=false) ?(cast=false) ik (x,y) : t*overflow_info = - if x >. y then - ([],{underflow=false; overflow=false}) - else - let (min_ik, max_ik) = range ik in - let underflow = min_ik >. x in - let overflow = max_ik <. y in - let v = if underflow || overflow then - begin - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (max_ik -. min_ik) in - let resdiff = Ints_t.abs (y -. x) in - if resdiff >. diff then - [range ik] - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if l <=. u then - [(l, u)] - else - (* Interval that wraps around (begins to the right of its end). We CAN represent such intervals *) - [(min_ik, u); (l, max_ik)] - else if not cast && should_ignore_overflow ik then - [Ints_t.max min_ik x, Ints_t.min max_ik y] - else - [range ik] - end - else - [(x,y)] - in - if suppress_ovwarn then (v, {underflow=false; overflow=false}) else (v, {underflow; overflow}) - - let norm_intvs ?(suppress_ovwarn=false) ?(cast=false) (ik:ikind) (xs: t) : t*overflow_info = - let res = List.map (norm_interval ~suppress_ovwarn ~cast ik) xs in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let binary_op_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> [op x y]) (BatList.cartesian_product x y) - - let binary_op_with_ovc (x: t) (y: t) op : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> - let res = List.map op (BatList.cartesian_product x y) in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let unary_op_with_norm op (ik:ikind) (x: t) = match x with - | [] -> ([],{overflow=false; underflow=false}) - | _ -> norm_intvs ik @@ List.concat_map (fun x -> [op x]) x - - let rec leq (xs: t) (ys: t) = - let leq_interval (al, au) (bl, bu) = al >=. bl && au <=. bu in - match xs, ys with - | [], _ -> true - | _, [] -> false - | (xl,xr)::xs', (yl,yr)::ys' -> - if leq_interval (xl,xr) (yl,yr) then - leq xs' ys - else if xr <. yl then - false - else - leq xs ys' - - let join ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let meet ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Meet |> - events_to_intervals - - let to_int = function - | [x] -> IArith.to_int x - | _ -> None - - let zero = [IArith.zero] - let one = [IArith.one] - let top_bool = [IArith.top_bool] - - let not_bool (x:t) = - let is_false x = equal x zero in - let is_true x = equal x one in - if is_true x then zero else if is_false x then one else top_bool - - let to_bool = function - | [(l,u)] when l =. Ints_t.zero && u =. Ints_t.zero -> Some false - | x -> if leq zero x then None else Some true - - let of_bool _ = function true -> one | false -> zero - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm_interval ~suppress_ovwarn ~cast:false ik (x,y) - - let of_int ik (x: int_t) = of_interval ik (x, x) - - let lt ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <. min_y then - of_bool ik true - else if min_x >=. max_y then - of_bool ik false - else - top_bool - - let le ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <=. min_y then - of_bool ik true - else if min_x >. max_y then - of_bool ik false - else - top_bool - - let gt ik x y = not_bool @@ le ik x y - - let ge ik x y = not_bool @@ lt ik x y - - let eq ik x y = match x, y with - | (a, b)::[], (c, d)::[] when a =. b && c =. d && a =. c -> - one - | _ -> - if is_bot (meet ik x y) then - zero - else - top_bool - - let ne ik x y = not_bool @@ eq ik x y - let interval_to_int i = Interval.to_int (Some i) - let interval_to_bool i = Interval.to_bool (Some i) - - let log f ik (i1, i2) = - match (interval_to_bool i1, interval_to_bool i2) with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - - let bit f ik (i1, i2) = - match (interval_to_int i1), (interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - - let bitcomp f ik (i1, i2) = - match (interval_to_int i1, interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{overflow=false; underflow=false})) - | _, _ -> (top_of ik,{overflow=false; underflow=false}) - - let logand ik x y = - let interval_logand = bit Ints_t.logand ik in - binop x y interval_logand - - let logor ik x y = - let interval_logor = bit Ints_t.logor ik in - binop x y interval_logor - - let logxor ik x y = - let interval_logxor = bit Ints_t.logxor ik in - binop x y interval_logxor - - let lognot ik x = - let interval_lognot i = - match interval_to_int i with - | Some x -> of_int ik (Ints_t.lognot x) |> fst - | _ -> top_of ik - in - unop x interval_lognot - - let shift_left ik x y = - let interval_shiftleft = bitcomp (fun x y -> Ints_t.shift_left x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftleft - - let shift_right ik x y = - let interval_shiftright = bitcomp (fun x y -> Ints_t.shift_right x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftright - - let c_lognot ik x = - let log1 f ik i1 = - match interval_to_bool i1 with - | Some x -> of_bool ik (f x) - | _ -> top_of ik - in - let interval_lognot = log1 not ik in - unop x interval_lognot - - let c_logand ik x y = - let interval_logand = log (&&) ik in - binop x y interval_logand - - let c_logor ik x y = - let interval_logor = log (||) ik in - binop x y interval_logor - - let add ?no_ov = binary_op_with_norm IArith.add - let sub ?no_ov = binary_op_with_norm IArith.sub - let mul ?no_ov = binary_op_with_norm IArith.mul - let neg ?no_ov = unary_op_with_norm IArith.neg - - let div ?no_ov ik x y = - let rec interval_div x (y1, y2) = begin - let top_of ik = top_of ik |> List.hd in - let is_zero v = v =. Ints_t.zero in - match y1, y2 with - | l, u when is_zero l && is_zero u -> top_of ik (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> interval_div x (Ints_t.one,y2) - | _, u when is_zero u -> interval_div x (y1, Ints_t.(neg one)) - | _ when leq (of_int ik (Ints_t.zero) |> fst) ([(y1,y2)]) -> top_of ik - | _ -> IArith.div x (y1, y2) - end - in binary_op_with_norm interval_div ik x y - - let rem ik x y = - let interval_rem (x, y) = - if Interval.is_top_of ik (Some x) && Interval.is_top_of ik (Some y) then - top_of ik - else - let (xl, xu) = x in let (yl, yu) = y in - let pos x = if x <. Ints_t.zero then Ints_t.neg x else x in - let b = (Ints_t.max (pos yl) (pos yu)) -. Ints_t.one in - let range = if xl >=. Ints_t.zero then (Ints_t.zero, Ints_t.min xu b) else (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit Ints_t.rem ik (x, y)) [range] - in - binop x y interval_rem - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik x = norm_intvs ~cast:true ik x - - (* - narrows down the extremeties of xs if they are equal to boundary values of the ikind with (possibly) narrower values from ys - *) - let narrow ik xs ys = match xs ,ys with - | [], _ -> [] | _ ,[] -> xs - | _, _ -> - let min_xs = minimal xs |> Option.get in - let max_xs = maximal xs |> Option.get in - let min_ys = minimal ys |> Option.get in - let max_ys = maximal ys |> Option.get in - let min_range,max_range = range ik in - let threshold = get_interval_threshold_widening () in - let min = if min_xs =. min_range || threshold && min_ys >. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in - let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in - xs - |> (function (_, y)::z -> (min, y)::z | _ -> []) - |> List.rev - |> (function (x, _)::z -> (x, max)::z | _ -> []) - |> List.rev - - (* - 1. partitions the intervals of xs by assigning each of them to the an interval in ys that includes it. - and joins all intervals in xs assigned to the same interval in ys as one interval. - 2. checks for every pair of adjacent pairs whether the pairs did approach (if you compare the intervals from xs and ys) and merges them if it is the case. - 3. checks whether partitions at the extremeties are approaching infinity (and expands them to infinity. in that case) - - The expansion (between a pair of adjacent partitions or at extremeties ) stops at a threshold. - *) - let widen ik xs ys = - let (min_ik,max_ik) = range ik in - let threshold = get_bool "ana.int.interval_threshold_widening" in - let upper_threshold (_,u) = IArith.upper_threshold u max_ik in - let lower_threshold (l,_) = IArith.lower_threshold l min_ik in - (*obtain partitioning of xs intervals according to the ys interval that includes them*) - let rec interval_sets_to_partitions (ik: ikind) (acc : (int_t * int_t) option) (xs: t) (ys: t)= - match xs,ys with - | _, [] -> [] - | [], (y::ys) -> (acc,y):: interval_sets_to_partitions ik None [] ys - | (x::xs), (y::ys) when Interval.leq (Some x) (Some y) -> interval_sets_to_partitions ik (Interval.join ik acc (Some x)) xs (y::ys) - | (x::xs), (y::ys) -> (acc,y) :: interval_sets_to_partitions ik None (x::xs) ys - in - let interval_sets_to_partitions ik xs ys = interval_sets_to_partitions ik None xs ys in - (*merge a pair of adjacent partitions*) - let merge_pair ik (a,b) (c,d) = - let new_a = function - | None -> Some (upper_threshold b, upper_threshold b) - | Some (ax,ay) -> Some (ax, upper_threshold b) - in - let new_c = function - | None -> Some (lower_threshold d, lower_threshold d) - | Some (cx,cy) -> Some (lower_threshold d, cy) - in - if threshold && (lower_threshold d +. Ints_t.one) >. (upper_threshold b) then - [(new_a a,(fst b, upper_threshold b)); (new_c c, (lower_threshold d, snd d))] - else - [(Interval.join ik a c, (Interval.join ik (Some b) (Some d) |> Option.get))] - in - let partitions_are_approaching part_left part_right = match part_left, part_right with - | (Some (_, left_x), (_, left_y)), (Some (right_x, _), (right_y, _)) -> (right_x -. left_x) >. (right_y -. left_y) - | _,_ -> false - in - (*merge all approaching pairs of adjacent partitions*) - let rec merge_list ik = function - | [] -> [] - | x::y::xs when partitions_are_approaching x y -> merge_list ik ((merge_pair ik x y) @ xs) - | x::xs -> x :: merge_list ik xs - in - (*expands left extremity*) - let widen_left = function - | [] -> [] - | (None,(lb,rb))::ts -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (None, (lt,rb))::ts - | (Some (la,ra), (lb,rb))::ts when lb <. la -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (Some (la,ra),(lt,rb))::ts - | x -> x - in - (*expands right extremity*) - let widen_right x = - let map_rightmost = function - | [] -> [] - | (None,(lb,rb))::ts -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (None, (lb,ut))::ts - | (Some (la,ra), (lb,rb))::ts when ra <. rb -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (Some (la,ra),(lb,ut))::ts - | x -> x - in - List.rev x |> map_rightmost |> List.rev - in - interval_sets_to_partitions ik xs ys |> merge_list ik |> widen_left |> widen_right |> List.map snd - - let starting ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (fst (range ik), n) - - let invariant_ikind e ik xs = - List.map (fun x -> Interval.invariant_ikind e ik (Some x)) xs |> - let open Invariant in List.fold_left (||) (bot ()) - - let modulo n k = - let result = Ints_t.rem n k in - if result >=. Ints_t.zero then result - else result +. k - - let refine_with_congruence ik (intvs: t) (cong: (int_t * int_t ) option): t = - let refine_with_congruence_interval ik (cong : (int_t * int_t ) option) (intv : (int_t * int_t ) option): t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =. Ints_t.zero && (c <. x || c >. y) then [] - else if m =. Ints_t.zero then - [(c, c)] - else - let (min_ik, max_ik) = range ik in - let rcx = - if x =. min_ik then x else - x +. (modulo (c -. x) (Ints_t.abs m)) in - let lcy = - if y =. max_ik then y else - y -. (modulo (y -. c) (Ints_t.abs m)) in - if rcx >. lcy then [] - else if rcx =. lcy then norm_interval ik (rcx, rcx) |> fst - else norm_interval ik (rcx, lcy) |> fst - | _ -> [] - in - List.concat_map (fun x -> refine_with_congruence_interval ik cong (Some x)) intvs - - let refine_with_interval ik xs = function None -> [] | Some (a,b) -> meet ik xs [(a,b)] - - let refine_with_incl_list ik intvs = function - | None -> intvs - | Some xs -> meet ik intvs (List.map (fun x -> (x,x)) xs) - - let excl_range_to_intervalset (ik: ikind) ((min, max): int_t * int_t) (excl: int_t): t = - let intv1 = (min, excl -. Ints_t.one) in - let intv2 = (excl +. Ints_t.one, max) in - norm_intvs ik ~suppress_ovwarn:true [intv1 ; intv2] |> fst - - let of_excl_list ik (excls: int_t list) = - let excl_list = List.map (excl_range_to_intervalset ik (range ik)) excls in - let res = List.fold_left (meet ik) (top_of ik) excl_list in - res - - let refine_with_excl_list ik (intv : t) = function - | None -> intv - | Some (xs, range) -> - let excl_to_intervalset (ik: ikind) ((rl, rh): (int64 * int64)) (excl: int_t): t = - excl_range_to_intervalset ik (Ints_t.of_bigint (Size.min_from_bit_range rl),Ints_t.of_bigint (Size.max_from_bit_range rh)) excl - in - let excl_list = List.map (excl_to_intervalset ik range) xs in - List.fold_left (meet ik) intv excl_list - - let project ik p t = t - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let list_pair_arb = QCheck.small_list pair_arb in - let canonize_randomly_generated_list = (fun x -> norm_intvs ik x |> fst) in - let shrink xs = GobQCheck.shrink list_pair_arb xs >|= canonize_randomly_generated_list - in QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) canonize_randomly_generated_list list_pair_arb) -end - -module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct - include D - - let add ?no_ov ik x y = fst @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = fst @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = fst @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = fst @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = fst @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = fst @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = fst @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = fst @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = fst @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = fst @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = fst @@ D.shift_left ik x y - - let shift_right ik x y = fst @@ D.shift_right ik x y -end - -module IntIkind = struct let ikind () = Cil.IInt end -module Interval = IntervalFunctor (IntOps.BigIntOps) -module Interval32 = IntDomWithDefaultIkind (IntDomLifter (SOverflowUnlifter (IntervalFunctor (IntOps.Int64Ops)))) (IntIkind) -module IntervalSet = IntervalSetFunctor (IntOps.BigIntOps) -module Integers (Ints_t : IntOps.IntOps): IkindUnawareS with type t = Ints_t.t and type int_t = Ints_t.t = (* no top/bot, order is <= *) -struct - include Printable.Std - let name () = "integers" - type t = Ints_t.t [@@deriving eq, ord, hash] - type int_t = Ints_t.t - let top () = raise Unknown - let bot () = raise Error - let top_of ik = top () - let bot_of ik = bot () - let show (x: Ints_t.t) = Ints_t.to_string x - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - (* is_top and is_bot are never called, but if they were, the Std impl would raise their exception, so we overwrite them: *) - let is_top _ = false - let is_bot _ = false - - let equal_to i x = if i > x then `Neq else `Top - let leq x y = x <= y - let join x y = if Ints_t.compare x y > 0 then x else y - let widen = join - let meet x y = if Ints_t.compare x y > 0 then y else x - let narrow = meet - - let of_bool x = if x then Ints_t.one else Ints_t.zero - let to_bool' x = x <> Ints_t.zero - let to_bool x = Some (to_bool' x) - let of_int x = x - let to_int x = Some x - - let neg = Ints_t.neg - let add = Ints_t.add (* TODO: signed overflow is undefined behavior! *) - let sub = Ints_t.sub - let mul = Ints_t.mul - let div = Ints_t.div - let rem = Ints_t.rem - let lt n1 n2 = of_bool (n1 < n2) - let gt n1 n2 = of_bool (n1 > n2) - let le n1 n2 = of_bool (n1 <= n2) - let ge n1 n2 = of_bool (n1 >= n2) - let eq n1 n2 = of_bool (n1 = n2) - let ne n1 n2 = of_bool (n1 <> n2) - let lognot = Ints_t.lognot - let logand = Ints_t.logand - let logor = Ints_t.logor - let logxor = Ints_t.logxor - let shift_left n1 n2 = Ints_t.shift_left n1 (Ints_t.to_int n2) - let shift_right n1 n2 = Ints_t.shift_right n1 (Ints_t.to_int n2) - let c_lognot n1 = of_bool (not (to_bool' n1)) - let c_logand n1 n2 = of_bool ((to_bool' n1) && (to_bool' n2)) - let c_logor n1 n2 = of_bool ((to_bool' n1) || (to_bool' n2)) - let cast_to ?(suppress_ovwarn=false) ?torg t x = failwith @@ "Cast_to not implemented for " ^ (name ()) ^ "." - let arbitrary ik = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 (* TODO: use ikind *) - let invariant _ _ = Invariant.none (* TODO *) -end - -module FlatPureIntegers: IkindUnawareS with type t = int64 and type int_t = int64 = (* Integers, but raises Unknown/Error on join/meet *) -struct - include Integers(IntOps.Int64Ops) - let top () = raise Unknown - let bot () = raise Error - let leq = equal - let pretty_diff () (x,y) = Pretty.dprintf "Integer %a instead of %a" pretty x pretty y - let join x y = if equal x y then x else top () - let meet x y = if equal x y then x else bot () -end - -module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) -struct - type int_t = Base.int_t - include Lattice.FlatConf (struct - include Printable.DefaultConf - let top_name = "Unknown int" - let bot_name = "Error int" - end) (Base) - - let top_of ik = top () - let bot_of ik = bot () - - - let name () = "flat integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ikind x = top_of ikind - let ending ?(suppress_ovwarn=false) ikind x = top_of ikind - let maximal x = None - let minimal x = None - - let lift1 f x = match x with - | `Lifted x -> - (try `Lifted (f x) with Unknown -> `Top | Error -> `Bot) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> - (try `Lifted (f x y) with Unknown -> `Top | Error -> `Bot) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) -struct - include Lattice.LiftPO (struct - include Printable.DefaultConf - let top_name = "MaxInt" - let bot_name = "MinInt" - end) (Base) - type int_t = Base.int_t - let top_of ik = top () - let bot_of ik = bot () - include StdTop (struct type nonrec t = t let top_of = top_of end) - - let name () = "lifted integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let lift1 f x = match x with - | `Lifted x -> `Lifted (f x) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> `Lifted (f x y) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Flattened = Flat (Integers (IntOps.Int64Ops)) -module Lifted = Lift (Integers (IntOps.Int64Ops)) - -module Reverse (Base: IkindUnawareS) = -struct - include Base - include (Lattice.Reverse (Base) : Lattice.S with type t := Base.t) -end - -module BISet = struct - include SetDomain.Make (IntOps.BigIntOps) - let is_singleton s = cardinal s = 1 -end - -(* The module [Exclusion] constains common functionality about handling of exclusion sets between [DefExc] and [Enums] *) -module Exclusion = -struct - module R = Interval32 - (* We use these types for the functions in this module to make the intended meaning more explicit *) - type t = Exc of BISet.t * Interval32.t - type inc = Inc of BISet.t [@@unboxed] - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.succ (Z.add (Z.neg (min_of_range r)) (max_of_range r)) - - let cardinality_BISet s = - Z.of_int (BISet.cardinal s) - - let leq_excl_incl (Exc (xs, r)) (Inc ys) = - (* For a <= b to hold, the cardinalities must fit, i.e. |a| <= |b|, which implies |min_r, max_r| - |xs| <= |ys|. We check this first. *) - let lower_bound_cardinality_a = Z.sub (cardinality_of_range r) (cardinality_BISet xs) in - let card_b = cardinality_BISet ys in - if Z.compare lower_bound_cardinality_a card_b > 0 then - false - else (* The cardinality did fit, so we check for all elements that are represented by range r, whether they are in (xs union ys) *) - let min_a = min_of_range r in - let max_a = max_of_range r in - GobZ.for_all_range (fun el -> BISet.mem el xs || BISet.mem el ys) (min_a, max_a) - - let leq (Exc (xs, r)) (Exc (ys, s)) = - let min_a, max_a = min_of_range r, max_of_range r in - let excluded_check = BISet.for_all (fun y -> BISet.mem y xs || Z.compare y min_a < 0 || Z.compare y max_a > 0) ys in (* if true, then the values ys, that are not in b, also do not occur in a *) - if not excluded_check - then false - else begin (* Check whether all elements that are in the range r, but not in s, are in xs, i.e. excluded. *) - if R.leq r s then true - else begin if Z.compare (cardinality_BISet xs) (Z.sub (cardinality_of_range r) (cardinality_of_range s)) >= 0 (* Check whether the number of excluded elements in a is as least as big as |min_r, max_r| - |min_s, max_s| *) - then - let min_b, max_b = min_of_range s, max_of_range s in - let leq1 = (* check whether the elements in [r_l; s_l-1] are all in xs, i.e. excluded *) - if Z.compare min_a min_b < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (min_a, Z.pred min_b) - else - true - in - let leq2 () = (* check whether the elements in [s_u+1; r_u] are all in xs, i.e. excluded *) - if Z.compare max_b max_a < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (Z.succ max_b, max_a) - else - true - in - leq1 && (leq2 ()) - else - false - end - end -end - -module DefExc : S with type int_t = Z.t = (* definite or set of excluded values *) -struct - module S = BISet - module R = Interval32 (* range for exclusion *) - - (* Ikind used for intervals representing the domain *) - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - - type t = [ - | `Excluded of S.t * R.t - | `Definite of Z.t - | `Bot - ] [@@deriving eq, ord, hash] - type int_t = Z.t - let name () = "def_exc" - - - let top_range = R.of_interval range_ikind (-99L, 99L) (* Since there is no top ikind we use a range that includes both ILongLong [-63,63] and IULongLong [0,64]. Only needed for intermediate range computation on longs. Correct range is set by cast. *) - let top () = `Excluded (S.empty (), top_range) - let bot () = `Bot - let top_of ik = `Excluded (S.empty (), size ik) - let bot_of ik = bot () - - let show x = - let short_size x = "("^R.show x^")" in - match x with - | `Bot -> "Error int" - | `Definite x -> Z.to_string x - (* Print the empty exclusion as if it was a distinct top element: *) - | `Excluded (s,l) when S.is_empty s -> "Unknown int" ^ short_size l - (* Prepend the exclusion sets with something: *) - | `Excluded (s,l) -> "Not " ^ S.show s ^ short_size l - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let maximal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.max_of_range r) - | `Bot -> None - - let minimal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.min_of_range r) - | `Bot -> None - - let in_range r i = - if Z.compare i Z.zero < 0 then - let lowerb = Exclusion.min_of_range r in - Z.compare lowerb i <= 0 - else - let upperb = Exclusion.max_of_range r in - Z.compare i upperb <= 0 - - let is_top x = x = top () - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Definite x -> if i = x then `Eq else `Neq - | `Excluded (s,r) -> if S.mem i s then `Neq else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik = function - | `Excluded (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - `Excluded (s, r) - else if ik = IBool then (* downcast to bool *) - if S.mem Z.zero s then - `Definite Z.one - else - `Excluded (S.empty(), r') - else - (* downcast: may overflow *) - (* let s' = S.map (Size.cast ik) s in *) - (* We want to filter out all i in s' where (t)x with x in r could be i. *) - (* Since this is hard to compute, we just keep all i in s' which overflowed, since those are safe - all i which did not overflow may now be possible due to overflow of r. *) - (* S.diff s' s, r' *) - (* The above is needed for test 21/03, but not sound! See example https://github.com/goblint/analyzer/pull/95#discussion_r483023140 *) - `Excluded (S.empty (), r') - | `Definite x -> `Definite (Size.cast ik x) - | `Bot -> `Bot - - (* Wraps definite values and excluded values according to the ikind. - * For an `Excluded s,r , assumes that r is already an overapproximation of the range of possible values. - * r might be larger than the possible range of this type; the range of the returned `Excluded set will be within the bounds of the ikind. - *) - let norm ik v = - match v with - | `Excluded (s, r) -> - let possibly_overflowed = not (R.leq r (size ik)) || not (S.for_all (in_range (size ik)) s) in - (* If no overflow occurred, just return x *) - if not possibly_overflowed then ( - v - ) - (* Else, if an overflow might have occurred but we should just ignore it *) - else if should_ignore_overflow ik then ( - let r = size ik in - (* filter out excluded elements that are not in the range *) - let mapped_excl = S.filter (in_range r) s in - `Excluded (mapped_excl, r) - ) - (* Else, if an overflow occurred that we should not treat with wrap-around, go to top *) - else if not (should_wrap ik) then ( - top_of ik - ) else ( - (* Else an overflow occurred that we should treat with wrap-around *) - let r = size ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - let mapped_excl = S.map (fun excl -> Size.cast ik excl) s in - match ik with - | IBool -> - begin match S.mem Z.zero mapped_excl, S.mem Z.one mapped_excl with - | false, false -> `Excluded (mapped_excl, r) (* Not {} -> Not {} *) - | true, false -> `Definite Z.one (* Not {0} -> 1 *) - | false, true -> `Definite Z.zero (* Not {1} -> 0 *) - | true, true -> `Bot (* Not {0, 1} -> bot *) - end - | ik -> - `Excluded (mapped_excl, r) - ) - | `Definite x -> - let min, max = Size.range ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - if should_wrap ik then ( - cast_to ik v - ) - else if Z.compare min x <= 0 && Z.compare x max <= 0 then ( - v - ) - else if should_ignore_overflow ik then ( - M.warn ~category:M.Category.Integer.overflow "DefExc: Value was outside of range, indicating overflow, but 'sem.int.signed_overflow' is 'assume_none' -> Returned Bot"; - `Bot - ) - else ( - top_of ik - ) - | `Bot -> `Bot - - let leq x y = match (x,y) with - (* `Bot <= x is always true *) - | `Bot, _ -> true - (* Anything except bot <= bot is always false *) - | _, `Bot -> false - (* Two known values are leq whenever equal *) - | `Definite (x: int_t), `Definite y -> x = y - (* A definite value is leq all exclusion sets that don't contain it *) - | `Definite x, `Excluded (s,r) -> in_range r x && not (S.mem x s) - (* No finite exclusion set can be leq than a definite value *) - | `Excluded (xs, xr), `Definite d -> - Exclusion.(leq_excl_incl (Exc (xs, xr)) (Inc (S.singleton d))) - | `Excluded (xs,xr), `Excluded (ys,yr) -> - Exclusion.(leq (Exc (xs,xr)) (Exc (ys, yr))) - - let join' ?range ik x y = - match (x,y) with - (* The least upper bound with the bottom element: *) - | `Bot, x -> x - | x, `Bot -> x - (* The case for two known values: *) - | `Definite (x: int_t), `Definite y -> - (* If they're equal, it's just THAT value *) - if x = y then `Definite x - (* Unless one of them is zero, we can exclude it: *) - else - let a,b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval range_ikind a) (R.of_interval range_ikind b) in - `Excluded ((if Z.equal x Z.zero || Z.equal y Z.zero then S.empty () else S.singleton Z.zero), r) - (* A known value and an exclusion set... the definite value should no - * longer be excluded: *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> - if not (in_range r x) then - let a = R.of_interval range_ikind (Size.min_range_sign_agnostic x) in - `Excluded (S.remove x s, R.join a r) - else - `Excluded (S.remove x s, r) - (* For two exclusion sets, only their intersection can be excluded: *) - | `Excluded (x,wx), `Excluded (y,wy) -> `Excluded (S.inter x y, range |? R.join wx wy) - - let join ik = join' ik - - - let widen ik x y = - if get_def_exc_widen_by_join () then - join' ik x y - else if equal x y then - x - else - join' ~range:(size ik) ik x y - - - let meet ik x y = - match (x,y) with - (* Greatest LOWER bound with the least element is trivial: *) - | `Bot, _ -> `Bot - | _, `Bot -> `Bot - (* Definite elements are either equal or the glb is bottom *) - | `Definite x, `Definite y -> if x = y then `Definite x else `Bot - (* The glb of a definite element and an exclusion set is either bottom or - * just the element itself, if it isn't in the exclusion set *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> if S.mem x s || not (in_range r x) then `Bot else `Definite x - (* The greatest lower bound of two exclusion sets is their union, this is - * just DeMorgans Law *) - | `Excluded (x,r1), `Excluded (y,r2) -> - let r' = R.meet r1 r2 in - let s' = S.union x y |> S.filter (in_range r') in - `Excluded (s', r') - - let narrow ik x y = x - - let of_int ik x = norm ik @@ `Definite x - let to_int x = match x with - | `Definite x -> Some x - | _ -> None - - let from_excl ikind (s: S.t) = norm ikind @@ `Excluded (s, size ikind) - - let of_bool_cmp ik x = of_int ik (if x then Z.one else Z.zero) - let of_bool = of_bool_cmp - let to_bool x = - match x with - | `Definite x -> Some (IntOps.BigIntOps.to_bool x) - | `Excluded (s,r) when S.mem Z.zero s -> Some true - | _ -> None - let top_bool = `Excluded (S.empty (), R.of_interval range_ikind (0L, 1L)) - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then S.singleton Z.zero else S.empty () in - norm ik @@ (`Excluded (ex, r)) - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let of_excl_list t l = - let r = size t in (* elements in l are excluded from the full range of t! *) - `Excluded (List.fold_right S.add l (S.empty ()), r) - let is_excl_list l = match l with `Excluded _ -> true | _ -> false - let to_excl_list (x:t) = match x with - | `Definite _ -> None - | `Excluded (s,r) -> Some (S.elements s, (Option.get (R.minimal r), Option.get (R.maximal r))) - | `Bot -> None - - let to_incl_list x = match x with - | `Definite x -> Some [x] - | `Excluded _ -> None - | `Bot -> None - - let apply_range f r = (* apply f to the min/max of the old range r to get a new range *) - (* If the Int64 might overflow on us during computation, we instead go to top_range *) - match R.minimal r, R.maximal r with - | _ -> - let rf m = (size % Size.min_for % f) (m r) in - let r1, r2 = rf Exclusion.min_of_range, rf Exclusion.max_of_range in - R.join r1 r2 - - (* Default behaviour for unary operators, simply maps the function to the - * DefExc data structure. *) - let lift1 f ik x = norm ik @@ match x with - | `Excluded (s,r) -> - let s' = S.map f s in - `Excluded (s', apply_range f r) - | `Definite x -> `Definite (f x) - | `Bot -> `Bot - - let lift2 f ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite _ - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (f x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - (* Default behaviour for binary operators that are injective in either - * argument, so that Exclusion Sets can be used: *) - let lift2_inj f ik x y = - let def_exc f x s r = `Excluded (S.map (f x) s, apply_range (f x) r) in - norm ik @@ - match x,y with - (* If both are exclusion sets, there isn't anything we can do: *) - | `Excluded _, `Excluded _ -> top () - (* A definite value should be applied to all members of the exclusion set *) - | `Definite x, `Excluded (s,r) -> def_exc f x s r - (* Same thing here, but we should flip the operator to map it properly *) - | `Excluded (s,r), `Definite x -> def_exc (Batteries.flip f) x s r - (* The good case: *) - | `Definite x, `Definite y -> `Definite (f x y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The equality check: *) - let eq ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x equal to an exclusion set, if it is a member then NO otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt false else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt false else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x = y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The inequality check: *) - let ne ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x unequal to an exclusion set, if it is a member then Yes otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt true else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt true else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x <> y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - let neg ?no_ov ik (x :t) = norm ik @@ lift1 Z.neg ik x - let add ?no_ov ik x y = norm ik @@ lift2_inj Z.add ik x y - - let sub ?no_ov ik x y = norm ik @@ lift2_inj Z.sub ik x y - let mul ?no_ov ik x y = norm ik @@ match x, y with - | `Definite z, (`Excluded _ | `Definite _) when Z.equal z Z.zero -> x - | (`Excluded _ | `Definite _), `Definite z when Z.equal z Z.zero -> y - | `Definite a, `Excluded (s,r) - (* Integer multiplication with even numbers is not injective. *) - (* Thus we cannot exclude the values to which the exclusion set would be mapped to. *) - | `Excluded (s,r),`Definite a when Z.equal (Z.rem a (Z.of_int 2)) Z.zero -> `Excluded (S.empty (), apply_range (Z.mul a) r) - | _ -> lift2_inj Z.mul ik x y - let div ?no_ov ik x y = lift2 Z.div ik x y - let rem ik x y = lift2 Z.rem ik x y - - (* Comparison handling copied from Enums. *) - let handle_bot x y f = match x, y with - | `Bot, `Bot -> `Bot - | `Bot, _ - | _, `Bot -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> f () - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let lognot = lift1 Z.lognot - - let logand ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite i -> - (* Except in two special cases *) - if Z.equal i Z.zero then - `Definite Z.zero - else if Z.equal i Z.one then - of_interval IBool (Z.zero, Z.one) - else - top () - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (Z.logand x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - norm ik @@ lift2 shift_op_big_int ik x y - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - (* TODO: lift does not treat Not {0} as true. *) - let c_logand ik x y = - match to_bool x, to_bool y with - | Some false, _ - | _, Some false -> - of_bool ik false - | _, _ -> - lift2 IntOps.BigIntOps.c_logand ik x y - let c_logor ik x y = - match to_bool x, to_bool y with - | Some true, _ - | _, Some true -> - of_bool ik true - | _, _ -> - lift2 IntOps.BigIntOps.c_logor ik x y - let c_lognot ik = eq ik (of_int ik Z.zero) - - let invariant_ikind e ik (x:t) = - match x with - | `Definite x -> - IntInvariant.of_int e ik x - | `Excluded (s, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let si = IntInvariant.of_excl_list e ik (S.elements s) in - Invariant.(ri && si) - | `Bot -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - let excluded s = from_excl ik s in - let definite x = of_int ik x in - let shrink = function - | `Excluded (s, _) -> GobQCheck.shrink (S.arbitrary ()) s >|= excluded (* S TODO: possibly shrink excluded to definite *) - | `Definite x -> (return `Bot) <+> (GobQCheck.shrink (IntOps.BigIntOps.arbitrary ()) x >|= definite) - | `Bot -> empty - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map excluded (S.arbitrary ()); - 10, QCheck.map definite (IntOps.BigIntOps.arbitrary ()); - 1, QCheck.always `Bot - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = a - let refine_with_interval ik a b = match a, b with - | x, Some(i) -> meet ik x (of_interval ik i) - | _ -> a - let refine_with_excl_list ik a b = match a, b with - | `Excluded (s, r), Some(ls, _) -> meet ik (`Excluded (s, r)) (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - let refine_with_incl_list ik a b = a - - let project ik p t = t -end - -(* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) -module Enums : S with type int_t = Z.t = struct - module R = Interval32 (* range for exclusion *) - - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - type t = Inc of BISet.t | Exc of BISet.t * R.t [@@deriving eq, ord, hash] (* inclusion/exclusion set *) - - type int_t = Z.t - let name () = "enums" - let bot () = failwith "bot () not implemented for Enums" - let top () = failwith "top () not implemented for Enums" - let bot_of ik = Inc (BISet.empty ()) - let top_bool = Inc (BISet.of_list [Z.zero; Z.one]) - let top_of ik = - match ik with - | IBool -> top_bool - | _ -> Exc (BISet.empty (), size ik) - - let range ik = Size.range ik - -(* - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.add (Z.neg (min_of_range r)) (max_of_range r) *) - let value_in_range (min, max) v = Z.compare min v <= 0 && Z.compare v max <= 0 - - let show = function - | Inc xs when BISet.is_empty xs -> "bot" - | Inc xs -> "{" ^ (String.concat ", " (List.map Z.to_string (BISet.elements xs))) ^ "}" - | Exc (xs,r) -> "not {" ^ (String.concat ", " (List.map Z.to_string (BISet.elements xs))) ^ "} " ^ "("^R.show r^")" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - (* Normalization function for enums, that handles overflows for Inc. - As we do not compute on Excl, we do not have to perform any overflow handling for it. *) - let norm ikind v = - let min, max = range ikind in - (* Whether the value v lies within the values of the specified ikind. *) - let value_in_ikind v = - Z.compare min v <= 0 && Z.compare v max <= 0 - in - match v with - | Inc xs when BISet.for_all value_in_ikind xs -> v - | Inc xs -> - if should_wrap ikind then - Inc (BISet.map (Size.cast ikind) xs) - else if should_ignore_overflow ikind then - Inc (BISet.filter value_in_ikind xs) - else - top_of ikind - | Exc (xs, r) -> - (* The following assert should hold for Exc, therefore we do not have to overflow handling / normalization for it: - let range_in_ikind r = - R.leq r (size ikind) - in - let r_min, r_max = min_of_range r, max_of_range r in - assert (range_in_ikind r && BISet.for_all (value_in_range (r_min, r_max)) xs); *) - begin match ikind with - | IBool -> - begin match BISet.mem Z.zero xs, BISet.mem Z.one xs with - | false, false -> top_bool (* Not {} -> {0, 1} *) - | true, false -> Inc (BISet.singleton Z.one) (* Not {0} -> {1} *) - | false, true -> Inc (BISet.singleton Z.zero) (* Not {1} -> {0} *) - | true, true -> bot_of ikind (* Not {0, 1} -> bot *) - end - | _ -> - v - end - - - let equal_to i = function - | Inc x -> - if BISet.mem i x then - if BISet.is_singleton x then `Eq - else `Top - else `Neq - | Exc (x, r) -> - if BISet.mem i x then `Neq - else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik v = norm ik @@ match v with - | Exc (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - Exc (s, r) - else if ik = IBool then (* downcast to bool *) - if BISet.mem Z.zero s then - Inc (BISet.singleton Z.one) - else - Exc (BISet.empty(), r') - else (* downcast: may overflow *) - Exc ((BISet.empty ()), r') - | Inc xs -> - let casted_xs = BISet.map (Size.cast ik) xs in - if Cil.isSigned ik && not (BISet.equal xs casted_xs) - then top_of ik (* When casting into a signed type and the result does not fit, the behavior is implementation-defined *) - else Inc casted_xs - - let of_int ikind x = cast_to ikind (Inc (BISet.singleton x)) - - let of_interval ?(suppress_ovwarn=false) ik (x, y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then BISet.singleton Z.zero else BISet.empty () in - norm ik @@ (Exc (ex, r)) - - let join _ x y = - match x, y with - | Inc x, Inc y -> Inc (BISet.union x y) - | Exc (x,r1), Exc (y,r2) -> Exc (BISet.inter x y, R.join r1 r2) - | Exc (x,r), Inc y - | Inc y, Exc (x,r) -> - let r = if BISet.is_empty y - then r - else - let (min_el_range, max_el_range) = Batteries.Tuple2.mapn (fun x -> R.of_interval range_ikind (Size.min_range_sign_agnostic x)) (BISet.min_elt y, BISet.max_elt y) in - let range = R.join min_el_range max_el_range in - R.join r range - in - Exc (BISet.diff x y, r) - - let meet _ x y = - match x, y with - | Inc x, Inc y -> Inc (BISet.inter x y) - | Exc (x,r1), Exc (y,r2) -> - let r = R.meet r1 r2 in - let r_min, r_max = Exclusion.min_of_range r, Exclusion.max_of_range r in - let filter_by_range = BISet.filter (value_in_range (r_min, r_max)) in - (* We remove those elements from the exclusion set that do not fit in the range anyway *) - let excl = BISet.union (filter_by_range x) (filter_by_range y) in - Exc (excl, r) - | Inc x, Exc (y,r) - | Exc (y,r), Inc x -> Inc (BISet.diff x y) - - let widen = join - let narrow = meet - let leq a b = - match a, b with - | Inc xs, Exc (ys, r) -> - if BISet.is_empty xs - then true - else - let min_b, max_b = Exclusion.min_of_range r, Exclusion.max_of_range r in - let min_a, max_a = BISet.min_elt xs, BISet.max_elt xs in - (* Check that the xs fit into the range r *) - Z.compare min_b min_a <= 0 && Z.compare max_a max_b <= 0 && - (* && check that none of the values contained in xs is excluded, i.e. contained in ys. *) - BISet.for_all (fun x -> not (BISet.mem x ys)) xs - | Inc xs, Inc ys -> - BISet.subset xs ys - | Exc (xs, r), Exc (ys, s) -> - Exclusion.(leq (Exc (xs, r)) (Exc (ys, s))) - | Exc (xs, r), Inc ys -> - Exclusion.(leq_excl_incl (Exc (xs, r)) (Inc ys)) - - let handle_bot x y f = match is_bot x, is_bot y with - | false, false -> f () - | true, false - | false, true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | true, true -> Inc (BISet.empty ()) - - let lift1 f ikind v = norm ikind @@ match v with - | Inc x when BISet.is_empty x -> v (* Return bottom when value is bottom *) - | Inc x when BISet.is_singleton x -> Inc (BISet.singleton (f (BISet.choose x))) - | _ -> top_of ikind - - let lift2 f (ikind: Cil.ikind) u v = - handle_bot u v (fun () -> - norm ikind @@ match u, v with - | Inc x,Inc y when BISet.is_singleton x && BISet.is_singleton y -> Inc (BISet.singleton (f (BISet.choose x) (BISet.choose y))) - | _,_ -> top_of ikind) - - let lift2 f ikind a b = - try lift2 f ikind a b with Division_by_zero -> top_of ikind - - let neg ?no_ov = lift1 Z.neg - let add ?no_ov ikind a b = - match a, b with - | Inc z,x when BISet.is_singleton z && BISet.choose z = Z.zero -> x - | x,Inc z when BISet.is_singleton z && BISet.choose z = Z.zero -> x - | x,y -> lift2 Z.add ikind x y - let sub ?no_ov = lift2 Z.sub - let mul ?no_ov ikind a b = - match a, b with - | Inc one,x when BISet.is_singleton one && BISet.choose one = Z.one -> x - | x,Inc one when BISet.is_singleton one && BISet.choose one = Z.one -> x - | Inc zero,_ when BISet.is_singleton zero && BISet.choose zero = Z.zero -> a - | _,Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> b - | x,y -> lift2 Z.mul ikind x y - - let div ?no_ov ikind a b = match a, b with - | x,Inc one when BISet.is_singleton one && BISet.choose one = Z.one -> x - | _,Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> top_of ikind - | Inc zero,_ when BISet.is_singleton zero && BISet.choose zero = Z.zero -> a - | x,y -> lift2 Z.div ikind x y - - let rem = lift2 Z.rem - - let lognot = lift1 Z.lognot - let logand = lift2 Z.logand - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - handle_bot x y (fun () -> - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - lift2 shift_op_big_int ik x y) - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - - let of_bool ikind x = Inc (BISet.singleton (if x then Z.one else Z.zero)) - let to_bool = function - | Inc e when BISet.is_empty e -> None - | Exc (e,_) when BISet.is_empty e -> None - | Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> Some false - | Inc xs when BISet.for_all ((<>) Z.zero) xs -> Some true - | Exc (xs,_) when BISet.exists ((=) Z.zero) xs -> Some true - | _ -> None - let to_int = function Inc x when BISet.is_singleton x -> Some (BISet.choose x) | _ -> None - - let to_excl_list = function Exc (x,r) when not (BISet.is_empty x) -> Some (BISet.elements x, (Option.get (R.minimal r), Option.get (R.maximal r))) | _ -> None - let of_excl_list ik xs = - let min_ik, max_ik = Size.range ik in - let exc = BISet.of_list @@ List.filter (value_in_range (min_ik, max_ik)) xs in - norm ik @@ Exc (exc, size ik) - let is_excl_list = BatOption.is_some % to_excl_list - let to_incl_list = function Inc s when not (BISet.is_empty s) -> Some (BISet.elements s) | _ -> None - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let c_lognot ik x = - if is_bot x - then x - else - match to_bool x with - | Some b -> of_bool ik (not b) - | None -> top_bool - - let c_logand = lift2 IntOps.BigIntOps.c_logand - let c_logor = lift2 IntOps.BigIntOps.c_logor - let maximal = function - | Inc xs when not (BISet.is_empty xs) -> Some (BISet.max_elt xs) - | Exc (excl,r) -> - let rec decrement_while_contained v = - if BISet.mem v excl - then decrement_while_contained (Z.pred v) - else v - in - let range_max = Exclusion.max_of_range r in - Some (decrement_while_contained range_max) - | _ (* bottom case *) -> None - - let minimal = function - | Inc xs when not (BISet.is_empty xs) -> Some (BISet.min_elt xs) - | Exc (excl,r) -> - let rec increment_while_contained v = - if BISet.mem v excl - then increment_while_contained (Z.succ v) - else v - in - let range_min = Exclusion.min_of_range r in - Some (increment_while_contained range_min) - | _ (* bottom case *) -> None - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let eq ik x y = - handle_bot x y (fun () -> - match x, y with - | Inc xs, Inc ys when BISet.is_singleton xs && BISet.is_singleton ys -> of_bool ik (Z.equal (BISet.choose xs) (BISet.choose ys)) - | _, _ -> - if is_bot (meet ik x y) then - (* If the meet is empty, there is no chance that concrete values are equal *) - of_bool ik false - else - top_bool) - - let ne ik x y = c_lognot ik (eq ik x y) - - let invariant_ikind e ik x = - match x with - | Inc ps -> - IntInvariant.of_incl_list e ik (BISet.elements ps) - | Exc (ns, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let nsi = IntInvariant.of_excl_list e ik (BISet.elements ns) in - Invariant.(ri && nsi) - - - let arbitrary ik = - let open QCheck.Iter in - let neg s = of_excl_list ik (BISet.elements s) in - let pos s = norm ik (Inc s) in - let shrink = function - | Exc (s, _) -> GobQCheck.shrink (BISet.arbitrary ()) s >|= neg (* S TODO: possibly shrink neg to pos *) - | Inc s -> GobQCheck.shrink (BISet.arbitrary ()) s >|= pos - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map neg (BISet.arbitrary ()); - 10, QCheck.map pos (BISet.arbitrary ()); - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = - let contains c m x = if Z.equal m Z.zero then Z.equal c x else Z.equal (Z.rem (Z.sub x c) m) Z.zero in - match a, b with - | Inc e, None -> bot_of ik - | Inc e, Some (c, m) -> Inc (BISet.filter (contains c m) e) - | _ -> a - - let refine_with_interval ik a b = a (* TODO: refine inclusion (exclusion?) set *) - - let refine_with_excl_list ik a b = - match b with - | Some (ls, _) -> meet ik a (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - - let refine_with_incl_list ik a b = - match a, b with - | Inc x, Some (ls) -> meet ik (Inc x) (Inc (BISet.of_list ls)) - | _ -> a - - let project ik p t = t -end - -module Congruence : S with type int_t = Z.t and type t = (Z.t * Z.t) option = -struct - let name () = "congruences" - type int_t = Z.t - - (* represents congruence class of c mod m, None is bot *) - type t = (Z.t * Z.t) option [@@deriving eq, ord, hash] - - let ( *: ) = Z.mul - let (+:) = Z.add - let (-:) = Z.sub - let (%:) = Z.rem - let (/:) = Z.div - let (=:) = Z.equal - let (<:) x y = Z.compare x y < 0 - let (>:) x y = Z.compare x y > 0 - let (<=:) x y = Z.compare x y <= 0 - let (>=:) x y = Z.compare x y >= 0 - (* a divides b *) - let ( |: ) a b = - if a =: Z.zero then false else (b %: a) =: Z.zero - - let normalize ik x = - match x with - | None -> None - | Some (c, m) -> - if m =: Z.zero then - if should_wrap ik then - Some (Size.cast ik c, m) - else - Some (c, m) - else - let m' = Z.abs m in - let c' = c %: m' in - if c' <: Z.zero then - Some (c' +: m', m') - else - Some (c' %: m', m') - - let range ik = Size.range ik - - let top () = Some (Z.zero, Z.one) - let top_of ik = Some (Z.zero, Z.one) - let bot () = None - let bot_of ik = bot () - - let show = function ik -> match ik with - | None -> "⟂" - | Some (c, m) when (c, m) = (Z.zero, Z.zero) -> Z.to_string c - | Some (c, m) -> - let a = if c =: Z.zero then "" else Z.to_string c in - let b = if m =: Z.zero then "" else if m = Z.one then "ℤ" else Z.to_string m^"ℤ" in - let c = if a = "" || b = "" then "" else "+" in - a^c^b - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let is_top x = x = top () - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) when b =: Z.zero -> if a =: i then `Eq else `Neq - | Some (a, b) -> if i %: b =: a then `Top else `Neq - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (c1,m1), Some (c2,m2) when m2 =: Z.zero && m1 =: Z.zero -> c1 =: c2 - | Some (c1,m1), Some (c2,m2) when m2 =: Z.zero -> c1 =: c2 && m1 =: Z.zero - | Some (c1,m1), Some (c2,m2) -> m2 |: Z.gcd (c1 -: c2) m1 - (* Typo in original equation of P. Granger (m2 instead of m1): gcd (c1 -: c2) m2 - Reference: https://doi.org/10.1080/00207168908803778 Page 171 corollary 3.3*) - - let leq x y = - let res = leq x y in - if M.tracing then M.trace "congruence" "leq %a %a -> %a " pretty x pretty y pretty (Some (Z.of_int (Bool.to_int res), Z.zero)) ; - res - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (c1,m1), Some (c2,m2) -> - let m3 = Z.gcd m1 (Z.gcd m2 (c1 -: c2)) in - normalize ik (Some (c1, m3)) - - let join ik (x:t) y = - let res = join ik x y in - if M.tracing then M.trace "congruence" "join %a %a -> %a" pretty x pretty y pretty res; - res - - - let meet ik x y = - (* if it exists, c2/a2 is solution to a*x ≡ c (mod m) *) - let congruence_series a c m = - let rec next a1 c1 a2 c2 = - if a2 |: a1 then (a2, c2) - else next a2 c2 (a1 %: a2) (c1 -: (c2 *: (a1 /: a2))) - in next m Z.zero a c - in - let simple_case i c m = - if m |: (i -: c) - then Some (i, Z.zero) else None - in - match x, y with - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero -> if c1 =: c2 then Some (c1, Z.zero) else None - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero -> simple_case c1 c2 m2 - | Some (c1, m1), Some (c2, m2) when m2 =: Z.zero -> simple_case c2 c1 m1 - | Some (c1, m1), Some (c2, m2) when (Z.gcd m1 m2) |: (c1 -: c2) -> - let (c, m) = congruence_series m1 (c2 -: c1 ) m2 in - normalize ik (Some(c1 +: (m1 *: (m /: c)), m1 *: (m2 /: c))) - | _ -> None - - let meet ik x y = - let res = meet ik x y in - if M.tracing then M.trace "congruence" "meet %a %a -> %a" pretty x pretty y pretty res; - res - - let to_int = function Some (c, m) when m =: Z.zero -> Some c | _ -> None - let of_int ik (x: int_t) = normalize ik @@ Some (x, Z.zero) - let zero = Some (Z.zero, Z.zero) - let one = Some (Z.one, Z.zero) - let top_bool = top() - - let of_bool _ik = function true -> one | false -> zero - - let to_bool (a: t) = match a with - | None -> None - | x when equal zero x -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = top() - - let ending = starting - - let of_congruence ik (c,m) = normalize ik @@ Some(c,m) - - let maximal t = match t with - | Some (x, y) when y =: Z.zero -> Some x - | _ -> None - - let minimal t = match t with - | Some (x,y) when y =: Z.zero -> Some x - | _ -> None - - (* cast from original type to ikind, set to top if the value doesn't fit into the new type *) - let cast_to ?(suppress_ovwarn=false) ?torg ?(no_ov=false) t x = - match x with - | None -> None - | Some (c, m) when m =: Z.zero -> - let c' = Size.cast t c in - (* When casting into a signed type and the result does not fit, the behavior is implementation-defined. (C90 6.2.1.2, C99 and C11 6.3.1.3) *) - (* We go with GCC behavior here: *) - (* For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised. *) - (* (https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html) *) - (* Clang behaves the same but they never document that anywhere *) - Some (c', m) - | _ -> - let (min_t, max_t) = range t in - let p ikorg = - let (min_ikorg, max_ikorg) = range ikorg in - ikorg = t || (max_t >=: max_ikorg && min_t <=: min_ikorg) - in - match torg with - | Some (Cil.TInt (ikorg, _)) when p ikorg -> - if M.tracing then M.trace "cong-cast" "some case"; - x - | _ -> top () - - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov (t : Cil.ikind) x = - let pretty_bool _ x = Pretty.text (string_of_bool x) in - let res = cast_to ?torg ?no_ov t x in - if M.tracing then M.trace "cong-cast" "Cast %a to %a (no_ov: %a) = %a" pretty x Cil.d_ikind t (Pretty.docOpt (pretty_bool ())) no_ov pretty res; - res - - let widen = join - - let widen ik x y = - let res = widen ik x y in - if M.tracing then M.trace "congruence" "widen %a %a -> %a" pretty x pretty y pretty res; - res - - let narrow = meet - - let log f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) - let c_logand = log (&&) - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let shift_right _ _ _ = top() - - let shift_right ik x y = - let res = shift_right ik x y in - if M.tracing then M.trace "congruence" "shift_right : %a %a becomes %a " pretty x pretty y pretty res; - res - - let shift_left ik x y = - (* Naive primality test *) - (* let is_prime n = - let n = Z.abs n in - let rec is_prime' d = - (d *: d >: n) || ((not ((n %: d) =: Z.zero)) && (is_prime' [@tailcall]) (d +: Z.one)) - in - not (n =: Z.one) && is_prime' (Z.of_int 2) - in *) - match x, y with - | None, None -> None - | None, _ - | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c, m), Some (c', m') when Cil.isSigned ik || c <: Z.zero || c' <: Z.zero -> top_of ik - | Some (c, m), Some (c', m') -> - let (_, max_ik) = range ik in - if m =: Z.zero && m' =: Z.zero then - normalize ik @@ Some (Z.logand max_ik (Z.shift_left c (Z.to_int c')), Z.zero) - else - let x = Z.logand max_ik (Z.shift_left Z.one (Z.to_int c')) in (* 2^c' *) - (* TODO: commented out because fails test with _Bool *) - (* if is_prime (m' +: Z.one) then - normalize ik @@ Some (x *: c, Z.gcd (x *: m) ((c *: x) *: (m' +: Z.one))) - else *) - normalize ik @@ Some (x *: c, Z.gcd (x *: m) (c *: x)) - - let shift_left ik x y = - let res = shift_left ik x y in - if M.tracing then M.trace "congruence" "shift_left : %a %a becomes %a " pretty x pretty y pretty res; - res - - (* Handle unsigned overflows. - From n === k mod (2^a * b), we conclude n === k mod 2^a, for a <= bitwidth. - The congruence modulo b may not persist on an overflow. *) - let handle_overflow ik (c, m) = - if m =: Z.zero then - normalize ik (Some (c, m)) - else - (* Find largest m'=2^k (for some k) such that m is divisible by m' *) - let tz = Z.trailing_zeros m in - let m' = Z.shift_left Z.one tz in - - let max = (snd (Size.range ik)) +: Z.one in - if m' >=: max then - (* if m' >= 2 ^ {bitlength}, there is only one value in range *) - let c' = c %: max in - Some (c', Z.zero) - else - normalize ik (Some (c, m')) - - let mul ?(no_ov=false) ik x y = - let no_ov_case (c1, m1) (c2, m2) = - c1 *: c2, Z.gcd (c1 *: m2) (Z.gcd (m1 *: c2) (m1 *: m2)) - in - match x, y with - | None, None -> bot () - | None, _ | _, None -> - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c1, m1), Some (c2, m2) when no_ov -> - Some (no_ov_case (c1, m1) (c2, m2)) - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero && not (Cil.isSigned ik) -> - let (_, max_ik) = range ik in - Some ((c1 *: c2) %: (max_ik +: Z.one), Z.zero) - | Some a, Some b when not (Cil.isSigned ik) -> - handle_overflow ik (no_ov_case a b ) - | _ -> top () - - let mul ?no_ov ik x y = - let res = mul ?no_ov ik x y in - if M.tracing then M.trace "congruence" "mul : %a %a -> %a " pretty x pretty y pretty res; - res - - let neg ?(no_ov=false) ik x = - match x with - | None -> bot() - | Some _ -> mul ~no_ov ik (of_int ik (Z.of_int (-1))) x - - let add ?(no_ov=false) ik x y = - let no_ov_case (c1, m1) (c2, m2) = - c1 +: c2, Z.gcd m1 m2 - in - match (x, y) with - | None, None -> bot () - | None, _ | _, None -> - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some a, Some b when no_ov -> - normalize ik (Some (no_ov_case a b)) - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero && not (Cil.isSigned ik) -> - let (_, max_ik) = range ik in - Some((c1 +: c2) %: (max_ik +: Z.one), Z.zero) - | Some a, Some b when not (Cil.isSigned ik) -> - handle_overflow ik (no_ov_case a b) - | _ -> top () - - - let add ?no_ov ik x y = - let res = add ?no_ov ik x y in - if M.tracing then - M.trace "congruence" "add : %a %a -> %a" pretty x pretty y - pretty res ; - res - - let sub ?(no_ov=false) ik x y = add ~no_ov ik x (neg ~no_ov ik y) - - - let sub ?no_ov ik x y = - let res = sub ?no_ov ik x y in - if M.tracing then - M.trace "congruence" "sub : %a %a -> %a" pretty x pretty y - pretty res ; - res - - let lognot ik x = match x with - | None -> None - | Some (c, m) -> - if (Cil.isSigned ik) then - sub ik (neg ik x) one - else - let (_, max_ik) = range ik in - Some (Z.sub max_ik c, m) - - (** The implementation of the bit operations could be improved based on the master’s thesis - 'Abstract Interpretation and Abstract Domains' written by Stefan Bygde. - see: http://www.es.mdh.se/pdf_publications/948.pdf *) - let bit2 f ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c, m), Some (c', m') -> - if m =: Z.zero && m' =: Z.zero then Some (f c c', Z.zero) - else top () - - let logor ik x y = bit2 Z.logor ik x y - - let logand ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c, m), Some (c', m') -> - if m =: Z.zero && m' =: Z.zero then - (* both arguments constant *) - Some (Z.logand c c', Z.zero) - else if m' =: Z.zero && c' =: Z.one && Z.rem m (Z.of_int 2) =: Z.zero then - (* x & 1 and x == c (mod 2*z) *) - (* Value is equal to LSB of c *) - Some (Z.logand c c', Z.zero) - else - top () - - let logxor ik x y = bit2 Z.logxor ik x y - - let rem ik x y = - match x, y with - | None, None -> bot() - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c1, m1), Some(c2, m2) -> - if m2 =: Z.zero then - if (c2 |: m1) && (c1 %: c2 =: Z.zero || m1 =: Z.zero || not (Cil.isSigned ik)) then - Some (c1 %: c2, Z.zero) - else - normalize ik (Some (c1, (Z.gcd m1 c2))) - else - normalize ik (Some (c1, Z.gcd m1 (Z.gcd c2 m2))) - - let rem ik x y = let res = rem ik x y in - if M.tracing then M.trace "congruence" "rem : %a %a -> %a " pretty x pretty y pretty res; - res - - let div ?(no_ov=false) ik x y = - match x,y with - | None, None -> bot () - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, x when leq zero x -> top () - | Some(c1, m1), Some(c2, m2) when not no_ov && m2 =: Z.zero && c2 =: Z.neg Z.one -> top () - | Some(c1, m1), Some(c2, m2) when m1 =: Z.zero && m2 =: Z.zero -> Some (c1 /: c2, Z.zero) - | Some(c1, m1), Some(c2, m2) when m2 =: Z.zero && c2 |: m1 && c2 |: c1 -> Some (c1 /: c2, m1 /: c2) - | _, _ -> top () - - - let div ?no_ov ik x y = - let res = div ?no_ov ik x y in - if M.tracing then - M.trace "congruence" "div : %a %a -> %a" pretty x pretty y pretty - res ; - res - - let ne ik (x: t) (y: t) = match x, y with - | Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> of_bool ik (not (c1 =: c2 )) - | x, y -> if meet ik x y = None then of_bool ik true else top_bool - - let eq ik (x: t) (y: t) = match x, y with - | Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> of_bool ik (c1 =: c2) - | x, y -> if meet ik x y <> None then top_bool else of_bool ik false - - let comparison ik op x y = match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c1, m1), Some (c2, m2) -> - if m1 =: Z.zero && m2 =: Z.zero then - if op c1 c2 then of_bool ik true else of_bool ik false - else - top_bool - - let ge ik x y = comparison ik (>=:) x y - - let ge ik x y = - let res = ge ik x y in - if M.tracing then M.trace "congruence" "greater or equal : %a %a -> %a " pretty x pretty y pretty res; - res - - let le ik x y = comparison ik (<=:) x y - - let le ik x y = - let res = le ik x y in - if M.tracing then M.trace "congruence" "less or equal : %a %a -> %a " pretty x pretty y pretty res; - res - - let gt ik x y = comparison ik (>:) x y - - - let gt ik x y = - let res = gt ik x y in - if M.tracing then M.trace "congruence" "greater than : %a %a -> %a " pretty x pretty y pretty res; - res - - let lt ik x y = comparison ik (<:) x y - - let lt ik x y = - let res = lt ik x y in - if M.tracing then M.trace "congruence" "less than : %a %a -> %a " pretty x pretty y pretty res; - res - - let invariant_ikind e ik x = - match x with - | x when is_top x -> Invariant.top () - | Some (c, m) when m =: Z.zero -> - IntInvariant.of_int e ik c - | Some (c, m) -> - let open Cil in - let (c, m) = BatTuple.Tuple2.mapn (fun a -> kintegerCilint ik a) (c, m) in - Invariant.of_exp (BinOp (Eq, (BinOp (Mod, e, m, TInt(ik,[]))), c, intType)) - | None -> Invariant.none - - let arbitrary ik = - let open QCheck in - let int_arb = map ~rev:Z.to_int64 Z.of_int64 GobQCheck.Arbitrary.int64 in - let cong_arb = pair int_arb int_arb in - let of_pair ik p = normalize ik (Some p) in - let to_pair = Option.get in - set_print show (map ~rev:to_pair (of_pair ik) cong_arb) - - let refine_with_interval ik (cong : t) (intv : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =: Z.zero then - if c <: x || c >: y then None else Some (c, Z.zero) - else - let rcx = x +: ((c -: x) %: Z.abs m) in - let lcy = y -: ((y -: c) %: Z.abs m) in - if rcx >: lcy then None - else if rcx =: lcy then Some (rcx, Z.zero) - else cong - | _ -> None - - let refine_with_interval ik (cong : t) (intv : (int_t * int_t) option) : t = - let pretty_intv _ i = - match i with - | Some (l, u) -> Pretty.dprintf "[%a,%a]" GobZ.pretty l GobZ.pretty u - | _ -> Pretty.text ("Display Error") in - let refn = refine_with_interval ik cong intv in - if M.tracing then M.trace "refine" "cong_refine_with_interval %a %a -> %a" pretty cong pretty_intv intv pretty refn; - refn - - let refine_with_congruence ik a b = meet ik a b - let refine_with_excl_list ik a b = a - let refine_with_incl_list ik a b = a - - let project ik p t = t -end - -module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct - - include D - - let lift v = (v, {overflow=false; underflow=false}) - - let add ?no_ov ik x y = lift @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = lift @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = lift @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = lift @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = lift @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = lift @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = lift @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = lift @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = lift @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = lift @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = lift @@ D.shift_left ik x y - - let shift_right ik x y = lift @@ D.shift_right ik x y - -end - +open IntDomain0 (* The old IntDomList had too much boilerplate since we had to edit every function in S when adding a new domain. With the following, we only have to edit the places where fn are applied, i.e., create, mapp, map, map2. You can search for I3 below to see where you need to extend. *) From 816809fcfcf7fb6fab2c79d43fe47940f0a9af91 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:49:35 +0300 Subject: [PATCH 593/689] Remove IntDomTuple from IntDomain0 --- src/cdomain/value/cdomains/intDomain0.ml | 516 ----------------------- 1 file changed, 516 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/intDomain0.ml index f4639d4522..7450e8a212 100644 --- a/src/cdomain/value/cdomains/intDomain0.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -3267,519 +3267,3 @@ module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t let shift_right ik x y = lift @@ D.shift_right ik x y end - - - -(* The old IntDomList had too much boilerplate since we had to edit every function in S when adding a new domain. With the following, we only have to edit the places where fn are applied, i.e., create, mapp, map, map2. You can search for I3 below to see where you need to extend. *) -(* discussion: https://github.com/goblint/analyzer/pull/188#issuecomment-818928540 *) -module IntDomTupleImpl = struct - include Printable.Std (* for default invariant, tag, ... *) - - open Batteries - type int_t = Z.t - module I1 = SOverflowLifter (DefExc) - module I2 = Interval - module I3 = SOverflowLifter (Enums) - module I4 = SOverflowLifter (Congruence) - module I5 = IntervalSetFunctor (IntOps.BigIntOps) - - type t = I1.t option * I2.t option * I3.t option * I4.t option * I5.t option - [@@deriving eq, ord, hash] - - let name () = "intdomtuple" - - (* The Interval domain can lead to too many contexts for recursive functions (top is [min,max]), but we don't want to drop all ints as with `ana.base.context.int`. TODO better solution? *) - let no_interval = Tuple5.map2 (const None) - let no_intervalSet = Tuple5.map5 (const None) - - type 'a m = (module SOverflow with type t = 'a) - type 'a m2 = (module SOverflow with type t = 'a and type int_t = int_t ) - - (* only first-order polymorphism on functions -> use records to get around monomorphism restriction on arguments *) - type 'b poly_in = { fi : 'a. 'a m -> 'b -> 'a } [@@unboxed] (* inject *) - type 'b poly2_in = { fi2 : 'a. 'a m2 -> 'b -> 'a } [@@unboxed] (* inject for functions that depend on int_t *) - type 'b poly2_in_ovc = { fi2_ovc : 'a. 'a m2 -> 'b -> 'a * overflow_info} [@@unboxed] (* inject for functions that depend on int_t *) - - type 'b poly_pr = { fp : 'a. 'a m -> 'a -> 'b } [@@unboxed] (* project *) - type 'b poly_pr2 = { fp2 : 'a. 'a m2 -> 'a -> 'b } [@@unboxed] (* project for functions that depend on int_t *) - type 'b poly2_pr = {f2p: 'a. 'a m -> ?no_ov:bool -> 'a -> 'a -> 'b} [@@unboxed] - type poly1 = {f1: 'a. 'a m -> ?no_ov:bool -> 'a -> 'a} [@@unboxed] (* needed b/c above 'b must be different from 'a *) - type poly1_ovc = {f1_ovc: 'a. 'a m -> ?no_ov:bool -> 'a -> 'a * overflow_info } [@@unboxed] (* needed b/c above 'b must be different from 'a *) - type poly2 = {f2: 'a. 'a m -> ?no_ov:bool -> 'a -> 'a -> 'a} [@@unboxed] - type poly2_ovc = {f2_ovc: 'a. 'a m -> ?no_ov:bool -> 'a -> 'a -> 'a * overflow_info } [@@unboxed] - type 'b poly3 = { f3: 'a. 'a m -> 'a option } [@@unboxed] (* used for projection to given precision *) - let create r x ((p1, p2, p3, p4, p5): int_precision) = - let f b g = if b then Some (g x) else None in - f p1 @@ r.fi (module I1), f p2 @@ r.fi (module I2), f p3 @@ r.fi (module I3), f p4 @@ r.fi (module I4), f p5 @@ r.fi (module I5) - let create r x = (* use where values are introduced *) - create r x (int_precision_from_node_or_config ()) - let create2 r x ((p1, p2, p3, p4, p5): int_precision) = - let f b g = if b then Some (g x) else None in - f p1 @@ r.fi2 (module I1), f p2 @@ r.fi2 (module I2), f p3 @@ r.fi2 (module I3), f p4 @@ r.fi2 (module I4), f p5 @@ r.fi2 (module I5) - let create2 r x = (* use where values are introduced *) - create2 r x (int_precision_from_node_or_config ()) - - let no_overflow ik = function - | Some(_, {underflow; overflow}) -> not (underflow || overflow) - | _ -> false - - let check_ov ?(suppress_ovwarn = false) ~cast ik intv intv_set = - let no_ov = (no_overflow ik intv) || (no_overflow ik intv_set) in - if not no_ov && not suppress_ovwarn && ( BatOption.is_some intv || BatOption.is_some intv_set) then ( - let (_,{underflow=underflow_intv; overflow=overflow_intv}) = match intv with None -> (I2.bot (), {underflow= true; overflow = true}) | Some x -> x in - let (_,{underflow=underflow_intv_set; overflow=overflow_intv_set}) = match intv_set with None -> (I5.bot (), {underflow= true; overflow = true}) | Some x -> x in - let underflow = underflow_intv && underflow_intv_set in - let overflow = overflow_intv && overflow_intv_set in - set_overflow_flag ~cast ~underflow ~overflow ik; - ); - no_ov - - let create2_ovc ik r x ((p1, p2, p3, p4, p5): int_precision) = - let f b g = if b then Some (g x) else None in - let map x = Option.map fst x in - let intv = f p2 @@ r.fi2_ovc (module I2) in - let intv_set = f p5 @@ r.fi2_ovc (module I5) in - ignore (check_ov ~cast:false ik intv intv_set); - map @@ f p1 @@ r.fi2_ovc (module I1), map @@ f p2 @@ r.fi2_ovc (module I2), map @@ f p3 @@ r.fi2_ovc (module I3), map @@ f p4 @@ r.fi2_ovc (module I4), map @@ f p5 @@ r.fi2_ovc (module I5) - - let create2_ovc ik r x = (* use where values are introduced *) - create2_ovc ik r x (int_precision_from_node_or_config ()) - - - let opt_map2 f ?no_ov = - curry @@ function Some x, Some y -> Some (f ?no_ov x y) | _ -> None - - let to_list x = Tuple5.enum x |> List.of_enum |> List.filter_map identity (* contains only the values of activated domains *) - let to_list_some x = List.filter_map identity @@ to_list x (* contains only the Some-values of activated domains *) - - let exists = function - | (Some true, _, _, _, _) - | (_, Some true, _, _, _) - | (_, _, Some true, _, _) - | (_, _, _, Some true, _) - | (_, _, _, _, Some true) -> - true - | _ -> - false - - let for_all = function - | (Some false, _, _, _, _) - | (_, Some false, _, _, _) - | (_, _, Some false, _, _) - | (_, _, _, Some false, _) - | (_, _, _, _, Some false) -> - false - | _ -> - true - - (* f0: constructors *) - let top () = create { fi = fun (type a) (module I:SOverflow with type t = a) -> I.top } () - let bot () = create { fi = fun (type a) (module I:SOverflow with type t = a) -> I.bot } () - let top_of = create { fi = fun (type a) (module I:SOverflow with type t = a) -> I.top_of } - let bot_of = create { fi = fun (type a) (module I:SOverflow with type t = a) -> I.bot_of } - let of_bool ik = create { fi = fun (type a) (module I:SOverflow with type t = a) -> I.of_bool ik } - let of_excl_list ik = create2 { fi2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.of_excl_list ik} - let of_int ik = create2_ovc ik { fi2_ovc = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.of_int ik } - let starting ?(suppress_ovwarn=false) ik = create2_ovc ik { fi2_ovc = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.starting ~suppress_ovwarn ik } - let ending ?(suppress_ovwarn=false) ik = create2_ovc ik { fi2_ovc = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.ending ~suppress_ovwarn ik } - let of_interval ?(suppress_ovwarn=false) ik = create2_ovc ik { fi2_ovc = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.of_interval ~suppress_ovwarn ik } - let of_congruence ik = create2 { fi2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.of_congruence ik } - - let refine_with_congruence ik ((a, b, c, d, e) : t) (cong : (int_t * int_t) option) : t= - let opt f a = - curry @@ function Some x, y -> Some (f a x y) | _ -> None - in - ( opt I1.refine_with_congruence ik a cong - , opt I2.refine_with_congruence ik b cong - , opt I3.refine_with_congruence ik c cong - , opt I4.refine_with_congruence ik d cong - , opt I5.refine_with_congruence ik e cong) - - let refine_with_interval ik (a, b, c, d, e) intv = - let opt f a = - curry @@ function Some x, y -> Some (f a x y) | _ -> None - in - ( opt I1.refine_with_interval ik a intv - , opt I2.refine_with_interval ik b intv - , opt I3.refine_with_interval ik c intv - , opt I4.refine_with_interval ik d intv - , opt I5.refine_with_interval ik e intv ) - - let refine_with_excl_list ik (a, b, c, d, e) excl = - let opt f a = - curry @@ function Some x, y -> Some (f a x y) | _ -> None - in - ( opt I1.refine_with_excl_list ik a excl - , opt I2.refine_with_excl_list ik b excl - , opt I3.refine_with_excl_list ik c excl - , opt I4.refine_with_excl_list ik d excl - , opt I5.refine_with_excl_list ik e excl ) - - let refine_with_incl_list ik (a, b, c, d, e) incl = - let opt f a = - curry @@ function Some x, y -> Some (f a x y) | _ -> None - in - ( opt I1.refine_with_incl_list ik a incl - , opt I2.refine_with_incl_list ik b incl - , opt I3.refine_with_incl_list ik c incl - , opt I4.refine_with_incl_list ik d incl - , opt I5.refine_with_incl_list ik e incl ) - - - let mapp r (a, b, c, d, e) = - let map = BatOption.map in - ( map (r.fp (module I1)) a - , map (r.fp (module I2)) b - , map (r.fp (module I3)) c - , map (r.fp (module I4)) d - , map (r.fp (module I5)) e) - - - let mapp2 r (a, b, c, d, e) = - BatOption. - ( map (r.fp2 (module I1)) a - , map (r.fp2 (module I2)) b - , map (r.fp2 (module I3)) c - , map (r.fp2 (module I4)) d - , map (r.fp2 (module I5)) e) - - - (* exists/for_all *) - let is_bot = exists % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.is_bot } - let is_top = for_all % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.is_top } - let is_top_of ik = for_all % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.is_top_of ik } - let is_excl_list = exists % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.is_excl_list } - - let map2p r (xa, xb, xc, xd, xe) (ya, yb, yc, yd, ye) = - ( opt_map2 (r.f2p (module I1)) xa ya - , opt_map2 (r.f2p (module I2)) xb yb - , opt_map2 (r.f2p (module I3)) xc yc - , opt_map2 (r.f2p (module I4)) xd yd - , opt_map2 (r.f2p (module I5)) xe ye) - - (* f2p: binary projections *) - let (%%) f g x = f % (g x) (* composition for binary function g *) - - let leq = - for_all - %% map2p {f2p= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.leq)} - - let flat f x = match to_list_some x with [] -> None | xs -> Some (f xs) - - let to_excl_list x = - let merge ps = - let (vs, rs) = List.split ps in - let (mins, maxs) = List.split rs in - (List.concat vs |> List.sort_uniq Z.compare, (List.min mins, List.max maxs)) - in - mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.to_excl_list } x |> flat merge - - let to_incl_list x = - let hd l = match l with h::t -> h | _ -> [] in - let tl l = match l with h::t -> t | _ -> [] in - let a y = BatSet.of_list (hd y) in - let b y = BatList.map BatSet.of_list (tl y) in - let merge y = BatSet.elements @@ BatList.fold BatSet.intersect (a y) (b y) - in - mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.to_incl_list } x |> flat merge - - let same show x = let xs = to_list_some x in let us = List.unique xs in let n = List.length us in - if n = 1 then Some (List.hd xs) - else ( - if n>1 then Messages.info ~category:Unsound "Inconsistent state! %a" (Pretty.docList ~sep:(Pretty.text ",") (Pretty.text % show)) us; (* do not want to abort *) - None - ) - let to_int = same Z.to_string % mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.to_int } - - let pretty () x = - match to_int x with - | Some v when not (GobConfig.get_bool "dbg.full-output") -> Pretty.text (Z.to_string v) - | _ -> - mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> (* assert sf==I.short; *) I.pretty () } x - |> to_list - |> (fun xs -> - text "(" ++ ( - try - List.reduce (fun a b -> a ++ text "," ++ b) xs - with Invalid_argument _ -> - nil) - ++ text ")") (* NOTE: the version above does something else. also, we ignore the sf-argument here. *) - - let refine_functions ik : (t -> t) list = - let maybe reffun ik domtup dom = - match dom with Some y -> reffun ik domtup y | _ -> domtup - in - [(fun (a, b, c, d, e) -> refine_with_excl_list ik (a, b, c, d, e) (to_excl_list (a, b, c, d, e))); - (fun (a, b, c, d, e) -> refine_with_incl_list ik (a, b, c, d, e) (to_incl_list (a, b, c, d, e))); - (fun (a, b, c, d, e) -> maybe refine_with_interval ik (a, b, c, d, e) b); (* TODO: get interval across all domains with minimal and maximal *) - (fun (a, b, c, d, e) -> maybe refine_with_congruence ik (a, b, c, d, e) d)] - - let refine ik ((a, b, c, d, e) : t ) : t = - let dt = ref (a, b, c, d, e) in - (match get_refinement () with - | "never" -> () - | "once" -> - List.iter (fun f -> dt := f !dt) (refine_functions ik); - | "fixpoint" -> - let quit_loop = ref false in - while not !quit_loop do - let old_dt = !dt in - List.iter (fun f -> dt := f !dt) (refine_functions ik); - quit_loop := equal old_dt !dt; - if is_bot !dt then dt := bot_of ik; quit_loop := true; - if M.tracing then M.trace "cong-refine-loop" "old: %a, new: %a" pretty old_dt pretty !dt; - done; - | _ -> () - ); !dt - - - (* map with overflow check *) - let mapovc ?(suppress_ovwarn=false) ?(cast=false) ik r (a, b, c, d, e) = - let map f ?no_ov = function Some x -> Some (f ?no_ov x) | _ -> None in - let intv = map (r.f1_ovc (module I2)) b in - let intv_set = map (r.f1_ovc (module I5)) e in - let no_ov = check_ov ~suppress_ovwarn ~cast ik intv intv_set in - let no_ov = no_ov || should_ignore_overflow ik in - refine ik - ( map (fun ?no_ov x -> r.f1_ovc ?no_ov (module I1) x |> fst) a - , BatOption.map fst intv - , map (fun ?no_ov x -> r.f1_ovc ?no_ov (module I3) x |> fst) c - , map (fun ?no_ov x -> r.f1_ovc ?no_ov (module I4) x |> fst) ~no_ov d - , BatOption.map fst intv_set ) - - (* map2 with overflow check *) - let map2ovc ?(cast=false) ik r (xa, xb, xc, xd, xe) (ya, yb, yc, yd, ye) = - let intv = opt_map2 (r.f2_ovc (module I2)) xb yb in - let intv_set = opt_map2 (r.f2_ovc (module I5)) xe ye in - let no_ov = check_ov ~cast ik intv intv_set in - let no_ov = no_ov || should_ignore_overflow ik in - refine ik - ( opt_map2 (fun ?no_ov x y -> r.f2_ovc ?no_ov (module I1) x y |> fst) xa ya - , BatOption.map fst intv - , opt_map2 (fun ?no_ov x y -> r.f2_ovc ?no_ov (module I3) x y |> fst) xc yc - , opt_map2 (fun ?no_ov x y -> r.f2_ovc ?no_ov (module I4) x y |> fst) ~no_ov:no_ov xd yd - , BatOption.map fst intv_set ) - - let map ik r (a, b, c, d, e) = - refine ik - BatOption. - ( map (r.f1 (module I1)) a - , map (r.f1 (module I2)) b - , map (r.f1 (module I3)) c - , map (r.f1 (module I4)) d - , map (r.f1 (module I5)) e) - - let map2 ?(norefine=false) ik r (xa, xb, xc, xd, xe) (ya, yb, yc, yd, ye) = - let r = - ( opt_map2 (r.f2 (module I1)) xa ya - , opt_map2 (r.f2 (module I2)) xb yb - , opt_map2 (r.f2 (module I3)) xc yc - , opt_map2 (r.f2 (module I4)) xd yd - , opt_map2 (r.f2 (module I5)) xe ye) - in - if norefine then r else refine ik r - - - (* f1: unary ops *) - let neg ?no_ov ik = - mapovc ik {f1_ovc = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.neg ?no_ov ik)} - - let lognot ik = - map ik {f1 = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.lognot ik)} - - let c_lognot ik = - map ik {f1 = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.c_lognot ik)} - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = - mapovc ~suppress_ovwarn ~cast:true t {f1_ovc = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.cast_to ?torg ?no_ov t)} - - (* fp: projections *) - let equal_to i x = - let xs = mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.equal_to i } x |> Tuple5.enum |> List.of_enum |> List.filter_map identity in - if List.mem `Eq xs then `Eq else - if List.mem `Neq xs then `Neq else - `Top - - let to_bool = same string_of_bool % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.to_bool } - let minimal = flat (List.max ~cmp:Z.compare) % mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.minimal } - let maximal = flat (List.min ~cmp:Z.compare) % mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.maximal } - (* others *) - let show x = - match to_int x with - | Some v when not (GobConfig.get_bool "dbg.full-output") -> Z.to_string v - | _ -> mapp { fp = fun (type a) (module I:SOverflow with type t = a) x -> I.name () ^ ":" ^ (I.show x) } x - |> to_list - |> String.concat "; " - let to_yojson = [%to_yojson: Yojson.Safe.t list] % to_list % mapp { fp = fun (type a) (module I:SOverflow with type t = a) x -> I.to_yojson x } - - (* `map/opt_map` are used by `project` *) - let opt_map b f = - curry @@ function None, true -> f | x, y when y || b -> x | _ -> None - let map ~keep r (i1, i2, i3, i4, i5) (b1, b2, b3, b4, b5) = - ( opt_map keep (r.f3 (module I1)) i1 b1 - , opt_map keep (r.f3 (module I2)) i2 b2 - , opt_map keep (r.f3 (module I3)) i3 b3 - , opt_map keep (r.f3 (module I4)) i4 b4 - , opt_map keep (r.f3 (module I5)) i5 b5 ) - - (** Project tuple t to precision p - * We have to deactivate IntDomains after the refinement, since we might - * lose information if we do it before. E.g. only "Interval" is active - * and shall be projected to only "Def_Exc". By seting "Interval" to None - * before refinement we have no information for "Def_Exc". - * - * Thus we have 3 Steps: - * 1. Add padding to t by setting `None` to `I.top_of ik` if p is true for this element - * 2. Refine the padded t - * 3. Set elements of t to `None` if p is false for this element - * - * Side Note: - * ~keep is used to reuse `map/opt_map` for Step 1 and 3. - * ~keep:true will keep elements that are `Some x` but should be set to `None` by p. - * This way we won't loose any information for the refinement. - * ~keep:false will set the elements to `None` as defined by p *) - let project ik (p: int_precision) t = - let t_padded = map ~keep:true { f3 = fun (type a) (module I:SOverflow with type t = a) -> Some (I.top_of ik) } t p in - let t_refined = refine ik t_padded in - map ~keep:false { f3 = fun (type a) (module I:SOverflow with type t = a) -> None } t_refined p - - - (* f2: binary ops *) - let join ik = - map2 ~norefine:true ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.join ik)} - - let meet ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.meet ik)} - - let widen ik = - map2 ~norefine:true ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.widen ik)} - - let narrow ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.narrow ik)} - - let add ?no_ov ik = - map2ovc ik - {f2_ovc = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.add ?no_ov ik)} - - let sub ?no_ov ik = - map2ovc ik - {f2_ovc = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.sub ?no_ov ik)} - - let mul ?no_ov ik = - map2ovc ik - {f2_ovc = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.mul ?no_ov ik)} - - let div ?no_ov ik = - map2ovc ik - {f2_ovc = (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.div ?no_ov ik)} - - let rem ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.rem ik)} - - let lt ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.lt ik)} - - let gt ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.gt ik)} - - let le ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.le ik)} - - let ge ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.ge ik)} - - let eq ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.eq ik)} - - let ne ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.ne ik)} - - let logand ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.logand ik)} - - let logor ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.logor ik)} - - let logxor ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.logxor ik)} - - let shift_left ik = - map2ovc ik {f2_ovc= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.shift_left ik)} - - let shift_right ik = - map2ovc ik {f2_ovc= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.shift_right ik)} - - let c_logand ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.c_logand ik)} - - let c_logor ik = - map2 ik {f2= (fun (type a) (module I : SOverflow with type t = a) ?no_ov -> I.c_logor ik)} - - - (* printing boilerplate *) - let pretty_diff () (x,y) = dprintf "%a instead of %a" pretty x pretty y - let printXml f x = - match to_int x with - | Some v when not (GobConfig.get_bool "dbg.full-output") -> BatPrintf.fprintf f "\n\n%s\n\n\n" (Z.to_string v) - | _ -> BatPrintf.fprintf f "\n\n%s\n\n\n" (show x) - - let invariant_ikind e ik ((_, _, _, x_cong, x_intset) as x) = - (* TODO: do refinement before to ensure incl_list being more precise than intervals, etc (https://github.com/goblint/analyzer/pull/1517#discussion_r1693998515), requires refine functions to actually refine that *) - let simplify_int fallback = - match to_int x with - | Some v -> - (* If definite, output single equality instead of every subdomain repeating same equality (or something less precise). *) - IntInvariant.of_int e ik v - | None -> - fallback () - in - let simplify_all () = - match to_incl_list x with - | Some ps -> - (* If inclusion set, output disjunction of equalities because it subsumes interval(s), exclusion set and congruence. *) - IntInvariant.of_incl_list e ik ps - | None -> - (* Get interval bounds from all domains (intervals and exclusion set ranges). *) - let min = minimal x in - let max = maximal x in - let ns = Option.map fst (to_excl_list x) |? [] in (* Ignore exclusion set bit range, known via interval bounds already. *) - (* "Refine" out-of-bounds exclusions for simpler output. *) - let ns = Option.map_default (fun min -> List.filter (Z.leq min) ns) ns min in - let ns = Option.map_default (fun max -> List.filter (Z.geq max) ns) ns max in - Invariant.( - IntInvariant.of_interval_opt e ik (min, max) && (* Output best interval bounds once instead of multiple subdomains repeating them (or less precise ones). *) - IntInvariant.of_excl_list e ik ns && - Option.map_default (I4.invariant_ikind e ik) Invariant.none x_cong && (* Output congruence as is. *) - Option.map_default (I5.invariant_ikind e ik) Invariant.none x_intset (* Output interval sets as is. *) - ) - in - let simplify_none () = - let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x) in - List.fold_left (fun a i -> - Invariant.(a && i) - ) (Invariant.top ()) is - in - match GobConfig.get_string "ana.base.invariant.int.simplify" with - | "none" -> simplify_none () - | "int" -> simplify_int simplify_none - | "all" -> simplify_int simplify_all - | _ -> assert false - - let arbitrary ik = QCheck.(set_print show @@ tup5 (option (I1.arbitrary ik)) (option (I2.arbitrary ik)) (option (I3.arbitrary ik)) (option (I4.arbitrary ik)) (option (I5.arbitrary ik))) - - let relift (a, b, c, d, e) = - (Option.map I1.relift a, Option.map I2.relift b, Option.map I3.relift c, Option.map I4.relift d, Option.map I5.relift e) -end - -module IntDomTuple = -struct - module I = IntDomLifter (IntDomTupleImpl) - include I - - let top () = failwith "top in IntDomTuple not supported. Use top_of instead." - let no_interval (x: I.t) = {x with v = IntDomTupleImpl.no_interval x.v} - - let no_intervalSet (x: I.t) = {x with v = IntDomTupleImpl.no_intervalSet x.v} -end - -let of_const (i, ik, str) = IntDomTuple.of_int ik i From 8c563ae9c3af6b1d0b4ceb2fdffbc9b1e7e94cd1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:54:49 +0300 Subject: [PATCH 594/689] Rename IntDomain0 -> CongruenceDomain for split --- .../value/cdomains/{intDomain0.ml => int/congruenceDomain.ml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cdomain/value/cdomains/{intDomain0.ml => int/congruenceDomain.ml} (100%) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/int/congruenceDomain.ml similarity index 100% rename from src/cdomain/value/cdomains/intDomain0.ml rename to src/cdomain/value/cdomains/int/congruenceDomain.ml From d66919e5b7ffb07fde6ae1929ca0c8d486f2acba Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:55:25 +0300 Subject: [PATCH 595/689] Remove non-CongruenceDomain parts --- .../value/cdomains/int/congruenceDomain.ml | 2776 +---------------- 1 file changed, 1 insertion(+), 2775 deletions(-) diff --git a/src/cdomain/value/cdomains/int/congruenceDomain.ml b/src/cdomain/value/cdomains/int/congruenceDomain.ml index 7450e8a212..a88ffbc813 100644 --- a/src/cdomain/value/cdomains/int/congruenceDomain.ml +++ b/src/cdomain/value/cdomains/int/congruenceDomain.ml @@ -1,2747 +1,5 @@ -open GobConfig -open GoblintCil -open Pretty -open PrecisionUtil - -module M = Messages - -let (%) = Batteries.(%) -let (|?) = Batteries.(|?) - -exception IncompatibleIKinds of string -exception Unknown -exception Error -exception ArithmeticOnIntegerBot of string - - - - -(** Define records that hold mutable variables representing different Configuration values. - * These values are used to keep track of whether or not the corresponding Config values are en-/disabled *) -type ana_int_config_values = { - mutable interval_threshold_widening : bool option; - mutable interval_narrow_by_meet : bool option; - mutable def_exc_widen_by_join : bool option; - mutable interval_threshold_widening_constants : string option; - mutable refinement : string option; -} - -let ana_int_config: ana_int_config_values = { - interval_threshold_widening = None; - interval_narrow_by_meet = None; - def_exc_widen_by_join = None; - interval_threshold_widening_constants = None; - refinement = None; -} - -let get_interval_threshold_widening () = - if ana_int_config.interval_threshold_widening = None then - ana_int_config.interval_threshold_widening <- Some (get_bool "ana.int.interval_threshold_widening"); - Option.get ana_int_config.interval_threshold_widening - -let get_interval_narrow_by_meet () = - if ana_int_config.interval_narrow_by_meet = None then - ana_int_config.interval_narrow_by_meet <- Some (get_bool "ana.int.interval_narrow_by_meet"); - Option.get ana_int_config.interval_narrow_by_meet - -let get_def_exc_widen_by_join () = - if ana_int_config.def_exc_widen_by_join = None then - ana_int_config.def_exc_widen_by_join <- Some (get_bool "ana.int.def_exc_widen_by_join"); - Option.get ana_int_config.def_exc_widen_by_join - -let get_interval_threshold_widening_constants () = - if ana_int_config.interval_threshold_widening_constants = None then - ana_int_config.interval_threshold_widening_constants <- Some (get_string "ana.int.interval_threshold_widening_constants"); - Option.get ana_int_config.interval_threshold_widening_constants - -let get_refinement () = - if ana_int_config.refinement = None then - ana_int_config.refinement <- Some (get_string "ana.int.refinement"); - Option.get ana_int_config.refinement - - - -(** Whether for a given ikind, we should compute with wrap-around arithmetic. - * Always for unsigned types, for signed types if 'sem.int.signed_overflow' is 'assume_wraparound' *) -let should_wrap ik = not (Cil.isSigned ik) || get_string "sem.int.signed_overflow" = "assume_wraparound" - -(** Whether for a given ikind, we should assume there are no overflows. - * Always false for unsigned types, true for signed types if 'sem.int.signed_overflow' is 'assume_none' *) -let should_ignore_overflow ik = Cil.isSigned ik && get_string "sem.int.signed_overflow" = "assume_none" - -let widening_thresholds = ResettableLazy.from_fun WideningThresholds.thresholds -let widening_thresholds_desc = ResettableLazy.from_fun (List.rev % WideningThresholds.thresholds) - -type overflow_info = { overflow: bool; underflow: bool;} - -let set_overflow_flag ~cast ~underflow ~overflow ik = - if !AnalysisState.executing_speculative_computations then - (* Do not produce warnings when the operations are not actually happening in code *) - () - else - let signed = Cil.isSigned ik in - if !AnalysisState.postsolving && signed && not cast then - AnalysisState.svcomp_may_overflow := true; - let sign = if signed then "Signed" else "Unsigned" in - match underflow, overflow with - | true, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190; CWE 191] "%s integer overflow and underflow" sign - | true, false -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 191] "%s integer underflow" sign - | false, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190] "%s integer overflow" sign - | false, false -> assert false - -let reset_lazy () = - ResettableLazy.reset widening_thresholds; - ResettableLazy.reset widening_thresholds_desc; - ana_int_config.interval_threshold_widening <- None; - ana_int_config.interval_narrow_by_meet <- None; - ana_int_config.def_exc_widen_by_join <- None; - ana_int_config.interval_threshold_widening_constants <- None; - ana_int_config.refinement <- None - -module type Arith = -sig - type t - val neg: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div: t -> t -> t - val rem: t -> t -> t - - val lt: t -> t -> t - val gt: t -> t -> t - val le: t -> t -> t - val ge: t -> t -> t - val eq: t -> t -> t - val ne: t -> t -> t - - val lognot: t -> t - val logand: t -> t -> t - val logor : t -> t -> t - val logxor: t -> t -> t - - val shift_left : t -> t -> t - val shift_right: t -> t -> t - - val c_lognot: t -> t - val c_logand: t -> t -> t - val c_logor : t -> t -> t +open IntDomain0 -end - -module type ArithIkind = -sig - type t - val neg: Cil.ikind -> t -> t - val add: Cil.ikind -> t -> t -> t - val sub: Cil.ikind -> t -> t -> t - val mul: Cil.ikind -> t -> t -> t - val div: Cil.ikind -> t -> t -> t - val rem: Cil.ikind -> t -> t -> t - - val lt: Cil.ikind -> t -> t -> t - val gt: Cil.ikind -> t -> t -> t - val le: Cil.ikind -> t -> t -> t - val ge: Cil.ikind -> t -> t -> t - val eq: Cil.ikind -> t -> t -> t - val ne: Cil.ikind -> t -> t -> t - - val lognot: Cil.ikind -> t -> t - val logand: Cil.ikind -> t -> t -> t - val logor : Cil.ikind -> t -> t -> t - val logxor: Cil.ikind -> t -> t -> t - - val shift_left : Cil.ikind -> t -> t -> t - val shift_right: Cil.ikind -> t -> t -> t - - val c_lognot: Cil.ikind -> t -> t - val c_logand: Cil.ikind -> t -> t -> t - val c_logor : Cil.ikind -> t -> t -> t - -end - -(* Shared functions between S and Z *) -module type B = -sig - include Lattice.S - type int_t - val bot_of: Cil.ikind -> t - val top_of: Cil.ikind -> t - val to_int: t -> int_t option - val equal_to: int_t -> t -> [`Eq | `Neq | `Top] - - val to_bool: t -> bool option - val to_excl_list: t -> (int_t list * (int64 * int64)) option - val of_excl_list: Cil.ikind -> int_t list -> t - val is_excl_list: t -> bool - - val to_incl_list: t -> int_t list option - - val maximal : t -> int_t option - val minimal : t -> int_t option - - val cast_to: ?suppress_ovwarn:bool -> ?torg:Cil.typ -> Cil.ikind -> t -> t -end - -(** Interface of IntDomain implementations that do not take ikinds for arithmetic operations yet. TODO: Should be ported to S in the future. *) -module type IkindUnawareS = -sig - include B - include Arith with type t := t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: int_t -> t - val of_bool: bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val arbitrary: unit -> t QCheck.arbitrary - val invariant: Cil.exp -> t -> Invariant.t -end - -(** Interface of IntDomain implementations taking an ikind for arithmetic operations *) -module type S = -sig - include B - include ArithIkind with type t:= t - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val neg : ?no_ov:bool -> Cil.ikind -> t -> t - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t - - val join: Cil.ikind -> t -> t -> t - val meet: Cil.ikind -> t -> t -> t - val narrow: Cil.ikind -> t -> t -> t - val widen: Cil.ikind -> t -> t -> t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val is_top_of: Cil.ikind -> t -> bool - val invariant_ikind : Cil.exp -> Cil.ikind -> t -> Invariant.t - - val refine_with_congruence: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_interval: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_excl_list: Cil.ikind -> t -> (int_t list * (int64 * int64)) option -> t - val refine_with_incl_list: Cil.ikind -> t -> int_t list option -> t - - val project: Cil.ikind -> int_precision -> t -> t - val arbitrary: Cil.ikind -> t QCheck.arbitrary -end - -module type SOverflow = -sig - - include S - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val neg : ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val of_int : Cil.ikind -> int_t -> t * overflow_info - - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t * overflow_info - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - - val shift_left : Cil.ikind -> t -> t -> t * overflow_info - - val shift_right : Cil.ikind -> t -> t -> t * overflow_info -end - -module type Y = -sig - (* include B *) - include B - include Arith with type t:= t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val is_top_of: Cil.ikind -> t -> bool - - val project: int_precision -> t -> t - val invariant: Cil.exp -> t -> Invariant.t -end - -module type Z = Y with type int_t = Z.t - - -module IntDomLifter (I : S) = -struct - open Cil - type int_t = I.int_t - type t = { v : I.t; ikind : CilType.Ikind.t } [@@deriving eq, ord, hash] - - let ikind {ikind; _} = ikind - - (* Helper functions *) - let check_ikinds x y = if x.ikind <> y.ikind then raise (IncompatibleIKinds (GobPretty.sprintf "ikinds %a and %a are incompatible. Values: %a and %a" CilType.Ikind.pretty x.ikind CilType.Ikind.pretty y.ikind I.pretty x.v I.pretty y.v)) - let lift op x = {x with v = op x.ikind x.v } - (* For logical operations the result is of type int *) - let lift_logical op x = {v = op x.ikind x.v; ikind = Cil.IInt} - let lift2 op x y = check_ikinds x y; {x with v = op x.ikind x.v y.v } - let lift2_cmp op x y = check_ikinds x y; {v = op x.ikind x.v y.v; ikind = Cil.IInt} - - let bot_of ikind = { v = I.bot_of ikind; ikind} - let bot () = failwith "bot () is not implemented for IntDomLifter." - let is_bot x = I.is_bot x.v - let top_of ikind = { v = I.top_of ikind; ikind} - let top () = failwith "top () is not implemented for IntDomLifter." - let is_top x = I.is_top x.v - - (* Leq does not check for ikind, because it is used in invariant with arguments of different type. - TODO: check ikinds here and fix invariant to work with right ikinds *) - let leq x y = I.leq x.v y.v - let join = lift2 I.join - let meet = lift2 I.meet - let widen = lift2 I.widen - let narrow = lift2 I.narrow - - let show x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - "⊤" - else - I.show x.v (* TODO add ikind to output *) - let pretty () x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - Pretty.text "⊤" - else - I.pretty () x.v (* TODO add ikind to output *) - let pretty_diff () (x, y) = I.pretty_diff () (x.v, y.v) (* TODO check ikinds, add them to output *) - let printXml o x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - BatPrintf.fprintf o "\n\n⊤\n\n\n" - else - I.printXml o x.v (* TODO add ikind to output *) - (* This is for debugging *) - let name () = "IntDomLifter(" ^ (I.name ()) ^ ")" - let to_yojson x = I.to_yojson x.v - let invariant e x = - let e' = Cilfacade.mkCast ~e ~newt:(TInt (x.ikind, [])) in - I.invariant_ikind e' x.ikind x.v - let tag x = I.tag x.v - let arbitrary ik = failwith @@ "Arbitrary not implement for " ^ (name ()) ^ "." - let to_int x = I.to_int x.v - let of_int ikind x = { v = I.of_int ikind x; ikind} - let equal_to i x = I.equal_to i x.v - let to_bool x = I.to_bool x.v - let of_bool ikind b = { v = I.of_bool ikind b; ikind} - let to_excl_list x = I.to_excl_list x.v - let of_excl_list ikind is = {v = I.of_excl_list ikind is; ikind} - let is_excl_list x = I.is_excl_list x.v - let to_incl_list x = I.to_incl_list x.v - let of_interval ?(suppress_ovwarn=false) ikind (lb,ub) = {v = I.of_interval ~suppress_ovwarn ikind (lb,ub); ikind} - let of_congruence ikind (c,m) = {v = I.of_congruence ikind (c,m); ikind} - let starting ?(suppress_ovwarn=false) ikind i = {v = I.starting ~suppress_ovwarn ikind i; ikind} - let ending ?(suppress_ovwarn=false) ikind i = {v = I.ending ~suppress_ovwarn ikind i; ikind} - let maximal x = I.maximal x.v - let minimal x = I.minimal x.v - - let neg = lift I.neg - let add = lift2 I.add - let sub = lift2 I.sub - let mul = lift2 I.mul - let div = lift2 I.div - let rem = lift2 I.rem - let lt = lift2_cmp I.lt - let gt = lift2_cmp I.gt - let le = lift2_cmp I.le - let ge = lift2_cmp I.ge - let eq = lift2_cmp I.eq - let ne = lift2_cmp I.ne - let lognot = lift I.lognot - let logand = lift2 I.logand - let logor = lift2 I.logor - let logxor = lift2 I.logxor - let shift_left x y = {x with v = I.shift_left x.ikind x.v y.v } (* TODO check ikinds*) - let shift_right x y = {x with v = I.shift_right x.ikind x.v y.v } (* TODO check ikinds*) - let c_lognot = lift_logical I.c_lognot - let c_logand = lift2 I.c_logand - let c_logor = lift2 I.c_logor - - let cast_to ?(suppress_ovwarn=false) ?torg ikind x = {v = I.cast_to ~suppress_ovwarn ~torg:(TInt(x.ikind,[])) ikind x.v; ikind} - - let is_top_of ik x = ik = x.ikind && I.is_top_of ik x.v - - let relift x = { v = I.relift x.v; ikind = x.ikind } - - let project p v = { v = I.project v.ikind p v.v; ikind = v.ikind } -end - -module type Ikind = -sig - val ikind: unit -> Cil.ikind -end - -module PtrDiffIkind : Ikind = -struct - let ikind = Cilfacade.ptrdiff_ikind -end - -module IntDomWithDefaultIkind (I: Y) (Ik: Ikind) : Y with type t = I.t and type int_t = I.int_t = -struct - include I - let top () = I.top_of (Ik.ikind ()) - let bot () = I.bot_of (Ik.ikind ()) -end - -module Size = struct (* size in bits as int, range as int64 *) - open Cil - let sign x = if Z.compare x Z.zero < 0 then `Signed else `Unsigned - - let top_typ = TInt (ILongLong, []) - let min_for x = intKindForValue x (sign x = `Unsigned) - let bit = function (* bits needed for representation *) - | IBool -> 1 - | ik -> bytesSizeOfInt ik * 8 - let is_int64_big_int x = Z.fits_int64 x - let card ik = (* cardinality *) - let b = bit ik in - Z.shift_left Z.one b - let bits ik = (* highest bits for neg/pos values *) - let s = bit ik in - if isSigned ik then s-1, s-1 else 0, s - let bits_i64 ik = BatTuple.Tuple2.mapn Int64.of_int (bits ik) - let range ik = - let a,b = bits ik in - let x = if isSigned ik then Z.neg (Z.shift_left Z.one a) (* -2^a *) else Z.zero in - let y = Z.pred (Z.shift_left Z.one b) in (* 2^b - 1 *) - x,y - - let is_cast_injective ~from_type ~to_type = - let (from_min, from_max) = range (Cilfacade.get_ikind from_type) in - let (to_min, to_max) = range (Cilfacade.get_ikind to_type) in - if M.tracing then M.trace "int" "is_cast_injective %a (%a, %a) -> %a (%a, %a)" CilType.Typ.pretty from_type GobZ.pretty from_min GobZ.pretty from_max CilType.Typ.pretty to_type GobZ.pretty to_min GobZ.pretty to_max; - Z.compare to_min from_min <= 0 && Z.compare from_max to_max <= 0 - - let cast t x = (* TODO: overflow is implementation-dependent! *) - if t = IBool then - (* C11 6.3.1.2 Boolean type *) - if Z.equal x Z.zero then Z.zero else Z.one - else - let a,b = range t in - let c = card t in - let y = Z.erem x c in - let y = if Z.gt y b then Z.sub y c - else if Z.lt y a then Z.add y c - else y - in - if M.tracing then M.tracel "cast" "Cast %a to range [%a, %a] (%a) = %a (%s in int64)" GobZ.pretty x GobZ.pretty a GobZ.pretty b GobZ.pretty c GobZ.pretty y (if is_int64_big_int y then "fits" else "does not fit"); - y - - let min_range_sign_agnostic x = - let size ik = - let a,b = bits_i64 ik in - Int64.neg a,b - in - if sign x = `Signed then - size (min_for x) - else - let a, b = size (min_for x) in - if b <= 64L then - let upper_bound_less = Int64.sub b 1L in - let max_one_less = Z.(pred @@ shift_left Z.one (Int64.to_int upper_bound_less)) in - if x <= max_one_less then - a, upper_bound_less - else - a,b - else - a, b - - (* From the number of bits used to represent a positive value, determines the maximal representable value *) - let max_from_bit_range pos_bits = Z.(pred @@ shift_left Z.one (to_int (Z.of_int64 pos_bits))) - - (* From the number of bits used to represent a non-positive value, determines the minimal representable value *) - let min_from_bit_range neg_bits = Z.(if neg_bits = 0L then Z.zero else neg @@ shift_left Z.one (to_int (neg (Z.of_int64 neg_bits)))) - -end - - -module StdTop (B: sig type t val top_of: Cil.ikind -> t end) = struct - open B - (* these should be overwritten for better precision if possible: *) - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ik x = top_of ik - let ending ?(suppress_ovwarn=false) ik x = top_of ik - let maximal x = None - let minimal x = None -end - -module Std (B: sig - type t - val name: unit -> string - val top_of: Cil.ikind -> t - val bot_of: Cil.ikind -> t - val show: t -> string - val equal: t -> t -> bool - end) = struct - include Printable.StdLeaf - let name = B.name (* overwrite the one from Printable.Std *) - open B - let is_top x = failwith "is_top not implemented for IntDomain.Std" - let is_bot x = B.equal x (bot_of Cil.IInt) (* Here we assume that the representation of bottom is independent of the ikind - This may be true for intdomain implementations, but not e.g. for IntDomLifter. *) - let is_top_of ik x = B.equal x (top_of ik) - - (* all output is based on B.show *) - include Printable.SimpleShow ( - struct - type nonrec t = t - let show = show - end - ) - let pretty_diff () (x,y) = dprintf "%s: %a instead of %a" (name ()) pretty x pretty y - - include StdTop (B) -end - -(* Textbook interval arithmetic, without any overflow handling etc. *) -module IntervalArith (Ints_t : IntOps.IntOps) = struct - let min4 a b c d = Ints_t.min (Ints_t.min a b) (Ints_t.min c d) - let max4 a b c d = Ints_t.max (Ints_t.max a b) (Ints_t.max c d) - - let mul (x1, x2) (y1, y2) = - let x1y1 = (Ints_t.mul x1 y1) in - let x1y2 = (Ints_t.mul x1 y2) in - let x2y1 = (Ints_t.mul x2 y1) in - let x2y2 = (Ints_t.mul x2 y2) in - (min4 x1y1 x1y2 x2y1 x2y2, max4 x1y1 x1y2 x2y1 x2y2) - - let shift_left (x1,x2) (y1,y2) = - let y1p = Ints_t.shift_left Ints_t.one y1 in - let y2p = Ints_t.shift_left Ints_t.one y2 in - mul (x1, x2) (y1p, y2p) - - let div (x1, x2) (y1, y2) = - let x1y1n = (Ints_t.div x1 y1) in - let x1y2n = (Ints_t.div x1 y2) in - let x2y1n = (Ints_t.div x2 y1) in - let x2y2n = (Ints_t.div x2 y2) in - let x1y1p = (Ints_t.div x1 y1) in - let x1y2p = (Ints_t.div x1 y2) in - let x2y1p = (Ints_t.div x2 y1) in - let x2y2p = (Ints_t.div x2 y2) in - (min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p) - - let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2) - let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1) - - let neg (x1, x2) = (Ints_t.neg x2, Ints_t.neg x1) - - let one = (Ints_t.one, Ints_t.one) - let zero = (Ints_t.zero, Ints_t.zero) - let top_bool = (Ints_t.zero, Ints_t.one) - - let to_int (x1, x2) = - if Ints_t.equal x1 x2 then Some x1 else None - - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let max_ik' = Ints_t.to_bigint max_ik in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let min_ik' = Ints_t.to_bigint min_ik in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let is_upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - List.exists (Z.equal u) ts - let is_lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - List.exists (Z.equal l) ts -end - -module IntInvariant = -struct - let of_int e ik x = - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.none - - let of_incl_list e ik ps = - match ps with - | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> - assert (List.mem Z.zero ps); - assert (List.mem Z.one ps); - Invariant.none - | [_] when get_bool "witness.invariant.exact" -> - Invariant.none - | _ :: _ :: _ - | [_] | [] -> - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) (Invariant.bot ()) ps - - let of_interval_opt e ik = function - | (Some x1, Some x2) when Z.equal x1 x2 -> - of_int e ik x1 - | x1_opt, x2_opt -> - let (min_ik, max_ik) = Size.range ik in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = - match x1_opt, inexact_type_bounds with - | Some x1, false when Z.equal min_ik x1 -> Invariant.none - | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) - | None, _ -> Invariant.none - in - let i2 = - match x2_opt, inexact_type_bounds with - | Some x2, false when Z.equal x2 max_ik -> Invariant.none - | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) - | None, _ -> Invariant.none - in - Invariant.(i1 && i2) - - let of_interval e ik (x1, x2) = - of_interval_opt e ik (Some x1, Some x2) - - let of_excl_list e ik ns = - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) (Invariant.top ()) ns -end - -module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = -struct - let name () = "intervals" - type int_t = Ints_t.t - type t = (Ints_t.t * Ints_t.t) option [@@deriving eq, ord, hash] - module IArith = IntervalArith (Ints_t) - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - let top_of ik = Some (range ik) - let bot () = None - let bot_of ik = bot () (* TODO: improve *) - - let show = function None -> "bottom" | Some (x,y) -> "["^Ints_t.to_string x^","^Ints_t.to_string y^"]" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) -> - if a = b && b = i then `Eq else if Ints_t.compare a i <= 0 && Ints_t.compare i b <=0 then `Top else `Neq - - let norm ?(suppress_ovwarn=false) ?(cast=false) ik : (t -> t * overflow_info) = function None -> (None, {underflow=false; overflow=false}) | Some (x,y) -> - if Ints_t.compare x y > 0 then - (None,{underflow=false; overflow=false}) - else ( - let (min_ik, max_ik) = range ik in - let underflow = Ints_t.compare min_ik x > 0 in - let overflow = Ints_t.compare max_ik y < 0 in - let ov_info = { underflow = underflow && not suppress_ovwarn; overflow = overflow && not suppress_ovwarn } in - let v = - if underflow || overflow then - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (Ints_t.sub max_ik min_ik) in - let resdiff = Ints_t.abs (Ints_t.sub y x) in - if Ints_t.compare resdiff diff > 0 then - top_of ik - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if Ints_t.compare l u <= 0 then - Some (l, u) - else - (* Interval that wraps around (begins to the right of its end). We can not represent such intervals *) - top_of ik - else if not cast && should_ignore_overflow ik then - let tl, tu = BatOption.get @@ top_of ik in - Some (Ints_t.max tl x, Ints_t.min tu y) - else - top_of ik - else - Some (x,y) - in - (v, ov_info) - ) - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0 - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst - - let meet ik (x:t) y = - match x, y with - | None, z | z, None -> None - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.max x1 y1, Ints_t.min x2 y2) |> fst - - (* TODO: change to_int signature so it returns a big_int *) - let to_int x = Option.bind x (IArith.to_int) - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm ~suppress_ovwarn ik @@ Some (x,y) - let of_int ik (x: int_t) = of_interval ik (x,x) - let zero = Some IArith.zero - let one = Some IArith.one - let top_bool = Some IArith.top_bool - - let of_bool _ik = function true -> one | false -> zero - let to_bool (a: t) = match a with - | None -> None - | Some (l, u) when Ints_t.compare l Ints_t.zero = 0 && Ints_t.compare u Ints_t.zero = 0 -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (fst (range ik), n) - - (* TODO: change signature of maximal, minimal to return big_int*) - let maximal = function None -> None | Some (x,y) -> Some y - let minimal = function None -> None | Some (x,y) -> Some x - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - - let widen ik x y = - match x, y with - | None, z | z, None -> z - | Some (l0,u0), Some (l1,u1) -> - let (min_ik, max_ik) = range ik in - let threshold = get_interval_threshold_widening () in - let l2 = - if Ints_t.compare l0 l1 = 0 then l0 - else if threshold then IArith.lower_threshold l1 min_ik - else min_ik - in - let u2 = - if Ints_t.compare u0 u1 = 0 then u0 - else if threshold then IArith.upper_threshold u1 max_ik - else max_ik - in - norm ik @@ Some (l2,u2) |> fst - let widen ik x y = - let r = widen ik x y in - if M.tracing && not (equal x y) then M.tracel "int" "interval widen %a %a -> %a" pretty x pretty y pretty r; - assert (leq x y); (* TODO: remove for performance reasons? *) - r - - let narrow ik x y = - match x, y with - | _,None | None, _ -> None - | Some (x1,x2), Some (y1,y2) -> - let threshold = get_interval_threshold_widening () in - let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in - norm ik @@ Some (lr,ur) |> fst - - - let narrow ik x y = - if get_interval_narrow_by_meet () then - meet ik x y - else - narrow ik x y - - let log f ~annihilator ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, _ when x = annihilator -> of_bool ik annihilator - | _, Some y when y = annihilator -> of_bool ik annihilator - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) ~annihilator:true - let c_logand = log (&&) ~annihilator:false - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let bit f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - let bitcomp f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{underflow=false; overflow=false})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let logxor = bit (fun _ik -> Ints_t.logxor) - - let logand ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (Ints_t.logand x y) |> fst with Division_by_zero -> top_of ik) - | _, Some y when Ints_t.equal y Ints_t.zero -> of_int ik Ints_t.zero |> fst - | _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst - | _ -> top_of ik - - let logor = bit (fun _ik -> Ints_t.logor) - - let bit1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_int i1 with - | Some x -> of_int ik (f ik x) |> fst - | _ -> top_of ik - - let lognot = bit1 (fun _ik -> Ints_t.lognot) - let shift_right = bitcomp (fun _ik x y -> Ints_t.shift_right x (Ints_t.to_int y)) - - let neg ?no_ov ik = function None -> (None,{underflow=false; overflow=false}) | Some x -> norm ik @@ Some (IArith.neg x) - - let binary_op_with_norm ?no_ov op ik x y = match x, y with - | None, None -> (None, {overflow=false; underflow= false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some x, Some y -> norm ik @@ Some (op x y) - - let add ?no_ov = binary_op_with_norm IArith.add - let mul ?no_ov = binary_op_with_norm IArith.mul - let sub ?no_ov = binary_op_with_norm IArith.sub - - let shift_left ik a b = - match is_bot a, is_bot b with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show a) (show b))) - | _ -> - match a, minimal b, maximal b with - | Some a, Some bl, Some bu when (Ints_t.compare bl Ints_t.zero >= 0) -> - (try - let r = IArith.shift_left a (Ints_t.to_int bl, Ints_t.to_int bu) in - norm ik @@ Some r - with Z.Overflow -> (top_of ik,{underflow=false; overflow=true})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let rem ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (xl, xu), Some (yl, yu) -> - if is_top_of ik x && is_top_of ik y then - (* This is needed to preserve soundness also on things bigger than int32 e.g. *) - (* x: 3803957176L -> T in Interval32 *) - (* y: 4209861404L -> T in Interval32 *) - (* x % y: 3803957176L -> T in Interval32 *) - (* T in Interval32 is [-2147483648,2147483647] *) - (* the code below computes [-2147483647,2147483647] for this though which is unsound *) - top_of ik - else - (* If we have definite values, Ints_t.rem will give a definite result. - * Otherwise we meet with a [range] the result can be in. - * This range is [0, min xu b] if x is positive, and [max xl -b, min xu b] if x can be negative. - * The precise bound b is one smaller than the maximum bound. Negative y give the same result as positive. *) - let pos x = if Ints_t.compare x Ints_t.zero < 0 then Ints_t.neg x else x in - let b = Ints_t.sub (Ints_t.max (pos yl) (pos yu)) Ints_t.one in - let range = if Ints_t.compare xl Ints_t.zero>= 0 then Some (Ints_t.zero, Ints_t.min xu b) else Some (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit (fun _ik -> Ints_t.rem) ik x y) range - - let rec div ?no_ov ik x y = - match x, y with - | None, None -> (bot (),{underflow=false; overflow=false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | (Some (x1,x2) as x), (Some (y1,y2) as y) -> - begin - let is_zero v = Ints_t.compare v Ints_t.zero = 0 in - match y1, y2 with - | l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false}) (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2)) - | _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one))) - | _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false}) - | _ -> binary_op_with_norm IArith.div ik x y - end - - let ne ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik true - else if Ints_t.compare x2 y1 <= 0 && Ints_t.compare y2 x1 <= 0 then - of_bool ik false - else top_bool - - let eq ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 && Ints_t.compare x2 y1 <= 0 then - of_bool ik true - else if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik false - else top_bool - - let ge ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 then of_bool ik true - else if Ints_t.compare x2 y1 < 0 then of_bool ik false - else top_bool - - let le ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 <= 0 then of_bool ik true - else if Ints_t.compare y2 x1 < 0 then of_bool ik false - else top_bool - - let gt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 then of_bool ik true - else if Ints_t.compare x2 y1 <= 0 then of_bool ik false - else top_bool - - let lt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 < 0 then of_bool ik true - else if Ints_t.compare y2 x1 <= 0 then of_bool ik false - else top_bool - - let invariant_ikind e ik = function - | Some (x1, x2) -> - let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in - IntInvariant.of_interval e ik (x1', x2') - | None -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let shrink = function - | Some (l, u) -> (return None) <+> (GobQCheck.shrink pair_arb (l, u) >|= of_interval ik >|= fst) - | None -> empty - in - QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) (fun x -> of_interval ik x |> fst ) pair_arb) - - let modulo n k = - let result = Ints_t.rem n k in - if Ints_t.compare result Ints_t.zero >= 0 then result - else Ints_t.add result k - - let refine_with_congruence ik (intv : t) (cong : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if Ints_t.equal m Ints_t.zero && (Ints_t.compare c x < 0 || Ints_t.compare c y > 0) then None - else if Ints_t.equal m Ints_t.zero then - Some (c, c) - else - let (min_ik, max_ik) = range ik in - let rcx = - if Ints_t.equal x min_ik then x else - Ints_t.add x (modulo (Ints_t.sub c x) (Ints_t.abs m)) in - let lcy = - if Ints_t.equal y max_ik then y else - Ints_t.sub y (modulo (Ints_t.sub y c) (Ints_t.abs m)) in - if Ints_t.compare rcx lcy > 0 then None - else if Ints_t.equal rcx lcy then norm ik @@ Some (rcx, rcx) |> fst - else norm ik @@ Some (rcx, lcy) |> fst - | _ -> None - - let refine_with_congruence ik x y = - let refn = refine_with_congruence ik x y in - if M.tracing then M.trace "refine" "int_refine_with_congruence %a %a -> %a" pretty x pretty y pretty refn; - refn - - let refine_with_interval ik a b = meet ik a b - - let refine_with_excl_list ik (intv : t) (excl : (int_t list * (int64 * int64)) option) : t = - match intv, excl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls, (rl, rh)) -> - let rec shrink op b = - let new_b = (op b (Ints_t.of_int(Bool.to_int(BatList.mem_cmp Ints_t.compare b ls)))) in - if not (Ints_t.equal b new_b) then shrink op new_b else new_b - in - let (min_ik, max_ik) = range ik in - let l' = if Ints_t.equal l min_ik then l else shrink Ints_t.add l in - let u' = if Ints_t.equal u max_ik then u else shrink Ints_t.sub u in - let intv' = norm ik @@ Some (l', u') |> fst in - let range = norm ~suppress_ovwarn:true ik (Some (Ints_t.of_bigint (Size.min_from_bit_range rl), Ints_t.of_bigint (Size.max_from_bit_range rh))) |> fst in - meet ik intv' range - - let refine_with_incl_list ik (intv: t) (incl : (int_t list) option) : t = - match intv, incl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls) -> - let rec min m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> min (Some x) xs | Some m -> if Ints_t.compare m x < 0 then min (Some m) xs else min (Some x) xs in - let rec max m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> max (Some x) xs | Some m -> if Ints_t.compare m x > 0 then max (Some m) xs else max (Some x) xs in - match min None ls, max None ls with - | Some m1, Some m2 -> refine_with_interval ik (Some(l, u)) (Some (m1, m2)) - | _, _-> intv - - let project ik p t = t -end - -(** IntervalSetFunctor that is not just disjunctive completion of intervals, but attempts to be precise for wraparound arithmetic for unsigned types *) -module IntervalSetFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) list = -struct - - module Interval = IntervalFunctor (Ints_t) - module IArith = IntervalArith (Ints_t) - - - let name () = "interval_sets" - - type int_t = Ints_t.t - - let (>.) a b = Ints_t.compare a b > 0 - let (=.) a b = Ints_t.compare a b = 0 - let (<.) a b = Ints_t.compare a b < 0 - let (>=.) a b = Ints_t.compare a b >= 0 - let (<=.) a b = Ints_t.compare a b <= 0 - let (+.) a b = Ints_t.add a b - let (-.) a b = Ints_t.sub a b - - (* - Each domain's element is guaranteed to be in canonical form. That is, each interval contained - inside the set does not overlap with each other and they are not adjacent. - *) - type t = (Ints_t.t * Ints_t.t) list [@@deriving eq, hash, ord] - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - - let top_of ik = [range ik] - - let bot () = [] - - let bot_of ik = bot () - - let show (x: t) = - let show_interval i = Printf.sprintf "[%s, %s]" (Ints_t.to_string (fst i)) (Ints_t.to_string (snd i)) in - List.fold_left (fun acc i -> (show_interval i) :: acc) [] x |> List.rev |> String.concat ", " |> Printf.sprintf "[%s]" - - (* New type definition for the sweeping line algorithm used for implementing join/meet functions. *) - type event = Enter of Ints_t.t | Exit of Ints_t.t - - let unbox_event = function Enter x -> x | Exit x -> x - - let cmp_events x y = - (* Deliberately comparing ints first => Cannot be derived *) - let res = Ints_t.compare (unbox_event x) (unbox_event y) in - if res <> 0 then res - else - begin - match (x, y) with - | (Enter _, Exit _) -> -1 - | (Exit _, Enter _) -> 1 - | (_, _) -> 0 - end - - let interval_set_to_events (xs: t) = - List.concat_map (fun (a, b) -> [Enter a; Exit b]) xs - - let two_interval_sets_to_events (xs: t) (ys: t) = - let xs = interval_set_to_events xs in - let ys = interval_set_to_events ys in - List.merge cmp_events xs ys - - (* Using the sweeping line algorithm, combined_event_list returns a new event list representing the intervals in which at least n intervals in xs overlap - This function is used for both join and meet operations with different parameter n: 1 for join, 2 for meet *) - let combined_event_list lattice_op (xs:event list) = - let l = match lattice_op with `Join -> 1 | `Meet -> 2 in - let aux (interval_count, acc) = function - | Enter x -> (interval_count + 1, if (interval_count + 1) >= l && interval_count < l then (Enter x)::acc else acc) - | Exit x -> (interval_count - 1, if interval_count >= l && (interval_count - 1) < l then (Exit x)::acc else acc) - in - List.fold_left aux (0, []) xs |> snd |> List.rev - - let rec events_to_intervals = function - | [] -> [] - | (Enter x)::(Exit y)::xs -> (x, y)::(events_to_intervals xs) - | _ -> failwith "Invalid events list" - - let remove_empty_gaps (xs: t) = - let aux acc (l, r) = match acc with - | ((a, b)::acc') when (b +. Ints_t.one) >=. l -> (a, r)::acc' - | _ -> (l, r)::acc - in - List.fold_left aux [] xs |> List.rev - - let canonize (xs: t) = - interval_set_to_events xs |> - List.sort cmp_events |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let unop (x: t) op = match x with - | [] -> [] - | _ -> canonize @@ List.concat_map op x - - let binop (x: t) (y: t) op : t = match x, y with - | [], _ -> [] - | _, [] -> [] - | _, _ -> canonize @@ List.concat_map op (BatList.cartesian_product x y) - - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let minimal = function - | [] -> None - | (x, _)::_ -> Some x - - let maximal = function - | [] -> None - | xs -> Some (BatList.last xs |> snd) - - let equal_to_interval i (a, b) = - if a =. b && b =. i then - `Eq - else if a <=. i && i <=. b then - `Top - else - `Neq - - let equal_to i xs = match List.map (equal_to_interval i) xs with - | [] -> failwith "unsupported: equal_to with bottom" - | [`Eq] -> `Eq - | ys when List.for_all ((=) `Neq) ys -> `Neq - | _ -> `Top - - let norm_interval ?(suppress_ovwarn=false) ?(cast=false) ik (x,y) : t*overflow_info = - if x >. y then - ([],{underflow=false; overflow=false}) - else - let (min_ik, max_ik) = range ik in - let underflow = min_ik >. x in - let overflow = max_ik <. y in - let v = if underflow || overflow then - begin - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (max_ik -. min_ik) in - let resdiff = Ints_t.abs (y -. x) in - if resdiff >. diff then - [range ik] - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if l <=. u then - [(l, u)] - else - (* Interval that wraps around (begins to the right of its end). We CAN represent such intervals *) - [(min_ik, u); (l, max_ik)] - else if not cast && should_ignore_overflow ik then - [Ints_t.max min_ik x, Ints_t.min max_ik y] - else - [range ik] - end - else - [(x,y)] - in - if suppress_ovwarn then (v, {underflow=false; overflow=false}) else (v, {underflow; overflow}) - - let norm_intvs ?(suppress_ovwarn=false) ?(cast=false) (ik:ikind) (xs: t) : t*overflow_info = - let res = List.map (norm_interval ~suppress_ovwarn ~cast ik) xs in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let binary_op_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> [op x y]) (BatList.cartesian_product x y) - - let binary_op_with_ovc (x: t) (y: t) op : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> - let res = List.map op (BatList.cartesian_product x y) in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let unary_op_with_norm op (ik:ikind) (x: t) = match x with - | [] -> ([],{overflow=false; underflow=false}) - | _ -> norm_intvs ik @@ List.concat_map (fun x -> [op x]) x - - let rec leq (xs: t) (ys: t) = - let leq_interval (al, au) (bl, bu) = al >=. bl && au <=. bu in - match xs, ys with - | [], _ -> true - | _, [] -> false - | (xl,xr)::xs', (yl,yr)::ys' -> - if leq_interval (xl,xr) (yl,yr) then - leq xs' ys - else if xr <. yl then - false - else - leq xs ys' - - let join ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let meet ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Meet |> - events_to_intervals - - let to_int = function - | [x] -> IArith.to_int x - | _ -> None - - let zero = [IArith.zero] - let one = [IArith.one] - let top_bool = [IArith.top_bool] - - let not_bool (x:t) = - let is_false x = equal x zero in - let is_true x = equal x one in - if is_true x then zero else if is_false x then one else top_bool - - let to_bool = function - | [(l,u)] when l =. Ints_t.zero && u =. Ints_t.zero -> Some false - | x -> if leq zero x then None else Some true - - let of_bool _ = function true -> one | false -> zero - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm_interval ~suppress_ovwarn ~cast:false ik (x,y) - - let of_int ik (x: int_t) = of_interval ik (x, x) - - let lt ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <. min_y then - of_bool ik true - else if min_x >=. max_y then - of_bool ik false - else - top_bool - - let le ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <=. min_y then - of_bool ik true - else if min_x >. max_y then - of_bool ik false - else - top_bool - - let gt ik x y = not_bool @@ le ik x y - - let ge ik x y = not_bool @@ lt ik x y - - let eq ik x y = match x, y with - | (a, b)::[], (c, d)::[] when a =. b && c =. d && a =. c -> - one - | _ -> - if is_bot (meet ik x y) then - zero - else - top_bool - - let ne ik x y = not_bool @@ eq ik x y - let interval_to_int i = Interval.to_int (Some i) - let interval_to_bool i = Interval.to_bool (Some i) - - let log f ik (i1, i2) = - match (interval_to_bool i1, interval_to_bool i2) with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - - let bit f ik (i1, i2) = - match (interval_to_int i1), (interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - - let bitcomp f ik (i1, i2) = - match (interval_to_int i1, interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{overflow=false; underflow=false})) - | _, _ -> (top_of ik,{overflow=false; underflow=false}) - - let logand ik x y = - let interval_logand = bit Ints_t.logand ik in - binop x y interval_logand - - let logor ik x y = - let interval_logor = bit Ints_t.logor ik in - binop x y interval_logor - - let logxor ik x y = - let interval_logxor = bit Ints_t.logxor ik in - binop x y interval_logxor - - let lognot ik x = - let interval_lognot i = - match interval_to_int i with - | Some x -> of_int ik (Ints_t.lognot x) |> fst - | _ -> top_of ik - in - unop x interval_lognot - - let shift_left ik x y = - let interval_shiftleft = bitcomp (fun x y -> Ints_t.shift_left x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftleft - - let shift_right ik x y = - let interval_shiftright = bitcomp (fun x y -> Ints_t.shift_right x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftright - - let c_lognot ik x = - let log1 f ik i1 = - match interval_to_bool i1 with - | Some x -> of_bool ik (f x) - | _ -> top_of ik - in - let interval_lognot = log1 not ik in - unop x interval_lognot - - let c_logand ik x y = - let interval_logand = log (&&) ik in - binop x y interval_logand - - let c_logor ik x y = - let interval_logor = log (||) ik in - binop x y interval_logor - - let add ?no_ov = binary_op_with_norm IArith.add - let sub ?no_ov = binary_op_with_norm IArith.sub - let mul ?no_ov = binary_op_with_norm IArith.mul - let neg ?no_ov = unary_op_with_norm IArith.neg - - let div ?no_ov ik x y = - let rec interval_div x (y1, y2) = begin - let top_of ik = top_of ik |> List.hd in - let is_zero v = v =. Ints_t.zero in - match y1, y2 with - | l, u when is_zero l && is_zero u -> top_of ik (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> interval_div x (Ints_t.one,y2) - | _, u when is_zero u -> interval_div x (y1, Ints_t.(neg one)) - | _ when leq (of_int ik (Ints_t.zero) |> fst) ([(y1,y2)]) -> top_of ik - | _ -> IArith.div x (y1, y2) - end - in binary_op_with_norm interval_div ik x y - - let rem ik x y = - let interval_rem (x, y) = - if Interval.is_top_of ik (Some x) && Interval.is_top_of ik (Some y) then - top_of ik - else - let (xl, xu) = x in let (yl, yu) = y in - let pos x = if x <. Ints_t.zero then Ints_t.neg x else x in - let b = (Ints_t.max (pos yl) (pos yu)) -. Ints_t.one in - let range = if xl >=. Ints_t.zero then (Ints_t.zero, Ints_t.min xu b) else (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit Ints_t.rem ik (x, y)) [range] - in - binop x y interval_rem - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik x = norm_intvs ~cast:true ik x - - (* - narrows down the extremeties of xs if they are equal to boundary values of the ikind with (possibly) narrower values from ys - *) - let narrow ik xs ys = match xs ,ys with - | [], _ -> [] | _ ,[] -> xs - | _, _ -> - let min_xs = minimal xs |> Option.get in - let max_xs = maximal xs |> Option.get in - let min_ys = minimal ys |> Option.get in - let max_ys = maximal ys |> Option.get in - let min_range,max_range = range ik in - let threshold = get_interval_threshold_widening () in - let min = if min_xs =. min_range || threshold && min_ys >. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in - let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in - xs - |> (function (_, y)::z -> (min, y)::z | _ -> []) - |> List.rev - |> (function (x, _)::z -> (x, max)::z | _ -> []) - |> List.rev - - (* - 1. partitions the intervals of xs by assigning each of them to the an interval in ys that includes it. - and joins all intervals in xs assigned to the same interval in ys as one interval. - 2. checks for every pair of adjacent pairs whether the pairs did approach (if you compare the intervals from xs and ys) and merges them if it is the case. - 3. checks whether partitions at the extremeties are approaching infinity (and expands them to infinity. in that case) - - The expansion (between a pair of adjacent partitions or at extremeties ) stops at a threshold. - *) - let widen ik xs ys = - let (min_ik,max_ik) = range ik in - let threshold = get_bool "ana.int.interval_threshold_widening" in - let upper_threshold (_,u) = IArith.upper_threshold u max_ik in - let lower_threshold (l,_) = IArith.lower_threshold l min_ik in - (*obtain partitioning of xs intervals according to the ys interval that includes them*) - let rec interval_sets_to_partitions (ik: ikind) (acc : (int_t * int_t) option) (xs: t) (ys: t)= - match xs,ys with - | _, [] -> [] - | [], (y::ys) -> (acc,y):: interval_sets_to_partitions ik None [] ys - | (x::xs), (y::ys) when Interval.leq (Some x) (Some y) -> interval_sets_to_partitions ik (Interval.join ik acc (Some x)) xs (y::ys) - | (x::xs), (y::ys) -> (acc,y) :: interval_sets_to_partitions ik None (x::xs) ys - in - let interval_sets_to_partitions ik xs ys = interval_sets_to_partitions ik None xs ys in - (*merge a pair of adjacent partitions*) - let merge_pair ik (a,b) (c,d) = - let new_a = function - | None -> Some (upper_threshold b, upper_threshold b) - | Some (ax,ay) -> Some (ax, upper_threshold b) - in - let new_c = function - | None -> Some (lower_threshold d, lower_threshold d) - | Some (cx,cy) -> Some (lower_threshold d, cy) - in - if threshold && (lower_threshold d +. Ints_t.one) >. (upper_threshold b) then - [(new_a a,(fst b, upper_threshold b)); (new_c c, (lower_threshold d, snd d))] - else - [(Interval.join ik a c, (Interval.join ik (Some b) (Some d) |> Option.get))] - in - let partitions_are_approaching part_left part_right = match part_left, part_right with - | (Some (_, left_x), (_, left_y)), (Some (right_x, _), (right_y, _)) -> (right_x -. left_x) >. (right_y -. left_y) - | _,_ -> false - in - (*merge all approaching pairs of adjacent partitions*) - let rec merge_list ik = function - | [] -> [] - | x::y::xs when partitions_are_approaching x y -> merge_list ik ((merge_pair ik x y) @ xs) - | x::xs -> x :: merge_list ik xs - in - (*expands left extremity*) - let widen_left = function - | [] -> [] - | (None,(lb,rb))::ts -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (None, (lt,rb))::ts - | (Some (la,ra), (lb,rb))::ts when lb <. la -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (Some (la,ra),(lt,rb))::ts - | x -> x - in - (*expands right extremity*) - let widen_right x = - let map_rightmost = function - | [] -> [] - | (None,(lb,rb))::ts -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (None, (lb,ut))::ts - | (Some (la,ra), (lb,rb))::ts when ra <. rb -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (Some (la,ra),(lb,ut))::ts - | x -> x - in - List.rev x |> map_rightmost |> List.rev - in - interval_sets_to_partitions ik xs ys |> merge_list ik |> widen_left |> widen_right |> List.map snd - - let starting ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (fst (range ik), n) - - let invariant_ikind e ik xs = - List.map (fun x -> Interval.invariant_ikind e ik (Some x)) xs |> - let open Invariant in List.fold_left (||) (bot ()) - - let modulo n k = - let result = Ints_t.rem n k in - if result >=. Ints_t.zero then result - else result +. k - - let refine_with_congruence ik (intvs: t) (cong: (int_t * int_t ) option): t = - let refine_with_congruence_interval ik (cong : (int_t * int_t ) option) (intv : (int_t * int_t ) option): t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =. Ints_t.zero && (c <. x || c >. y) then [] - else if m =. Ints_t.zero then - [(c, c)] - else - let (min_ik, max_ik) = range ik in - let rcx = - if x =. min_ik then x else - x +. (modulo (c -. x) (Ints_t.abs m)) in - let lcy = - if y =. max_ik then y else - y -. (modulo (y -. c) (Ints_t.abs m)) in - if rcx >. lcy then [] - else if rcx =. lcy then norm_interval ik (rcx, rcx) |> fst - else norm_interval ik (rcx, lcy) |> fst - | _ -> [] - in - List.concat_map (fun x -> refine_with_congruence_interval ik cong (Some x)) intvs - - let refine_with_interval ik xs = function None -> [] | Some (a,b) -> meet ik xs [(a,b)] - - let refine_with_incl_list ik intvs = function - | None -> intvs - | Some xs -> meet ik intvs (List.map (fun x -> (x,x)) xs) - - let excl_range_to_intervalset (ik: ikind) ((min, max): int_t * int_t) (excl: int_t): t = - let intv1 = (min, excl -. Ints_t.one) in - let intv2 = (excl +. Ints_t.one, max) in - norm_intvs ik ~suppress_ovwarn:true [intv1 ; intv2] |> fst - - let of_excl_list ik (excls: int_t list) = - let excl_list = List.map (excl_range_to_intervalset ik (range ik)) excls in - let res = List.fold_left (meet ik) (top_of ik) excl_list in - res - - let refine_with_excl_list ik (intv : t) = function - | None -> intv - | Some (xs, range) -> - let excl_to_intervalset (ik: ikind) ((rl, rh): (int64 * int64)) (excl: int_t): t = - excl_range_to_intervalset ik (Ints_t.of_bigint (Size.min_from_bit_range rl),Ints_t.of_bigint (Size.max_from_bit_range rh)) excl - in - let excl_list = List.map (excl_to_intervalset ik range) xs in - List.fold_left (meet ik) intv excl_list - - let project ik p t = t - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let list_pair_arb = QCheck.small_list pair_arb in - let canonize_randomly_generated_list = (fun x -> norm_intvs ik x |> fst) in - let shrink xs = GobQCheck.shrink list_pair_arb xs >|= canonize_randomly_generated_list - in QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) canonize_randomly_generated_list list_pair_arb) -end - -module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct - include D - - let add ?no_ov ik x y = fst @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = fst @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = fst @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = fst @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = fst @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = fst @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = fst @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = fst @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = fst @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = fst @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = fst @@ D.shift_left ik x y - - let shift_right ik x y = fst @@ D.shift_right ik x y -end - -module IntIkind = struct let ikind () = Cil.IInt end -module Interval = IntervalFunctor (IntOps.BigIntOps) -module Interval32 = IntDomWithDefaultIkind (IntDomLifter (SOverflowUnlifter (IntervalFunctor (IntOps.Int64Ops)))) (IntIkind) -module IntervalSet = IntervalSetFunctor (IntOps.BigIntOps) -module Integers (Ints_t : IntOps.IntOps): IkindUnawareS with type t = Ints_t.t and type int_t = Ints_t.t = (* no top/bot, order is <= *) -struct - include Printable.Std - let name () = "integers" - type t = Ints_t.t [@@deriving eq, ord, hash] - type int_t = Ints_t.t - let top () = raise Unknown - let bot () = raise Error - let top_of ik = top () - let bot_of ik = bot () - let show (x: Ints_t.t) = Ints_t.to_string x - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - (* is_top and is_bot are never called, but if they were, the Std impl would raise their exception, so we overwrite them: *) - let is_top _ = false - let is_bot _ = false - - let equal_to i x = if i > x then `Neq else `Top - let leq x y = x <= y - let join x y = if Ints_t.compare x y > 0 then x else y - let widen = join - let meet x y = if Ints_t.compare x y > 0 then y else x - let narrow = meet - - let of_bool x = if x then Ints_t.one else Ints_t.zero - let to_bool' x = x <> Ints_t.zero - let to_bool x = Some (to_bool' x) - let of_int x = x - let to_int x = Some x - - let neg = Ints_t.neg - let add = Ints_t.add (* TODO: signed overflow is undefined behavior! *) - let sub = Ints_t.sub - let mul = Ints_t.mul - let div = Ints_t.div - let rem = Ints_t.rem - let lt n1 n2 = of_bool (n1 < n2) - let gt n1 n2 = of_bool (n1 > n2) - let le n1 n2 = of_bool (n1 <= n2) - let ge n1 n2 = of_bool (n1 >= n2) - let eq n1 n2 = of_bool (n1 = n2) - let ne n1 n2 = of_bool (n1 <> n2) - let lognot = Ints_t.lognot - let logand = Ints_t.logand - let logor = Ints_t.logor - let logxor = Ints_t.logxor - let shift_left n1 n2 = Ints_t.shift_left n1 (Ints_t.to_int n2) - let shift_right n1 n2 = Ints_t.shift_right n1 (Ints_t.to_int n2) - let c_lognot n1 = of_bool (not (to_bool' n1)) - let c_logand n1 n2 = of_bool ((to_bool' n1) && (to_bool' n2)) - let c_logor n1 n2 = of_bool ((to_bool' n1) || (to_bool' n2)) - let cast_to ?(suppress_ovwarn=false) ?torg t x = failwith @@ "Cast_to not implemented for " ^ (name ()) ^ "." - let arbitrary ik = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 (* TODO: use ikind *) - let invariant _ _ = Invariant.none (* TODO *) -end - -module FlatPureIntegers: IkindUnawareS with type t = int64 and type int_t = int64 = (* Integers, but raises Unknown/Error on join/meet *) -struct - include Integers(IntOps.Int64Ops) - let top () = raise Unknown - let bot () = raise Error - let leq = equal - let pretty_diff () (x,y) = Pretty.dprintf "Integer %a instead of %a" pretty x pretty y - let join x y = if equal x y then x else top () - let meet x y = if equal x y then x else bot () -end - -module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) -struct - type int_t = Base.int_t - include Lattice.FlatConf (struct - include Printable.DefaultConf - let top_name = "Unknown int" - let bot_name = "Error int" - end) (Base) - - let top_of ik = top () - let bot_of ik = bot () - - - let name () = "flat integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ikind x = top_of ikind - let ending ?(suppress_ovwarn=false) ikind x = top_of ikind - let maximal x = None - let minimal x = None - - let lift1 f x = match x with - | `Lifted x -> - (try `Lifted (f x) with Unknown -> `Top | Error -> `Bot) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> - (try `Lifted (f x y) with Unknown -> `Top | Error -> `Bot) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) -struct - include Lattice.LiftPO (struct - include Printable.DefaultConf - let top_name = "MaxInt" - let bot_name = "MinInt" - end) (Base) - type int_t = Base.int_t - let top_of ik = top () - let bot_of ik = bot () - include StdTop (struct type nonrec t = t let top_of = top_of end) - - let name () = "lifted integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let lift1 f x = match x with - | `Lifted x -> `Lifted (f x) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> `Lifted (f x y) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Flattened = Flat (Integers (IntOps.Int64Ops)) -module Lifted = Lift (Integers (IntOps.Int64Ops)) - -module Reverse (Base: IkindUnawareS) = -struct - include Base - include (Lattice.Reverse (Base) : Lattice.S with type t := Base.t) -end - -module BISet = struct - include SetDomain.Make (IntOps.BigIntOps) - let is_singleton s = cardinal s = 1 -end - -(* The module [Exclusion] constains common functionality about handling of exclusion sets between [DefExc] and [Enums] *) -module Exclusion = -struct - module R = Interval32 - (* We use these types for the functions in this module to make the intended meaning more explicit *) - type t = Exc of BISet.t * Interval32.t - type inc = Inc of BISet.t [@@unboxed] - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.succ (Z.add (Z.neg (min_of_range r)) (max_of_range r)) - - let cardinality_BISet s = - Z.of_int (BISet.cardinal s) - - let leq_excl_incl (Exc (xs, r)) (Inc ys) = - (* For a <= b to hold, the cardinalities must fit, i.e. |a| <= |b|, which implies |min_r, max_r| - |xs| <= |ys|. We check this first. *) - let lower_bound_cardinality_a = Z.sub (cardinality_of_range r) (cardinality_BISet xs) in - let card_b = cardinality_BISet ys in - if Z.compare lower_bound_cardinality_a card_b > 0 then - false - else (* The cardinality did fit, so we check for all elements that are represented by range r, whether they are in (xs union ys) *) - let min_a = min_of_range r in - let max_a = max_of_range r in - GobZ.for_all_range (fun el -> BISet.mem el xs || BISet.mem el ys) (min_a, max_a) - - let leq (Exc (xs, r)) (Exc (ys, s)) = - let min_a, max_a = min_of_range r, max_of_range r in - let excluded_check = BISet.for_all (fun y -> BISet.mem y xs || Z.compare y min_a < 0 || Z.compare y max_a > 0) ys in (* if true, then the values ys, that are not in b, also do not occur in a *) - if not excluded_check - then false - else begin (* Check whether all elements that are in the range r, but not in s, are in xs, i.e. excluded. *) - if R.leq r s then true - else begin if Z.compare (cardinality_BISet xs) (Z.sub (cardinality_of_range r) (cardinality_of_range s)) >= 0 (* Check whether the number of excluded elements in a is as least as big as |min_r, max_r| - |min_s, max_s| *) - then - let min_b, max_b = min_of_range s, max_of_range s in - let leq1 = (* check whether the elements in [r_l; s_l-1] are all in xs, i.e. excluded *) - if Z.compare min_a min_b < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (min_a, Z.pred min_b) - else - true - in - let leq2 () = (* check whether the elements in [s_u+1; r_u] are all in xs, i.e. excluded *) - if Z.compare max_b max_a < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (Z.succ max_b, max_a) - else - true - in - leq1 && (leq2 ()) - else - false - end - end -end - -module DefExc : S with type int_t = Z.t = (* definite or set of excluded values *) -struct - module S = BISet - module R = Interval32 (* range for exclusion *) - - (* Ikind used for intervals representing the domain *) - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - - type t = [ - | `Excluded of S.t * R.t - | `Definite of Z.t - | `Bot - ] [@@deriving eq, ord, hash] - type int_t = Z.t - let name () = "def_exc" - - - let top_range = R.of_interval range_ikind (-99L, 99L) (* Since there is no top ikind we use a range that includes both ILongLong [-63,63] and IULongLong [0,64]. Only needed for intermediate range computation on longs. Correct range is set by cast. *) - let top () = `Excluded (S.empty (), top_range) - let bot () = `Bot - let top_of ik = `Excluded (S.empty (), size ik) - let bot_of ik = bot () - - let show x = - let short_size x = "("^R.show x^")" in - match x with - | `Bot -> "Error int" - | `Definite x -> Z.to_string x - (* Print the empty exclusion as if it was a distinct top element: *) - | `Excluded (s,l) when S.is_empty s -> "Unknown int" ^ short_size l - (* Prepend the exclusion sets with something: *) - | `Excluded (s,l) -> "Not " ^ S.show s ^ short_size l - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let maximal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.max_of_range r) - | `Bot -> None - - let minimal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.min_of_range r) - | `Bot -> None - - let in_range r i = - if Z.compare i Z.zero < 0 then - let lowerb = Exclusion.min_of_range r in - Z.compare lowerb i <= 0 - else - let upperb = Exclusion.max_of_range r in - Z.compare i upperb <= 0 - - let is_top x = x = top () - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Definite x -> if i = x then `Eq else `Neq - | `Excluded (s,r) -> if S.mem i s then `Neq else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik = function - | `Excluded (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - `Excluded (s, r) - else if ik = IBool then (* downcast to bool *) - if S.mem Z.zero s then - `Definite Z.one - else - `Excluded (S.empty(), r') - else - (* downcast: may overflow *) - (* let s' = S.map (Size.cast ik) s in *) - (* We want to filter out all i in s' where (t)x with x in r could be i. *) - (* Since this is hard to compute, we just keep all i in s' which overflowed, since those are safe - all i which did not overflow may now be possible due to overflow of r. *) - (* S.diff s' s, r' *) - (* The above is needed for test 21/03, but not sound! See example https://github.com/goblint/analyzer/pull/95#discussion_r483023140 *) - `Excluded (S.empty (), r') - | `Definite x -> `Definite (Size.cast ik x) - | `Bot -> `Bot - - (* Wraps definite values and excluded values according to the ikind. - * For an `Excluded s,r , assumes that r is already an overapproximation of the range of possible values. - * r might be larger than the possible range of this type; the range of the returned `Excluded set will be within the bounds of the ikind. - *) - let norm ik v = - match v with - | `Excluded (s, r) -> - let possibly_overflowed = not (R.leq r (size ik)) || not (S.for_all (in_range (size ik)) s) in - (* If no overflow occurred, just return x *) - if not possibly_overflowed then ( - v - ) - (* Else, if an overflow might have occurred but we should just ignore it *) - else if should_ignore_overflow ik then ( - let r = size ik in - (* filter out excluded elements that are not in the range *) - let mapped_excl = S.filter (in_range r) s in - `Excluded (mapped_excl, r) - ) - (* Else, if an overflow occurred that we should not treat with wrap-around, go to top *) - else if not (should_wrap ik) then ( - top_of ik - ) else ( - (* Else an overflow occurred that we should treat with wrap-around *) - let r = size ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - let mapped_excl = S.map (fun excl -> Size.cast ik excl) s in - match ik with - | IBool -> - begin match S.mem Z.zero mapped_excl, S.mem Z.one mapped_excl with - | false, false -> `Excluded (mapped_excl, r) (* Not {} -> Not {} *) - | true, false -> `Definite Z.one (* Not {0} -> 1 *) - | false, true -> `Definite Z.zero (* Not {1} -> 0 *) - | true, true -> `Bot (* Not {0, 1} -> bot *) - end - | ik -> - `Excluded (mapped_excl, r) - ) - | `Definite x -> - let min, max = Size.range ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - if should_wrap ik then ( - cast_to ik v - ) - else if Z.compare min x <= 0 && Z.compare x max <= 0 then ( - v - ) - else if should_ignore_overflow ik then ( - M.warn ~category:M.Category.Integer.overflow "DefExc: Value was outside of range, indicating overflow, but 'sem.int.signed_overflow' is 'assume_none' -> Returned Bot"; - `Bot - ) - else ( - top_of ik - ) - | `Bot -> `Bot - - let leq x y = match (x,y) with - (* `Bot <= x is always true *) - | `Bot, _ -> true - (* Anything except bot <= bot is always false *) - | _, `Bot -> false - (* Two known values are leq whenever equal *) - | `Definite (x: int_t), `Definite y -> x = y - (* A definite value is leq all exclusion sets that don't contain it *) - | `Definite x, `Excluded (s,r) -> in_range r x && not (S.mem x s) - (* No finite exclusion set can be leq than a definite value *) - | `Excluded (xs, xr), `Definite d -> - Exclusion.(leq_excl_incl (Exc (xs, xr)) (Inc (S.singleton d))) - | `Excluded (xs,xr), `Excluded (ys,yr) -> - Exclusion.(leq (Exc (xs,xr)) (Exc (ys, yr))) - - let join' ?range ik x y = - match (x,y) with - (* The least upper bound with the bottom element: *) - | `Bot, x -> x - | x, `Bot -> x - (* The case for two known values: *) - | `Definite (x: int_t), `Definite y -> - (* If they're equal, it's just THAT value *) - if x = y then `Definite x - (* Unless one of them is zero, we can exclude it: *) - else - let a,b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval range_ikind a) (R.of_interval range_ikind b) in - `Excluded ((if Z.equal x Z.zero || Z.equal y Z.zero then S.empty () else S.singleton Z.zero), r) - (* A known value and an exclusion set... the definite value should no - * longer be excluded: *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> - if not (in_range r x) then - let a = R.of_interval range_ikind (Size.min_range_sign_agnostic x) in - `Excluded (S.remove x s, R.join a r) - else - `Excluded (S.remove x s, r) - (* For two exclusion sets, only their intersection can be excluded: *) - | `Excluded (x,wx), `Excluded (y,wy) -> `Excluded (S.inter x y, range |? R.join wx wy) - - let join ik = join' ik - - - let widen ik x y = - if get_def_exc_widen_by_join () then - join' ik x y - else if equal x y then - x - else - join' ~range:(size ik) ik x y - - - let meet ik x y = - match (x,y) with - (* Greatest LOWER bound with the least element is trivial: *) - | `Bot, _ -> `Bot - | _, `Bot -> `Bot - (* Definite elements are either equal or the glb is bottom *) - | `Definite x, `Definite y -> if x = y then `Definite x else `Bot - (* The glb of a definite element and an exclusion set is either bottom or - * just the element itself, if it isn't in the exclusion set *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> if S.mem x s || not (in_range r x) then `Bot else `Definite x - (* The greatest lower bound of two exclusion sets is their union, this is - * just DeMorgans Law *) - | `Excluded (x,r1), `Excluded (y,r2) -> - let r' = R.meet r1 r2 in - let s' = S.union x y |> S.filter (in_range r') in - `Excluded (s', r') - - let narrow ik x y = x - - let of_int ik x = norm ik @@ `Definite x - let to_int x = match x with - | `Definite x -> Some x - | _ -> None - - let from_excl ikind (s: S.t) = norm ikind @@ `Excluded (s, size ikind) - - let of_bool_cmp ik x = of_int ik (if x then Z.one else Z.zero) - let of_bool = of_bool_cmp - let to_bool x = - match x with - | `Definite x -> Some (IntOps.BigIntOps.to_bool x) - | `Excluded (s,r) when S.mem Z.zero s -> Some true - | _ -> None - let top_bool = `Excluded (S.empty (), R.of_interval range_ikind (0L, 1L)) - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then S.singleton Z.zero else S.empty () in - norm ik @@ (`Excluded (ex, r)) - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let of_excl_list t l = - let r = size t in (* elements in l are excluded from the full range of t! *) - `Excluded (List.fold_right S.add l (S.empty ()), r) - let is_excl_list l = match l with `Excluded _ -> true | _ -> false - let to_excl_list (x:t) = match x with - | `Definite _ -> None - | `Excluded (s,r) -> Some (S.elements s, (Option.get (R.minimal r), Option.get (R.maximal r))) - | `Bot -> None - - let to_incl_list x = match x with - | `Definite x -> Some [x] - | `Excluded _ -> None - | `Bot -> None - - let apply_range f r = (* apply f to the min/max of the old range r to get a new range *) - (* If the Int64 might overflow on us during computation, we instead go to top_range *) - match R.minimal r, R.maximal r with - | _ -> - let rf m = (size % Size.min_for % f) (m r) in - let r1, r2 = rf Exclusion.min_of_range, rf Exclusion.max_of_range in - R.join r1 r2 - - (* Default behaviour for unary operators, simply maps the function to the - * DefExc data structure. *) - let lift1 f ik x = norm ik @@ match x with - | `Excluded (s,r) -> - let s' = S.map f s in - `Excluded (s', apply_range f r) - | `Definite x -> `Definite (f x) - | `Bot -> `Bot - - let lift2 f ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite _ - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (f x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - (* Default behaviour for binary operators that are injective in either - * argument, so that Exclusion Sets can be used: *) - let lift2_inj f ik x y = - let def_exc f x s r = `Excluded (S.map (f x) s, apply_range (f x) r) in - norm ik @@ - match x,y with - (* If both are exclusion sets, there isn't anything we can do: *) - | `Excluded _, `Excluded _ -> top () - (* A definite value should be applied to all members of the exclusion set *) - | `Definite x, `Excluded (s,r) -> def_exc f x s r - (* Same thing here, but we should flip the operator to map it properly *) - | `Excluded (s,r), `Definite x -> def_exc (Batteries.flip f) x s r - (* The good case: *) - | `Definite x, `Definite y -> `Definite (f x y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The equality check: *) - let eq ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x equal to an exclusion set, if it is a member then NO otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt false else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt false else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x = y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The inequality check: *) - let ne ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x unequal to an exclusion set, if it is a member then Yes otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt true else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt true else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x <> y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - let neg ?no_ov ik (x :t) = norm ik @@ lift1 Z.neg ik x - let add ?no_ov ik x y = norm ik @@ lift2_inj Z.add ik x y - - let sub ?no_ov ik x y = norm ik @@ lift2_inj Z.sub ik x y - let mul ?no_ov ik x y = norm ik @@ match x, y with - | `Definite z, (`Excluded _ | `Definite _) when Z.equal z Z.zero -> x - | (`Excluded _ | `Definite _), `Definite z when Z.equal z Z.zero -> y - | `Definite a, `Excluded (s,r) - (* Integer multiplication with even numbers is not injective. *) - (* Thus we cannot exclude the values to which the exclusion set would be mapped to. *) - | `Excluded (s,r),`Definite a when Z.equal (Z.rem a (Z.of_int 2)) Z.zero -> `Excluded (S.empty (), apply_range (Z.mul a) r) - | _ -> lift2_inj Z.mul ik x y - let div ?no_ov ik x y = lift2 Z.div ik x y - let rem ik x y = lift2 Z.rem ik x y - - (* Comparison handling copied from Enums. *) - let handle_bot x y f = match x, y with - | `Bot, `Bot -> `Bot - | `Bot, _ - | _, `Bot -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> f () - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let lognot = lift1 Z.lognot - - let logand ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite i -> - (* Except in two special cases *) - if Z.equal i Z.zero then - `Definite Z.zero - else if Z.equal i Z.one then - of_interval IBool (Z.zero, Z.one) - else - top () - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (Z.logand x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - norm ik @@ lift2 shift_op_big_int ik x y - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - (* TODO: lift does not treat Not {0} as true. *) - let c_logand ik x y = - match to_bool x, to_bool y with - | Some false, _ - | _, Some false -> - of_bool ik false - | _, _ -> - lift2 IntOps.BigIntOps.c_logand ik x y - let c_logor ik x y = - match to_bool x, to_bool y with - | Some true, _ - | _, Some true -> - of_bool ik true - | _, _ -> - lift2 IntOps.BigIntOps.c_logor ik x y - let c_lognot ik = eq ik (of_int ik Z.zero) - - let invariant_ikind e ik (x:t) = - match x with - | `Definite x -> - IntInvariant.of_int e ik x - | `Excluded (s, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let si = IntInvariant.of_excl_list e ik (S.elements s) in - Invariant.(ri && si) - | `Bot -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - let excluded s = from_excl ik s in - let definite x = of_int ik x in - let shrink = function - | `Excluded (s, _) -> GobQCheck.shrink (S.arbitrary ()) s >|= excluded (* S TODO: possibly shrink excluded to definite *) - | `Definite x -> (return `Bot) <+> (GobQCheck.shrink (IntOps.BigIntOps.arbitrary ()) x >|= definite) - | `Bot -> empty - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map excluded (S.arbitrary ()); - 10, QCheck.map definite (IntOps.BigIntOps.arbitrary ()); - 1, QCheck.always `Bot - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = a - let refine_with_interval ik a b = match a, b with - | x, Some(i) -> meet ik x (of_interval ik i) - | _ -> a - let refine_with_excl_list ik a b = match a, b with - | `Excluded (s, r), Some(ls, _) -> meet ik (`Excluded (s, r)) (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - let refine_with_incl_list ik a b = a - - let project ik p t = t -end - -(* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) -module Enums : S with type int_t = Z.t = struct - module R = Interval32 (* range for exclusion *) - - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - type t = Inc of BISet.t | Exc of BISet.t * R.t [@@deriving eq, ord, hash] (* inclusion/exclusion set *) - - type int_t = Z.t - let name () = "enums" - let bot () = failwith "bot () not implemented for Enums" - let top () = failwith "top () not implemented for Enums" - let bot_of ik = Inc (BISet.empty ()) - let top_bool = Inc (BISet.of_list [Z.zero; Z.one]) - let top_of ik = - match ik with - | IBool -> top_bool - | _ -> Exc (BISet.empty (), size ik) - - let range ik = Size.range ik - -(* - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.add (Z.neg (min_of_range r)) (max_of_range r) *) - let value_in_range (min, max) v = Z.compare min v <= 0 && Z.compare v max <= 0 - - let show = function - | Inc xs when BISet.is_empty xs -> "bot" - | Inc xs -> "{" ^ (String.concat ", " (List.map Z.to_string (BISet.elements xs))) ^ "}" - | Exc (xs,r) -> "not {" ^ (String.concat ", " (List.map Z.to_string (BISet.elements xs))) ^ "} " ^ "("^R.show r^")" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - (* Normalization function for enums, that handles overflows for Inc. - As we do not compute on Excl, we do not have to perform any overflow handling for it. *) - let norm ikind v = - let min, max = range ikind in - (* Whether the value v lies within the values of the specified ikind. *) - let value_in_ikind v = - Z.compare min v <= 0 && Z.compare v max <= 0 - in - match v with - | Inc xs when BISet.for_all value_in_ikind xs -> v - | Inc xs -> - if should_wrap ikind then - Inc (BISet.map (Size.cast ikind) xs) - else if should_ignore_overflow ikind then - Inc (BISet.filter value_in_ikind xs) - else - top_of ikind - | Exc (xs, r) -> - (* The following assert should hold for Exc, therefore we do not have to overflow handling / normalization for it: - let range_in_ikind r = - R.leq r (size ikind) - in - let r_min, r_max = min_of_range r, max_of_range r in - assert (range_in_ikind r && BISet.for_all (value_in_range (r_min, r_max)) xs); *) - begin match ikind with - | IBool -> - begin match BISet.mem Z.zero xs, BISet.mem Z.one xs with - | false, false -> top_bool (* Not {} -> {0, 1} *) - | true, false -> Inc (BISet.singleton Z.one) (* Not {0} -> {1} *) - | false, true -> Inc (BISet.singleton Z.zero) (* Not {1} -> {0} *) - | true, true -> bot_of ikind (* Not {0, 1} -> bot *) - end - | _ -> - v - end - - - let equal_to i = function - | Inc x -> - if BISet.mem i x then - if BISet.is_singleton x then `Eq - else `Top - else `Neq - | Exc (x, r) -> - if BISet.mem i x then `Neq - else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik v = norm ik @@ match v with - | Exc (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - Exc (s, r) - else if ik = IBool then (* downcast to bool *) - if BISet.mem Z.zero s then - Inc (BISet.singleton Z.one) - else - Exc (BISet.empty(), r') - else (* downcast: may overflow *) - Exc ((BISet.empty ()), r') - | Inc xs -> - let casted_xs = BISet.map (Size.cast ik) xs in - if Cil.isSigned ik && not (BISet.equal xs casted_xs) - then top_of ik (* When casting into a signed type and the result does not fit, the behavior is implementation-defined *) - else Inc casted_xs - - let of_int ikind x = cast_to ikind (Inc (BISet.singleton x)) - - let of_interval ?(suppress_ovwarn=false) ik (x, y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then BISet.singleton Z.zero else BISet.empty () in - norm ik @@ (Exc (ex, r)) - - let join _ x y = - match x, y with - | Inc x, Inc y -> Inc (BISet.union x y) - | Exc (x,r1), Exc (y,r2) -> Exc (BISet.inter x y, R.join r1 r2) - | Exc (x,r), Inc y - | Inc y, Exc (x,r) -> - let r = if BISet.is_empty y - then r - else - let (min_el_range, max_el_range) = Batteries.Tuple2.mapn (fun x -> R.of_interval range_ikind (Size.min_range_sign_agnostic x)) (BISet.min_elt y, BISet.max_elt y) in - let range = R.join min_el_range max_el_range in - R.join r range - in - Exc (BISet.diff x y, r) - - let meet _ x y = - match x, y with - | Inc x, Inc y -> Inc (BISet.inter x y) - | Exc (x,r1), Exc (y,r2) -> - let r = R.meet r1 r2 in - let r_min, r_max = Exclusion.min_of_range r, Exclusion.max_of_range r in - let filter_by_range = BISet.filter (value_in_range (r_min, r_max)) in - (* We remove those elements from the exclusion set that do not fit in the range anyway *) - let excl = BISet.union (filter_by_range x) (filter_by_range y) in - Exc (excl, r) - | Inc x, Exc (y,r) - | Exc (y,r), Inc x -> Inc (BISet.diff x y) - - let widen = join - let narrow = meet - let leq a b = - match a, b with - | Inc xs, Exc (ys, r) -> - if BISet.is_empty xs - then true - else - let min_b, max_b = Exclusion.min_of_range r, Exclusion.max_of_range r in - let min_a, max_a = BISet.min_elt xs, BISet.max_elt xs in - (* Check that the xs fit into the range r *) - Z.compare min_b min_a <= 0 && Z.compare max_a max_b <= 0 && - (* && check that none of the values contained in xs is excluded, i.e. contained in ys. *) - BISet.for_all (fun x -> not (BISet.mem x ys)) xs - | Inc xs, Inc ys -> - BISet.subset xs ys - | Exc (xs, r), Exc (ys, s) -> - Exclusion.(leq (Exc (xs, r)) (Exc (ys, s))) - | Exc (xs, r), Inc ys -> - Exclusion.(leq_excl_incl (Exc (xs, r)) (Inc ys)) - - let handle_bot x y f = match is_bot x, is_bot y with - | false, false -> f () - | true, false - | false, true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | true, true -> Inc (BISet.empty ()) - - let lift1 f ikind v = norm ikind @@ match v with - | Inc x when BISet.is_empty x -> v (* Return bottom when value is bottom *) - | Inc x when BISet.is_singleton x -> Inc (BISet.singleton (f (BISet.choose x))) - | _ -> top_of ikind - - let lift2 f (ikind: Cil.ikind) u v = - handle_bot u v (fun () -> - norm ikind @@ match u, v with - | Inc x,Inc y when BISet.is_singleton x && BISet.is_singleton y -> Inc (BISet.singleton (f (BISet.choose x) (BISet.choose y))) - | _,_ -> top_of ikind) - - let lift2 f ikind a b = - try lift2 f ikind a b with Division_by_zero -> top_of ikind - - let neg ?no_ov = lift1 Z.neg - let add ?no_ov ikind a b = - match a, b with - | Inc z,x when BISet.is_singleton z && BISet.choose z = Z.zero -> x - | x,Inc z when BISet.is_singleton z && BISet.choose z = Z.zero -> x - | x,y -> lift2 Z.add ikind x y - let sub ?no_ov = lift2 Z.sub - let mul ?no_ov ikind a b = - match a, b with - | Inc one,x when BISet.is_singleton one && BISet.choose one = Z.one -> x - | x,Inc one when BISet.is_singleton one && BISet.choose one = Z.one -> x - | Inc zero,_ when BISet.is_singleton zero && BISet.choose zero = Z.zero -> a - | _,Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> b - | x,y -> lift2 Z.mul ikind x y - - let div ?no_ov ikind a b = match a, b with - | x,Inc one when BISet.is_singleton one && BISet.choose one = Z.one -> x - | _,Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> top_of ikind - | Inc zero,_ when BISet.is_singleton zero && BISet.choose zero = Z.zero -> a - | x,y -> lift2 Z.div ikind x y - - let rem = lift2 Z.rem - - let lognot = lift1 Z.lognot - let logand = lift2 Z.logand - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - handle_bot x y (fun () -> - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - lift2 shift_op_big_int ik x y) - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - - let of_bool ikind x = Inc (BISet.singleton (if x then Z.one else Z.zero)) - let to_bool = function - | Inc e when BISet.is_empty e -> None - | Exc (e,_) when BISet.is_empty e -> None - | Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> Some false - | Inc xs when BISet.for_all ((<>) Z.zero) xs -> Some true - | Exc (xs,_) when BISet.exists ((=) Z.zero) xs -> Some true - | _ -> None - let to_int = function Inc x when BISet.is_singleton x -> Some (BISet.choose x) | _ -> None - - let to_excl_list = function Exc (x,r) when not (BISet.is_empty x) -> Some (BISet.elements x, (Option.get (R.minimal r), Option.get (R.maximal r))) | _ -> None - let of_excl_list ik xs = - let min_ik, max_ik = Size.range ik in - let exc = BISet.of_list @@ List.filter (value_in_range (min_ik, max_ik)) xs in - norm ik @@ Exc (exc, size ik) - let is_excl_list = BatOption.is_some % to_excl_list - let to_incl_list = function Inc s when not (BISet.is_empty s) -> Some (BISet.elements s) | _ -> None - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let c_lognot ik x = - if is_bot x - then x - else - match to_bool x with - | Some b -> of_bool ik (not b) - | None -> top_bool - - let c_logand = lift2 IntOps.BigIntOps.c_logand - let c_logor = lift2 IntOps.BigIntOps.c_logor - let maximal = function - | Inc xs when not (BISet.is_empty xs) -> Some (BISet.max_elt xs) - | Exc (excl,r) -> - let rec decrement_while_contained v = - if BISet.mem v excl - then decrement_while_contained (Z.pred v) - else v - in - let range_max = Exclusion.max_of_range r in - Some (decrement_while_contained range_max) - | _ (* bottom case *) -> None - - let minimal = function - | Inc xs when not (BISet.is_empty xs) -> Some (BISet.min_elt xs) - | Exc (excl,r) -> - let rec increment_while_contained v = - if BISet.mem v excl - then increment_while_contained (Z.succ v) - else v - in - let range_min = Exclusion.min_of_range r in - Some (increment_while_contained range_min) - | _ (* bottom case *) -> None - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let eq ik x y = - handle_bot x y (fun () -> - match x, y with - | Inc xs, Inc ys when BISet.is_singleton xs && BISet.is_singleton ys -> of_bool ik (Z.equal (BISet.choose xs) (BISet.choose ys)) - | _, _ -> - if is_bot (meet ik x y) then - (* If the meet is empty, there is no chance that concrete values are equal *) - of_bool ik false - else - top_bool) - - let ne ik x y = c_lognot ik (eq ik x y) - - let invariant_ikind e ik x = - match x with - | Inc ps -> - IntInvariant.of_incl_list e ik (BISet.elements ps) - | Exc (ns, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let nsi = IntInvariant.of_excl_list e ik (BISet.elements ns) in - Invariant.(ri && nsi) - - - let arbitrary ik = - let open QCheck.Iter in - let neg s = of_excl_list ik (BISet.elements s) in - let pos s = norm ik (Inc s) in - let shrink = function - | Exc (s, _) -> GobQCheck.shrink (BISet.arbitrary ()) s >|= neg (* S TODO: possibly shrink neg to pos *) - | Inc s -> GobQCheck.shrink (BISet.arbitrary ()) s >|= pos - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map neg (BISet.arbitrary ()); - 10, QCheck.map pos (BISet.arbitrary ()); - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = - let contains c m x = if Z.equal m Z.zero then Z.equal c x else Z.equal (Z.rem (Z.sub x c) m) Z.zero in - match a, b with - | Inc e, None -> bot_of ik - | Inc e, Some (c, m) -> Inc (BISet.filter (contains c m) e) - | _ -> a - - let refine_with_interval ik a b = a (* TODO: refine inclusion (exclusion?) set *) - - let refine_with_excl_list ik a b = - match b with - | Some (ls, _) -> meet ik a (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - - let refine_with_incl_list ik a b = - match a, b with - | Inc x, Some (ls) -> meet ik (Inc x) (Inc (BISet.of_list ls)) - | _ -> a - - let project ik p t = t -end module Congruence : S with type int_t = Z.t and type t = (Z.t * Z.t) option = struct @@ -3235,35 +493,3 @@ struct let project ik p t = t end - -module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct - - include D - - let lift v = (v, {overflow=false; underflow=false}) - - let add ?no_ov ik x y = lift @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = lift @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = lift @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = lift @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = lift @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = lift @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = lift @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = lift @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = lift @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = lift @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = lift @@ D.shift_left ik x y - - let shift_right ik x y = lift @@ D.shift_right ik x y - -end From 48fad68eb50a15778ad55dce114c15f65b5f4138 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:56:51 +0300 Subject: [PATCH 596/689] Remove Congruence from IntDomain0 --- src/cdomain/value/cdomains/intDomain0.ml | 493 ----------------------- 1 file changed, 493 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/intDomain0.ml index 7450e8a212..8dd8b07f74 100644 --- a/src/cdomain/value/cdomains/intDomain0.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -2743,499 +2743,6 @@ module Enums : S with type int_t = Z.t = struct let project ik p t = t end -module Congruence : S with type int_t = Z.t and type t = (Z.t * Z.t) option = -struct - let name () = "congruences" - type int_t = Z.t - - (* represents congruence class of c mod m, None is bot *) - type t = (Z.t * Z.t) option [@@deriving eq, ord, hash] - - let ( *: ) = Z.mul - let (+:) = Z.add - let (-:) = Z.sub - let (%:) = Z.rem - let (/:) = Z.div - let (=:) = Z.equal - let (<:) x y = Z.compare x y < 0 - let (>:) x y = Z.compare x y > 0 - let (<=:) x y = Z.compare x y <= 0 - let (>=:) x y = Z.compare x y >= 0 - (* a divides b *) - let ( |: ) a b = - if a =: Z.zero then false else (b %: a) =: Z.zero - - let normalize ik x = - match x with - | None -> None - | Some (c, m) -> - if m =: Z.zero then - if should_wrap ik then - Some (Size.cast ik c, m) - else - Some (c, m) - else - let m' = Z.abs m in - let c' = c %: m' in - if c' <: Z.zero then - Some (c' +: m', m') - else - Some (c' %: m', m') - - let range ik = Size.range ik - - let top () = Some (Z.zero, Z.one) - let top_of ik = Some (Z.zero, Z.one) - let bot () = None - let bot_of ik = bot () - - let show = function ik -> match ik with - | None -> "⟂" - | Some (c, m) when (c, m) = (Z.zero, Z.zero) -> Z.to_string c - | Some (c, m) -> - let a = if c =: Z.zero then "" else Z.to_string c in - let b = if m =: Z.zero then "" else if m = Z.one then "ℤ" else Z.to_string m^"ℤ" in - let c = if a = "" || b = "" then "" else "+" in - a^c^b - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let is_top x = x = top () - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) when b =: Z.zero -> if a =: i then `Eq else `Neq - | Some (a, b) -> if i %: b =: a then `Top else `Neq - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (c1,m1), Some (c2,m2) when m2 =: Z.zero && m1 =: Z.zero -> c1 =: c2 - | Some (c1,m1), Some (c2,m2) when m2 =: Z.zero -> c1 =: c2 && m1 =: Z.zero - | Some (c1,m1), Some (c2,m2) -> m2 |: Z.gcd (c1 -: c2) m1 - (* Typo in original equation of P. Granger (m2 instead of m1): gcd (c1 -: c2) m2 - Reference: https://doi.org/10.1080/00207168908803778 Page 171 corollary 3.3*) - - let leq x y = - let res = leq x y in - if M.tracing then M.trace "congruence" "leq %a %a -> %a " pretty x pretty y pretty (Some (Z.of_int (Bool.to_int res), Z.zero)) ; - res - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (c1,m1), Some (c2,m2) -> - let m3 = Z.gcd m1 (Z.gcd m2 (c1 -: c2)) in - normalize ik (Some (c1, m3)) - - let join ik (x:t) y = - let res = join ik x y in - if M.tracing then M.trace "congruence" "join %a %a -> %a" pretty x pretty y pretty res; - res - - - let meet ik x y = - (* if it exists, c2/a2 is solution to a*x ≡ c (mod m) *) - let congruence_series a c m = - let rec next a1 c1 a2 c2 = - if a2 |: a1 then (a2, c2) - else next a2 c2 (a1 %: a2) (c1 -: (c2 *: (a1 /: a2))) - in next m Z.zero a c - in - let simple_case i c m = - if m |: (i -: c) - then Some (i, Z.zero) else None - in - match x, y with - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero -> if c1 =: c2 then Some (c1, Z.zero) else None - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero -> simple_case c1 c2 m2 - | Some (c1, m1), Some (c2, m2) when m2 =: Z.zero -> simple_case c2 c1 m1 - | Some (c1, m1), Some (c2, m2) when (Z.gcd m1 m2) |: (c1 -: c2) -> - let (c, m) = congruence_series m1 (c2 -: c1 ) m2 in - normalize ik (Some(c1 +: (m1 *: (m /: c)), m1 *: (m2 /: c))) - | _ -> None - - let meet ik x y = - let res = meet ik x y in - if M.tracing then M.trace "congruence" "meet %a %a -> %a" pretty x pretty y pretty res; - res - - let to_int = function Some (c, m) when m =: Z.zero -> Some c | _ -> None - let of_int ik (x: int_t) = normalize ik @@ Some (x, Z.zero) - let zero = Some (Z.zero, Z.zero) - let one = Some (Z.one, Z.zero) - let top_bool = top() - - let of_bool _ik = function true -> one | false -> zero - - let to_bool (a: t) = match a with - | None -> None - | x when equal zero x -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = top() - - let ending = starting - - let of_congruence ik (c,m) = normalize ik @@ Some(c,m) - - let maximal t = match t with - | Some (x, y) when y =: Z.zero -> Some x - | _ -> None - - let minimal t = match t with - | Some (x,y) when y =: Z.zero -> Some x - | _ -> None - - (* cast from original type to ikind, set to top if the value doesn't fit into the new type *) - let cast_to ?(suppress_ovwarn=false) ?torg ?(no_ov=false) t x = - match x with - | None -> None - | Some (c, m) when m =: Z.zero -> - let c' = Size.cast t c in - (* When casting into a signed type and the result does not fit, the behavior is implementation-defined. (C90 6.2.1.2, C99 and C11 6.3.1.3) *) - (* We go with GCC behavior here: *) - (* For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised. *) - (* (https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html) *) - (* Clang behaves the same but they never document that anywhere *) - Some (c', m) - | _ -> - let (min_t, max_t) = range t in - let p ikorg = - let (min_ikorg, max_ikorg) = range ikorg in - ikorg = t || (max_t >=: max_ikorg && min_t <=: min_ikorg) - in - match torg with - | Some (Cil.TInt (ikorg, _)) when p ikorg -> - if M.tracing then M.trace "cong-cast" "some case"; - x - | _ -> top () - - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov (t : Cil.ikind) x = - let pretty_bool _ x = Pretty.text (string_of_bool x) in - let res = cast_to ?torg ?no_ov t x in - if M.tracing then M.trace "cong-cast" "Cast %a to %a (no_ov: %a) = %a" pretty x Cil.d_ikind t (Pretty.docOpt (pretty_bool ())) no_ov pretty res; - res - - let widen = join - - let widen ik x y = - let res = widen ik x y in - if M.tracing then M.trace "congruence" "widen %a %a -> %a" pretty x pretty y pretty res; - res - - let narrow = meet - - let log f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) - let c_logand = log (&&) - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let shift_right _ _ _ = top() - - let shift_right ik x y = - let res = shift_right ik x y in - if M.tracing then M.trace "congruence" "shift_right : %a %a becomes %a " pretty x pretty y pretty res; - res - - let shift_left ik x y = - (* Naive primality test *) - (* let is_prime n = - let n = Z.abs n in - let rec is_prime' d = - (d *: d >: n) || ((not ((n %: d) =: Z.zero)) && (is_prime' [@tailcall]) (d +: Z.one)) - in - not (n =: Z.one) && is_prime' (Z.of_int 2) - in *) - match x, y with - | None, None -> None - | None, _ - | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c, m), Some (c', m') when Cil.isSigned ik || c <: Z.zero || c' <: Z.zero -> top_of ik - | Some (c, m), Some (c', m') -> - let (_, max_ik) = range ik in - if m =: Z.zero && m' =: Z.zero then - normalize ik @@ Some (Z.logand max_ik (Z.shift_left c (Z.to_int c')), Z.zero) - else - let x = Z.logand max_ik (Z.shift_left Z.one (Z.to_int c')) in (* 2^c' *) - (* TODO: commented out because fails test with _Bool *) - (* if is_prime (m' +: Z.one) then - normalize ik @@ Some (x *: c, Z.gcd (x *: m) ((c *: x) *: (m' +: Z.one))) - else *) - normalize ik @@ Some (x *: c, Z.gcd (x *: m) (c *: x)) - - let shift_left ik x y = - let res = shift_left ik x y in - if M.tracing then M.trace "congruence" "shift_left : %a %a becomes %a " pretty x pretty y pretty res; - res - - (* Handle unsigned overflows. - From n === k mod (2^a * b), we conclude n === k mod 2^a, for a <= bitwidth. - The congruence modulo b may not persist on an overflow. *) - let handle_overflow ik (c, m) = - if m =: Z.zero then - normalize ik (Some (c, m)) - else - (* Find largest m'=2^k (for some k) such that m is divisible by m' *) - let tz = Z.trailing_zeros m in - let m' = Z.shift_left Z.one tz in - - let max = (snd (Size.range ik)) +: Z.one in - if m' >=: max then - (* if m' >= 2 ^ {bitlength}, there is only one value in range *) - let c' = c %: max in - Some (c', Z.zero) - else - normalize ik (Some (c, m')) - - let mul ?(no_ov=false) ik x y = - let no_ov_case (c1, m1) (c2, m2) = - c1 *: c2, Z.gcd (c1 *: m2) (Z.gcd (m1 *: c2) (m1 *: m2)) - in - match x, y with - | None, None -> bot () - | None, _ | _, None -> - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c1, m1), Some (c2, m2) when no_ov -> - Some (no_ov_case (c1, m1) (c2, m2)) - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero && not (Cil.isSigned ik) -> - let (_, max_ik) = range ik in - Some ((c1 *: c2) %: (max_ik +: Z.one), Z.zero) - | Some a, Some b when not (Cil.isSigned ik) -> - handle_overflow ik (no_ov_case a b ) - | _ -> top () - - let mul ?no_ov ik x y = - let res = mul ?no_ov ik x y in - if M.tracing then M.trace "congruence" "mul : %a %a -> %a " pretty x pretty y pretty res; - res - - let neg ?(no_ov=false) ik x = - match x with - | None -> bot() - | Some _ -> mul ~no_ov ik (of_int ik (Z.of_int (-1))) x - - let add ?(no_ov=false) ik x y = - let no_ov_case (c1, m1) (c2, m2) = - c1 +: c2, Z.gcd m1 m2 - in - match (x, y) with - | None, None -> bot () - | None, _ | _, None -> - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some a, Some b when no_ov -> - normalize ik (Some (no_ov_case a b)) - | Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero && not (Cil.isSigned ik) -> - let (_, max_ik) = range ik in - Some((c1 +: c2) %: (max_ik +: Z.one), Z.zero) - | Some a, Some b when not (Cil.isSigned ik) -> - handle_overflow ik (no_ov_case a b) - | _ -> top () - - - let add ?no_ov ik x y = - let res = add ?no_ov ik x y in - if M.tracing then - M.trace "congruence" "add : %a %a -> %a" pretty x pretty y - pretty res ; - res - - let sub ?(no_ov=false) ik x y = add ~no_ov ik x (neg ~no_ov ik y) - - - let sub ?no_ov ik x y = - let res = sub ?no_ov ik x y in - if M.tracing then - M.trace "congruence" "sub : %a %a -> %a" pretty x pretty y - pretty res ; - res - - let lognot ik x = match x with - | None -> None - | Some (c, m) -> - if (Cil.isSigned ik) then - sub ik (neg ik x) one - else - let (_, max_ik) = range ik in - Some (Z.sub max_ik c, m) - - (** The implementation of the bit operations could be improved based on the master’s thesis - 'Abstract Interpretation and Abstract Domains' written by Stefan Bygde. - see: http://www.es.mdh.se/pdf_publications/948.pdf *) - let bit2 f ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c, m), Some (c', m') -> - if m =: Z.zero && m' =: Z.zero then Some (f c c', Z.zero) - else top () - - let logor ik x y = bit2 Z.logor ik x y - - let logand ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c, m), Some (c', m') -> - if m =: Z.zero && m' =: Z.zero then - (* both arguments constant *) - Some (Z.logand c c', Z.zero) - else if m' =: Z.zero && c' =: Z.one && Z.rem m (Z.of_int 2) =: Z.zero then - (* x & 1 and x == c (mod 2*z) *) - (* Value is equal to LSB of c *) - Some (Z.logand c c', Z.zero) - else - top () - - let logxor ik x y = bit2 Z.logxor ik x y - - let rem ik x y = - match x, y with - | None, None -> bot() - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c1, m1), Some(c2, m2) -> - if m2 =: Z.zero then - if (c2 |: m1) && (c1 %: c2 =: Z.zero || m1 =: Z.zero || not (Cil.isSigned ik)) then - Some (c1 %: c2, Z.zero) - else - normalize ik (Some (c1, (Z.gcd m1 c2))) - else - normalize ik (Some (c1, Z.gcd m1 (Z.gcd c2 m2))) - - let rem ik x y = let res = rem ik x y in - if M.tracing then M.trace "congruence" "rem : %a %a -> %a " pretty x pretty y pretty res; - res - - let div ?(no_ov=false) ik x y = - match x,y with - | None, None -> bot () - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, x when leq zero x -> top () - | Some(c1, m1), Some(c2, m2) when not no_ov && m2 =: Z.zero && c2 =: Z.neg Z.one -> top () - | Some(c1, m1), Some(c2, m2) when m1 =: Z.zero && m2 =: Z.zero -> Some (c1 /: c2, Z.zero) - | Some(c1, m1), Some(c2, m2) when m2 =: Z.zero && c2 |: m1 && c2 |: c1 -> Some (c1 /: c2, m1 /: c2) - | _, _ -> top () - - - let div ?no_ov ik x y = - let res = div ?no_ov ik x y in - if M.tracing then - M.trace "congruence" "div : %a %a -> %a" pretty x pretty y pretty - res ; - res - - let ne ik (x: t) (y: t) = match x, y with - | Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> of_bool ik (not (c1 =: c2 )) - | x, y -> if meet ik x y = None then of_bool ik true else top_bool - - let eq ik (x: t) (y: t) = match x, y with - | Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> of_bool ik (c1 =: c2) - | x, y -> if meet ik x y <> None then top_bool else of_bool ik false - - let comparison ik op x y = match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (c1, m1), Some (c2, m2) -> - if m1 =: Z.zero && m2 =: Z.zero then - if op c1 c2 then of_bool ik true else of_bool ik false - else - top_bool - - let ge ik x y = comparison ik (>=:) x y - - let ge ik x y = - let res = ge ik x y in - if M.tracing then M.trace "congruence" "greater or equal : %a %a -> %a " pretty x pretty y pretty res; - res - - let le ik x y = comparison ik (<=:) x y - - let le ik x y = - let res = le ik x y in - if M.tracing then M.trace "congruence" "less or equal : %a %a -> %a " pretty x pretty y pretty res; - res - - let gt ik x y = comparison ik (>:) x y - - - let gt ik x y = - let res = gt ik x y in - if M.tracing then M.trace "congruence" "greater than : %a %a -> %a " pretty x pretty y pretty res; - res - - let lt ik x y = comparison ik (<:) x y - - let lt ik x y = - let res = lt ik x y in - if M.tracing then M.trace "congruence" "less than : %a %a -> %a " pretty x pretty y pretty res; - res - - let invariant_ikind e ik x = - match x with - | x when is_top x -> Invariant.top () - | Some (c, m) when m =: Z.zero -> - IntInvariant.of_int e ik c - | Some (c, m) -> - let open Cil in - let (c, m) = BatTuple.Tuple2.mapn (fun a -> kintegerCilint ik a) (c, m) in - Invariant.of_exp (BinOp (Eq, (BinOp (Mod, e, m, TInt(ik,[]))), c, intType)) - | None -> Invariant.none - - let arbitrary ik = - let open QCheck in - let int_arb = map ~rev:Z.to_int64 Z.of_int64 GobQCheck.Arbitrary.int64 in - let cong_arb = pair int_arb int_arb in - let of_pair ik p = normalize ik (Some p) in - let to_pair = Option.get in - set_print show (map ~rev:to_pair (of_pair ik) cong_arb) - - let refine_with_interval ik (cong : t) (intv : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =: Z.zero then - if c <: x || c >: y then None else Some (c, Z.zero) - else - let rcx = x +: ((c -: x) %: Z.abs m) in - let lcy = y -: ((y -: c) %: Z.abs m) in - if rcx >: lcy then None - else if rcx =: lcy then Some (rcx, Z.zero) - else cong - | _ -> None - - let refine_with_interval ik (cong : t) (intv : (int_t * int_t) option) : t = - let pretty_intv _ i = - match i with - | Some (l, u) -> Pretty.dprintf "[%a,%a]" GobZ.pretty l GobZ.pretty u - | _ -> Pretty.text ("Display Error") in - let refn = refine_with_interval ik cong intv in - if M.tracing then M.trace "refine" "cong_refine_with_interval %a %a -> %a" pretty cong pretty_intv intv pretty refn; - refn - - let refine_with_congruence ik a b = meet ik a b - let refine_with_excl_list ik a b = a - let refine_with_incl_list ik a b = a - - let project ik p t = t -end - module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct include D From f5c1a1cf049a983f15384568a16dd55625340ec8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 16:59:38 +0300 Subject: [PATCH 597/689] Rename IntDomain0 -> EnumsDomain for split --- src/cdomain/value/cdomains/{intDomain0.ml => int/enumsDomain.ml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cdomain/value/cdomains/{intDomain0.ml => int/enumsDomain.ml} (100%) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/int/enumsDomain.ml similarity index 100% rename from src/cdomain/value/cdomains/intDomain0.ml rename to src/cdomain/value/cdomains/int/enumsDomain.ml From 92ec19e4007986f1d48b2da79d42456cda83fe95 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:00:03 +0300 Subject: [PATCH 598/689] Remove non-EnumsDomain parts --- src/cdomain/value/cdomains/int/enumsDomain.ml | 2409 +---------------- 1 file changed, 1 insertion(+), 2408 deletions(-) diff --git a/src/cdomain/value/cdomains/int/enumsDomain.ml b/src/cdomain/value/cdomains/int/enumsDomain.ml index 8dd8b07f74..d0208feeff 100644 --- a/src/cdomain/value/cdomains/int/enumsDomain.ml +++ b/src/cdomain/value/cdomains/int/enumsDomain.ml @@ -1,2380 +1,5 @@ -open GobConfig -open GoblintCil -open Pretty -open PrecisionUtil +open IntDomain0 -module M = Messages - -let (%) = Batteries.(%) -let (|?) = Batteries.(|?) - -exception IncompatibleIKinds of string -exception Unknown -exception Error -exception ArithmeticOnIntegerBot of string - - - - -(** Define records that hold mutable variables representing different Configuration values. - * These values are used to keep track of whether or not the corresponding Config values are en-/disabled *) -type ana_int_config_values = { - mutable interval_threshold_widening : bool option; - mutable interval_narrow_by_meet : bool option; - mutable def_exc_widen_by_join : bool option; - mutable interval_threshold_widening_constants : string option; - mutable refinement : string option; -} - -let ana_int_config: ana_int_config_values = { - interval_threshold_widening = None; - interval_narrow_by_meet = None; - def_exc_widen_by_join = None; - interval_threshold_widening_constants = None; - refinement = None; -} - -let get_interval_threshold_widening () = - if ana_int_config.interval_threshold_widening = None then - ana_int_config.interval_threshold_widening <- Some (get_bool "ana.int.interval_threshold_widening"); - Option.get ana_int_config.interval_threshold_widening - -let get_interval_narrow_by_meet () = - if ana_int_config.interval_narrow_by_meet = None then - ana_int_config.interval_narrow_by_meet <- Some (get_bool "ana.int.interval_narrow_by_meet"); - Option.get ana_int_config.interval_narrow_by_meet - -let get_def_exc_widen_by_join () = - if ana_int_config.def_exc_widen_by_join = None then - ana_int_config.def_exc_widen_by_join <- Some (get_bool "ana.int.def_exc_widen_by_join"); - Option.get ana_int_config.def_exc_widen_by_join - -let get_interval_threshold_widening_constants () = - if ana_int_config.interval_threshold_widening_constants = None then - ana_int_config.interval_threshold_widening_constants <- Some (get_string "ana.int.interval_threshold_widening_constants"); - Option.get ana_int_config.interval_threshold_widening_constants - -let get_refinement () = - if ana_int_config.refinement = None then - ana_int_config.refinement <- Some (get_string "ana.int.refinement"); - Option.get ana_int_config.refinement - - - -(** Whether for a given ikind, we should compute with wrap-around arithmetic. - * Always for unsigned types, for signed types if 'sem.int.signed_overflow' is 'assume_wraparound' *) -let should_wrap ik = not (Cil.isSigned ik) || get_string "sem.int.signed_overflow" = "assume_wraparound" - -(** Whether for a given ikind, we should assume there are no overflows. - * Always false for unsigned types, true for signed types if 'sem.int.signed_overflow' is 'assume_none' *) -let should_ignore_overflow ik = Cil.isSigned ik && get_string "sem.int.signed_overflow" = "assume_none" - -let widening_thresholds = ResettableLazy.from_fun WideningThresholds.thresholds -let widening_thresholds_desc = ResettableLazy.from_fun (List.rev % WideningThresholds.thresholds) - -type overflow_info = { overflow: bool; underflow: bool;} - -let set_overflow_flag ~cast ~underflow ~overflow ik = - if !AnalysisState.executing_speculative_computations then - (* Do not produce warnings when the operations are not actually happening in code *) - () - else - let signed = Cil.isSigned ik in - if !AnalysisState.postsolving && signed && not cast then - AnalysisState.svcomp_may_overflow := true; - let sign = if signed then "Signed" else "Unsigned" in - match underflow, overflow with - | true, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190; CWE 191] "%s integer overflow and underflow" sign - | true, false -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 191] "%s integer underflow" sign - | false, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190] "%s integer overflow" sign - | false, false -> assert false - -let reset_lazy () = - ResettableLazy.reset widening_thresholds; - ResettableLazy.reset widening_thresholds_desc; - ana_int_config.interval_threshold_widening <- None; - ana_int_config.interval_narrow_by_meet <- None; - ana_int_config.def_exc_widen_by_join <- None; - ana_int_config.interval_threshold_widening_constants <- None; - ana_int_config.refinement <- None - -module type Arith = -sig - type t - val neg: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div: t -> t -> t - val rem: t -> t -> t - - val lt: t -> t -> t - val gt: t -> t -> t - val le: t -> t -> t - val ge: t -> t -> t - val eq: t -> t -> t - val ne: t -> t -> t - - val lognot: t -> t - val logand: t -> t -> t - val logor : t -> t -> t - val logxor: t -> t -> t - - val shift_left : t -> t -> t - val shift_right: t -> t -> t - - val c_lognot: t -> t - val c_logand: t -> t -> t - val c_logor : t -> t -> t - -end - -module type ArithIkind = -sig - type t - val neg: Cil.ikind -> t -> t - val add: Cil.ikind -> t -> t -> t - val sub: Cil.ikind -> t -> t -> t - val mul: Cil.ikind -> t -> t -> t - val div: Cil.ikind -> t -> t -> t - val rem: Cil.ikind -> t -> t -> t - - val lt: Cil.ikind -> t -> t -> t - val gt: Cil.ikind -> t -> t -> t - val le: Cil.ikind -> t -> t -> t - val ge: Cil.ikind -> t -> t -> t - val eq: Cil.ikind -> t -> t -> t - val ne: Cil.ikind -> t -> t -> t - - val lognot: Cil.ikind -> t -> t - val logand: Cil.ikind -> t -> t -> t - val logor : Cil.ikind -> t -> t -> t - val logxor: Cil.ikind -> t -> t -> t - - val shift_left : Cil.ikind -> t -> t -> t - val shift_right: Cil.ikind -> t -> t -> t - - val c_lognot: Cil.ikind -> t -> t - val c_logand: Cil.ikind -> t -> t -> t - val c_logor : Cil.ikind -> t -> t -> t - -end - -(* Shared functions between S and Z *) -module type B = -sig - include Lattice.S - type int_t - val bot_of: Cil.ikind -> t - val top_of: Cil.ikind -> t - val to_int: t -> int_t option - val equal_to: int_t -> t -> [`Eq | `Neq | `Top] - - val to_bool: t -> bool option - val to_excl_list: t -> (int_t list * (int64 * int64)) option - val of_excl_list: Cil.ikind -> int_t list -> t - val is_excl_list: t -> bool - - val to_incl_list: t -> int_t list option - - val maximal : t -> int_t option - val minimal : t -> int_t option - - val cast_to: ?suppress_ovwarn:bool -> ?torg:Cil.typ -> Cil.ikind -> t -> t -end - -(** Interface of IntDomain implementations that do not take ikinds for arithmetic operations yet. TODO: Should be ported to S in the future. *) -module type IkindUnawareS = -sig - include B - include Arith with type t := t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: int_t -> t - val of_bool: bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val arbitrary: unit -> t QCheck.arbitrary - val invariant: Cil.exp -> t -> Invariant.t -end - -(** Interface of IntDomain implementations taking an ikind for arithmetic operations *) -module type S = -sig - include B - include ArithIkind with type t:= t - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val neg : ?no_ov:bool -> Cil.ikind -> t -> t - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t - - val join: Cil.ikind -> t -> t -> t - val meet: Cil.ikind -> t -> t -> t - val narrow: Cil.ikind -> t -> t -> t - val widen: Cil.ikind -> t -> t -> t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val is_top_of: Cil.ikind -> t -> bool - val invariant_ikind : Cil.exp -> Cil.ikind -> t -> Invariant.t - - val refine_with_congruence: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_interval: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_excl_list: Cil.ikind -> t -> (int_t list * (int64 * int64)) option -> t - val refine_with_incl_list: Cil.ikind -> t -> int_t list option -> t - - val project: Cil.ikind -> int_precision -> t -> t - val arbitrary: Cil.ikind -> t QCheck.arbitrary -end - -module type SOverflow = -sig - - include S - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val neg : ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val of_int : Cil.ikind -> int_t -> t * overflow_info - - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t * overflow_info - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - - val shift_left : Cil.ikind -> t -> t -> t * overflow_info - - val shift_right : Cil.ikind -> t -> t -> t * overflow_info -end - -module type Y = -sig - (* include B *) - include B - include Arith with type t:= t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val is_top_of: Cil.ikind -> t -> bool - - val project: int_precision -> t -> t - val invariant: Cil.exp -> t -> Invariant.t -end - -module type Z = Y with type int_t = Z.t - - -module IntDomLifter (I : S) = -struct - open Cil - type int_t = I.int_t - type t = { v : I.t; ikind : CilType.Ikind.t } [@@deriving eq, ord, hash] - - let ikind {ikind; _} = ikind - - (* Helper functions *) - let check_ikinds x y = if x.ikind <> y.ikind then raise (IncompatibleIKinds (GobPretty.sprintf "ikinds %a and %a are incompatible. Values: %a and %a" CilType.Ikind.pretty x.ikind CilType.Ikind.pretty y.ikind I.pretty x.v I.pretty y.v)) - let lift op x = {x with v = op x.ikind x.v } - (* For logical operations the result is of type int *) - let lift_logical op x = {v = op x.ikind x.v; ikind = Cil.IInt} - let lift2 op x y = check_ikinds x y; {x with v = op x.ikind x.v y.v } - let lift2_cmp op x y = check_ikinds x y; {v = op x.ikind x.v y.v; ikind = Cil.IInt} - - let bot_of ikind = { v = I.bot_of ikind; ikind} - let bot () = failwith "bot () is not implemented for IntDomLifter." - let is_bot x = I.is_bot x.v - let top_of ikind = { v = I.top_of ikind; ikind} - let top () = failwith "top () is not implemented for IntDomLifter." - let is_top x = I.is_top x.v - - (* Leq does not check for ikind, because it is used in invariant with arguments of different type. - TODO: check ikinds here and fix invariant to work with right ikinds *) - let leq x y = I.leq x.v y.v - let join = lift2 I.join - let meet = lift2 I.meet - let widen = lift2 I.widen - let narrow = lift2 I.narrow - - let show x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - "⊤" - else - I.show x.v (* TODO add ikind to output *) - let pretty () x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - Pretty.text "⊤" - else - I.pretty () x.v (* TODO add ikind to output *) - let pretty_diff () (x, y) = I.pretty_diff () (x.v, y.v) (* TODO check ikinds, add them to output *) - let printXml o x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - BatPrintf.fprintf o "\n\n⊤\n\n\n" - else - I.printXml o x.v (* TODO add ikind to output *) - (* This is for debugging *) - let name () = "IntDomLifter(" ^ (I.name ()) ^ ")" - let to_yojson x = I.to_yojson x.v - let invariant e x = - let e' = Cilfacade.mkCast ~e ~newt:(TInt (x.ikind, [])) in - I.invariant_ikind e' x.ikind x.v - let tag x = I.tag x.v - let arbitrary ik = failwith @@ "Arbitrary not implement for " ^ (name ()) ^ "." - let to_int x = I.to_int x.v - let of_int ikind x = { v = I.of_int ikind x; ikind} - let equal_to i x = I.equal_to i x.v - let to_bool x = I.to_bool x.v - let of_bool ikind b = { v = I.of_bool ikind b; ikind} - let to_excl_list x = I.to_excl_list x.v - let of_excl_list ikind is = {v = I.of_excl_list ikind is; ikind} - let is_excl_list x = I.is_excl_list x.v - let to_incl_list x = I.to_incl_list x.v - let of_interval ?(suppress_ovwarn=false) ikind (lb,ub) = {v = I.of_interval ~suppress_ovwarn ikind (lb,ub); ikind} - let of_congruence ikind (c,m) = {v = I.of_congruence ikind (c,m); ikind} - let starting ?(suppress_ovwarn=false) ikind i = {v = I.starting ~suppress_ovwarn ikind i; ikind} - let ending ?(suppress_ovwarn=false) ikind i = {v = I.ending ~suppress_ovwarn ikind i; ikind} - let maximal x = I.maximal x.v - let minimal x = I.minimal x.v - - let neg = lift I.neg - let add = lift2 I.add - let sub = lift2 I.sub - let mul = lift2 I.mul - let div = lift2 I.div - let rem = lift2 I.rem - let lt = lift2_cmp I.lt - let gt = lift2_cmp I.gt - let le = lift2_cmp I.le - let ge = lift2_cmp I.ge - let eq = lift2_cmp I.eq - let ne = lift2_cmp I.ne - let lognot = lift I.lognot - let logand = lift2 I.logand - let logor = lift2 I.logor - let logxor = lift2 I.logxor - let shift_left x y = {x with v = I.shift_left x.ikind x.v y.v } (* TODO check ikinds*) - let shift_right x y = {x with v = I.shift_right x.ikind x.v y.v } (* TODO check ikinds*) - let c_lognot = lift_logical I.c_lognot - let c_logand = lift2 I.c_logand - let c_logor = lift2 I.c_logor - - let cast_to ?(suppress_ovwarn=false) ?torg ikind x = {v = I.cast_to ~suppress_ovwarn ~torg:(TInt(x.ikind,[])) ikind x.v; ikind} - - let is_top_of ik x = ik = x.ikind && I.is_top_of ik x.v - - let relift x = { v = I.relift x.v; ikind = x.ikind } - - let project p v = { v = I.project v.ikind p v.v; ikind = v.ikind } -end - -module type Ikind = -sig - val ikind: unit -> Cil.ikind -end - -module PtrDiffIkind : Ikind = -struct - let ikind = Cilfacade.ptrdiff_ikind -end - -module IntDomWithDefaultIkind (I: Y) (Ik: Ikind) : Y with type t = I.t and type int_t = I.int_t = -struct - include I - let top () = I.top_of (Ik.ikind ()) - let bot () = I.bot_of (Ik.ikind ()) -end - -module Size = struct (* size in bits as int, range as int64 *) - open Cil - let sign x = if Z.compare x Z.zero < 0 then `Signed else `Unsigned - - let top_typ = TInt (ILongLong, []) - let min_for x = intKindForValue x (sign x = `Unsigned) - let bit = function (* bits needed for representation *) - | IBool -> 1 - | ik -> bytesSizeOfInt ik * 8 - let is_int64_big_int x = Z.fits_int64 x - let card ik = (* cardinality *) - let b = bit ik in - Z.shift_left Z.one b - let bits ik = (* highest bits for neg/pos values *) - let s = bit ik in - if isSigned ik then s-1, s-1 else 0, s - let bits_i64 ik = BatTuple.Tuple2.mapn Int64.of_int (bits ik) - let range ik = - let a,b = bits ik in - let x = if isSigned ik then Z.neg (Z.shift_left Z.one a) (* -2^a *) else Z.zero in - let y = Z.pred (Z.shift_left Z.one b) in (* 2^b - 1 *) - x,y - - let is_cast_injective ~from_type ~to_type = - let (from_min, from_max) = range (Cilfacade.get_ikind from_type) in - let (to_min, to_max) = range (Cilfacade.get_ikind to_type) in - if M.tracing then M.trace "int" "is_cast_injective %a (%a, %a) -> %a (%a, %a)" CilType.Typ.pretty from_type GobZ.pretty from_min GobZ.pretty from_max CilType.Typ.pretty to_type GobZ.pretty to_min GobZ.pretty to_max; - Z.compare to_min from_min <= 0 && Z.compare from_max to_max <= 0 - - let cast t x = (* TODO: overflow is implementation-dependent! *) - if t = IBool then - (* C11 6.3.1.2 Boolean type *) - if Z.equal x Z.zero then Z.zero else Z.one - else - let a,b = range t in - let c = card t in - let y = Z.erem x c in - let y = if Z.gt y b then Z.sub y c - else if Z.lt y a then Z.add y c - else y - in - if M.tracing then M.tracel "cast" "Cast %a to range [%a, %a] (%a) = %a (%s in int64)" GobZ.pretty x GobZ.pretty a GobZ.pretty b GobZ.pretty c GobZ.pretty y (if is_int64_big_int y then "fits" else "does not fit"); - y - - let min_range_sign_agnostic x = - let size ik = - let a,b = bits_i64 ik in - Int64.neg a,b - in - if sign x = `Signed then - size (min_for x) - else - let a, b = size (min_for x) in - if b <= 64L then - let upper_bound_less = Int64.sub b 1L in - let max_one_less = Z.(pred @@ shift_left Z.one (Int64.to_int upper_bound_less)) in - if x <= max_one_less then - a, upper_bound_less - else - a,b - else - a, b - - (* From the number of bits used to represent a positive value, determines the maximal representable value *) - let max_from_bit_range pos_bits = Z.(pred @@ shift_left Z.one (to_int (Z.of_int64 pos_bits))) - - (* From the number of bits used to represent a non-positive value, determines the minimal representable value *) - let min_from_bit_range neg_bits = Z.(if neg_bits = 0L then Z.zero else neg @@ shift_left Z.one (to_int (neg (Z.of_int64 neg_bits)))) - -end - - -module StdTop (B: sig type t val top_of: Cil.ikind -> t end) = struct - open B - (* these should be overwritten for better precision if possible: *) - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ik x = top_of ik - let ending ?(suppress_ovwarn=false) ik x = top_of ik - let maximal x = None - let minimal x = None -end - -module Std (B: sig - type t - val name: unit -> string - val top_of: Cil.ikind -> t - val bot_of: Cil.ikind -> t - val show: t -> string - val equal: t -> t -> bool - end) = struct - include Printable.StdLeaf - let name = B.name (* overwrite the one from Printable.Std *) - open B - let is_top x = failwith "is_top not implemented for IntDomain.Std" - let is_bot x = B.equal x (bot_of Cil.IInt) (* Here we assume that the representation of bottom is independent of the ikind - This may be true for intdomain implementations, but not e.g. for IntDomLifter. *) - let is_top_of ik x = B.equal x (top_of ik) - - (* all output is based on B.show *) - include Printable.SimpleShow ( - struct - type nonrec t = t - let show = show - end - ) - let pretty_diff () (x,y) = dprintf "%s: %a instead of %a" (name ()) pretty x pretty y - - include StdTop (B) -end - -(* Textbook interval arithmetic, without any overflow handling etc. *) -module IntervalArith (Ints_t : IntOps.IntOps) = struct - let min4 a b c d = Ints_t.min (Ints_t.min a b) (Ints_t.min c d) - let max4 a b c d = Ints_t.max (Ints_t.max a b) (Ints_t.max c d) - - let mul (x1, x2) (y1, y2) = - let x1y1 = (Ints_t.mul x1 y1) in - let x1y2 = (Ints_t.mul x1 y2) in - let x2y1 = (Ints_t.mul x2 y1) in - let x2y2 = (Ints_t.mul x2 y2) in - (min4 x1y1 x1y2 x2y1 x2y2, max4 x1y1 x1y2 x2y1 x2y2) - - let shift_left (x1,x2) (y1,y2) = - let y1p = Ints_t.shift_left Ints_t.one y1 in - let y2p = Ints_t.shift_left Ints_t.one y2 in - mul (x1, x2) (y1p, y2p) - - let div (x1, x2) (y1, y2) = - let x1y1n = (Ints_t.div x1 y1) in - let x1y2n = (Ints_t.div x1 y2) in - let x2y1n = (Ints_t.div x2 y1) in - let x2y2n = (Ints_t.div x2 y2) in - let x1y1p = (Ints_t.div x1 y1) in - let x1y2p = (Ints_t.div x1 y2) in - let x2y1p = (Ints_t.div x2 y1) in - let x2y2p = (Ints_t.div x2 y2) in - (min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p) - - let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2) - let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1) - - let neg (x1, x2) = (Ints_t.neg x2, Ints_t.neg x1) - - let one = (Ints_t.one, Ints_t.one) - let zero = (Ints_t.zero, Ints_t.zero) - let top_bool = (Ints_t.zero, Ints_t.one) - - let to_int (x1, x2) = - if Ints_t.equal x1 x2 then Some x1 else None - - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let max_ik' = Ints_t.to_bigint max_ik in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let min_ik' = Ints_t.to_bigint min_ik in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let is_upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - List.exists (Z.equal u) ts - let is_lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - List.exists (Z.equal l) ts -end - -module IntInvariant = -struct - let of_int e ik x = - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.none - - let of_incl_list e ik ps = - match ps with - | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> - assert (List.mem Z.zero ps); - assert (List.mem Z.one ps); - Invariant.none - | [_] when get_bool "witness.invariant.exact" -> - Invariant.none - | _ :: _ :: _ - | [_] | [] -> - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) (Invariant.bot ()) ps - - let of_interval_opt e ik = function - | (Some x1, Some x2) when Z.equal x1 x2 -> - of_int e ik x1 - | x1_opt, x2_opt -> - let (min_ik, max_ik) = Size.range ik in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = - match x1_opt, inexact_type_bounds with - | Some x1, false when Z.equal min_ik x1 -> Invariant.none - | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) - | None, _ -> Invariant.none - in - let i2 = - match x2_opt, inexact_type_bounds with - | Some x2, false when Z.equal x2 max_ik -> Invariant.none - | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) - | None, _ -> Invariant.none - in - Invariant.(i1 && i2) - - let of_interval e ik (x1, x2) = - of_interval_opt e ik (Some x1, Some x2) - - let of_excl_list e ik ns = - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) (Invariant.top ()) ns -end - -module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = -struct - let name () = "intervals" - type int_t = Ints_t.t - type t = (Ints_t.t * Ints_t.t) option [@@deriving eq, ord, hash] - module IArith = IntervalArith (Ints_t) - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - let top_of ik = Some (range ik) - let bot () = None - let bot_of ik = bot () (* TODO: improve *) - - let show = function None -> "bottom" | Some (x,y) -> "["^Ints_t.to_string x^","^Ints_t.to_string y^"]" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) -> - if a = b && b = i then `Eq else if Ints_t.compare a i <= 0 && Ints_t.compare i b <=0 then `Top else `Neq - - let norm ?(suppress_ovwarn=false) ?(cast=false) ik : (t -> t * overflow_info) = function None -> (None, {underflow=false; overflow=false}) | Some (x,y) -> - if Ints_t.compare x y > 0 then - (None,{underflow=false; overflow=false}) - else ( - let (min_ik, max_ik) = range ik in - let underflow = Ints_t.compare min_ik x > 0 in - let overflow = Ints_t.compare max_ik y < 0 in - let ov_info = { underflow = underflow && not suppress_ovwarn; overflow = overflow && not suppress_ovwarn } in - let v = - if underflow || overflow then - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (Ints_t.sub max_ik min_ik) in - let resdiff = Ints_t.abs (Ints_t.sub y x) in - if Ints_t.compare resdiff diff > 0 then - top_of ik - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if Ints_t.compare l u <= 0 then - Some (l, u) - else - (* Interval that wraps around (begins to the right of its end). We can not represent such intervals *) - top_of ik - else if not cast && should_ignore_overflow ik then - let tl, tu = BatOption.get @@ top_of ik in - Some (Ints_t.max tl x, Ints_t.min tu y) - else - top_of ik - else - Some (x,y) - in - (v, ov_info) - ) - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0 - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst - - let meet ik (x:t) y = - match x, y with - | None, z | z, None -> None - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.max x1 y1, Ints_t.min x2 y2) |> fst - - (* TODO: change to_int signature so it returns a big_int *) - let to_int x = Option.bind x (IArith.to_int) - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm ~suppress_ovwarn ik @@ Some (x,y) - let of_int ik (x: int_t) = of_interval ik (x,x) - let zero = Some IArith.zero - let one = Some IArith.one - let top_bool = Some IArith.top_bool - - let of_bool _ik = function true -> one | false -> zero - let to_bool (a: t) = match a with - | None -> None - | Some (l, u) when Ints_t.compare l Ints_t.zero = 0 && Ints_t.compare u Ints_t.zero = 0 -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (fst (range ik), n) - - (* TODO: change signature of maximal, minimal to return big_int*) - let maximal = function None -> None | Some (x,y) -> Some y - let minimal = function None -> None | Some (x,y) -> Some x - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - - let widen ik x y = - match x, y with - | None, z | z, None -> z - | Some (l0,u0), Some (l1,u1) -> - let (min_ik, max_ik) = range ik in - let threshold = get_interval_threshold_widening () in - let l2 = - if Ints_t.compare l0 l1 = 0 then l0 - else if threshold then IArith.lower_threshold l1 min_ik - else min_ik - in - let u2 = - if Ints_t.compare u0 u1 = 0 then u0 - else if threshold then IArith.upper_threshold u1 max_ik - else max_ik - in - norm ik @@ Some (l2,u2) |> fst - let widen ik x y = - let r = widen ik x y in - if M.tracing && not (equal x y) then M.tracel "int" "interval widen %a %a -> %a" pretty x pretty y pretty r; - assert (leq x y); (* TODO: remove for performance reasons? *) - r - - let narrow ik x y = - match x, y with - | _,None | None, _ -> None - | Some (x1,x2), Some (y1,y2) -> - let threshold = get_interval_threshold_widening () in - let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in - norm ik @@ Some (lr,ur) |> fst - - - let narrow ik x y = - if get_interval_narrow_by_meet () then - meet ik x y - else - narrow ik x y - - let log f ~annihilator ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, _ when x = annihilator -> of_bool ik annihilator - | _, Some y when y = annihilator -> of_bool ik annihilator - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) ~annihilator:true - let c_logand = log (&&) ~annihilator:false - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let bit f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - let bitcomp f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{underflow=false; overflow=false})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let logxor = bit (fun _ik -> Ints_t.logxor) - - let logand ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (Ints_t.logand x y) |> fst with Division_by_zero -> top_of ik) - | _, Some y when Ints_t.equal y Ints_t.zero -> of_int ik Ints_t.zero |> fst - | _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst - | _ -> top_of ik - - let logor = bit (fun _ik -> Ints_t.logor) - - let bit1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_int i1 with - | Some x -> of_int ik (f ik x) |> fst - | _ -> top_of ik - - let lognot = bit1 (fun _ik -> Ints_t.lognot) - let shift_right = bitcomp (fun _ik x y -> Ints_t.shift_right x (Ints_t.to_int y)) - - let neg ?no_ov ik = function None -> (None,{underflow=false; overflow=false}) | Some x -> norm ik @@ Some (IArith.neg x) - - let binary_op_with_norm ?no_ov op ik x y = match x, y with - | None, None -> (None, {overflow=false; underflow= false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some x, Some y -> norm ik @@ Some (op x y) - - let add ?no_ov = binary_op_with_norm IArith.add - let mul ?no_ov = binary_op_with_norm IArith.mul - let sub ?no_ov = binary_op_with_norm IArith.sub - - let shift_left ik a b = - match is_bot a, is_bot b with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show a) (show b))) - | _ -> - match a, minimal b, maximal b with - | Some a, Some bl, Some bu when (Ints_t.compare bl Ints_t.zero >= 0) -> - (try - let r = IArith.shift_left a (Ints_t.to_int bl, Ints_t.to_int bu) in - norm ik @@ Some r - with Z.Overflow -> (top_of ik,{underflow=false; overflow=true})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let rem ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (xl, xu), Some (yl, yu) -> - if is_top_of ik x && is_top_of ik y then - (* This is needed to preserve soundness also on things bigger than int32 e.g. *) - (* x: 3803957176L -> T in Interval32 *) - (* y: 4209861404L -> T in Interval32 *) - (* x % y: 3803957176L -> T in Interval32 *) - (* T in Interval32 is [-2147483648,2147483647] *) - (* the code below computes [-2147483647,2147483647] for this though which is unsound *) - top_of ik - else - (* If we have definite values, Ints_t.rem will give a definite result. - * Otherwise we meet with a [range] the result can be in. - * This range is [0, min xu b] if x is positive, and [max xl -b, min xu b] if x can be negative. - * The precise bound b is one smaller than the maximum bound. Negative y give the same result as positive. *) - let pos x = if Ints_t.compare x Ints_t.zero < 0 then Ints_t.neg x else x in - let b = Ints_t.sub (Ints_t.max (pos yl) (pos yu)) Ints_t.one in - let range = if Ints_t.compare xl Ints_t.zero>= 0 then Some (Ints_t.zero, Ints_t.min xu b) else Some (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit (fun _ik -> Ints_t.rem) ik x y) range - - let rec div ?no_ov ik x y = - match x, y with - | None, None -> (bot (),{underflow=false; overflow=false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | (Some (x1,x2) as x), (Some (y1,y2) as y) -> - begin - let is_zero v = Ints_t.compare v Ints_t.zero = 0 in - match y1, y2 with - | l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false}) (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2)) - | _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one))) - | _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false}) - | _ -> binary_op_with_norm IArith.div ik x y - end - - let ne ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik true - else if Ints_t.compare x2 y1 <= 0 && Ints_t.compare y2 x1 <= 0 then - of_bool ik false - else top_bool - - let eq ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 && Ints_t.compare x2 y1 <= 0 then - of_bool ik true - else if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik false - else top_bool - - let ge ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 then of_bool ik true - else if Ints_t.compare x2 y1 < 0 then of_bool ik false - else top_bool - - let le ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 <= 0 then of_bool ik true - else if Ints_t.compare y2 x1 < 0 then of_bool ik false - else top_bool - - let gt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 then of_bool ik true - else if Ints_t.compare x2 y1 <= 0 then of_bool ik false - else top_bool - - let lt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 < 0 then of_bool ik true - else if Ints_t.compare y2 x1 <= 0 then of_bool ik false - else top_bool - - let invariant_ikind e ik = function - | Some (x1, x2) -> - let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in - IntInvariant.of_interval e ik (x1', x2') - | None -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let shrink = function - | Some (l, u) -> (return None) <+> (GobQCheck.shrink pair_arb (l, u) >|= of_interval ik >|= fst) - | None -> empty - in - QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) (fun x -> of_interval ik x |> fst ) pair_arb) - - let modulo n k = - let result = Ints_t.rem n k in - if Ints_t.compare result Ints_t.zero >= 0 then result - else Ints_t.add result k - - let refine_with_congruence ik (intv : t) (cong : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if Ints_t.equal m Ints_t.zero && (Ints_t.compare c x < 0 || Ints_t.compare c y > 0) then None - else if Ints_t.equal m Ints_t.zero then - Some (c, c) - else - let (min_ik, max_ik) = range ik in - let rcx = - if Ints_t.equal x min_ik then x else - Ints_t.add x (modulo (Ints_t.sub c x) (Ints_t.abs m)) in - let lcy = - if Ints_t.equal y max_ik then y else - Ints_t.sub y (modulo (Ints_t.sub y c) (Ints_t.abs m)) in - if Ints_t.compare rcx lcy > 0 then None - else if Ints_t.equal rcx lcy then norm ik @@ Some (rcx, rcx) |> fst - else norm ik @@ Some (rcx, lcy) |> fst - | _ -> None - - let refine_with_congruence ik x y = - let refn = refine_with_congruence ik x y in - if M.tracing then M.trace "refine" "int_refine_with_congruence %a %a -> %a" pretty x pretty y pretty refn; - refn - - let refine_with_interval ik a b = meet ik a b - - let refine_with_excl_list ik (intv : t) (excl : (int_t list * (int64 * int64)) option) : t = - match intv, excl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls, (rl, rh)) -> - let rec shrink op b = - let new_b = (op b (Ints_t.of_int(Bool.to_int(BatList.mem_cmp Ints_t.compare b ls)))) in - if not (Ints_t.equal b new_b) then shrink op new_b else new_b - in - let (min_ik, max_ik) = range ik in - let l' = if Ints_t.equal l min_ik then l else shrink Ints_t.add l in - let u' = if Ints_t.equal u max_ik then u else shrink Ints_t.sub u in - let intv' = norm ik @@ Some (l', u') |> fst in - let range = norm ~suppress_ovwarn:true ik (Some (Ints_t.of_bigint (Size.min_from_bit_range rl), Ints_t.of_bigint (Size.max_from_bit_range rh))) |> fst in - meet ik intv' range - - let refine_with_incl_list ik (intv: t) (incl : (int_t list) option) : t = - match intv, incl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls) -> - let rec min m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> min (Some x) xs | Some m -> if Ints_t.compare m x < 0 then min (Some m) xs else min (Some x) xs in - let rec max m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> max (Some x) xs | Some m -> if Ints_t.compare m x > 0 then max (Some m) xs else max (Some x) xs in - match min None ls, max None ls with - | Some m1, Some m2 -> refine_with_interval ik (Some(l, u)) (Some (m1, m2)) - | _, _-> intv - - let project ik p t = t -end - -(** IntervalSetFunctor that is not just disjunctive completion of intervals, but attempts to be precise for wraparound arithmetic for unsigned types *) -module IntervalSetFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) list = -struct - - module Interval = IntervalFunctor (Ints_t) - module IArith = IntervalArith (Ints_t) - - - let name () = "interval_sets" - - type int_t = Ints_t.t - - let (>.) a b = Ints_t.compare a b > 0 - let (=.) a b = Ints_t.compare a b = 0 - let (<.) a b = Ints_t.compare a b < 0 - let (>=.) a b = Ints_t.compare a b >= 0 - let (<=.) a b = Ints_t.compare a b <= 0 - let (+.) a b = Ints_t.add a b - let (-.) a b = Ints_t.sub a b - - (* - Each domain's element is guaranteed to be in canonical form. That is, each interval contained - inside the set does not overlap with each other and they are not adjacent. - *) - type t = (Ints_t.t * Ints_t.t) list [@@deriving eq, hash, ord] - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - - let top_of ik = [range ik] - - let bot () = [] - - let bot_of ik = bot () - - let show (x: t) = - let show_interval i = Printf.sprintf "[%s, %s]" (Ints_t.to_string (fst i)) (Ints_t.to_string (snd i)) in - List.fold_left (fun acc i -> (show_interval i) :: acc) [] x |> List.rev |> String.concat ", " |> Printf.sprintf "[%s]" - - (* New type definition for the sweeping line algorithm used for implementing join/meet functions. *) - type event = Enter of Ints_t.t | Exit of Ints_t.t - - let unbox_event = function Enter x -> x | Exit x -> x - - let cmp_events x y = - (* Deliberately comparing ints first => Cannot be derived *) - let res = Ints_t.compare (unbox_event x) (unbox_event y) in - if res <> 0 then res - else - begin - match (x, y) with - | (Enter _, Exit _) -> -1 - | (Exit _, Enter _) -> 1 - | (_, _) -> 0 - end - - let interval_set_to_events (xs: t) = - List.concat_map (fun (a, b) -> [Enter a; Exit b]) xs - - let two_interval_sets_to_events (xs: t) (ys: t) = - let xs = interval_set_to_events xs in - let ys = interval_set_to_events ys in - List.merge cmp_events xs ys - - (* Using the sweeping line algorithm, combined_event_list returns a new event list representing the intervals in which at least n intervals in xs overlap - This function is used for both join and meet operations with different parameter n: 1 for join, 2 for meet *) - let combined_event_list lattice_op (xs:event list) = - let l = match lattice_op with `Join -> 1 | `Meet -> 2 in - let aux (interval_count, acc) = function - | Enter x -> (interval_count + 1, if (interval_count + 1) >= l && interval_count < l then (Enter x)::acc else acc) - | Exit x -> (interval_count - 1, if interval_count >= l && (interval_count - 1) < l then (Exit x)::acc else acc) - in - List.fold_left aux (0, []) xs |> snd |> List.rev - - let rec events_to_intervals = function - | [] -> [] - | (Enter x)::(Exit y)::xs -> (x, y)::(events_to_intervals xs) - | _ -> failwith "Invalid events list" - - let remove_empty_gaps (xs: t) = - let aux acc (l, r) = match acc with - | ((a, b)::acc') when (b +. Ints_t.one) >=. l -> (a, r)::acc' - | _ -> (l, r)::acc - in - List.fold_left aux [] xs |> List.rev - - let canonize (xs: t) = - interval_set_to_events xs |> - List.sort cmp_events |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let unop (x: t) op = match x with - | [] -> [] - | _ -> canonize @@ List.concat_map op x - - let binop (x: t) (y: t) op : t = match x, y with - | [], _ -> [] - | _, [] -> [] - | _, _ -> canonize @@ List.concat_map op (BatList.cartesian_product x y) - - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let minimal = function - | [] -> None - | (x, _)::_ -> Some x - - let maximal = function - | [] -> None - | xs -> Some (BatList.last xs |> snd) - - let equal_to_interval i (a, b) = - if a =. b && b =. i then - `Eq - else if a <=. i && i <=. b then - `Top - else - `Neq - - let equal_to i xs = match List.map (equal_to_interval i) xs with - | [] -> failwith "unsupported: equal_to with bottom" - | [`Eq] -> `Eq - | ys when List.for_all ((=) `Neq) ys -> `Neq - | _ -> `Top - - let norm_interval ?(suppress_ovwarn=false) ?(cast=false) ik (x,y) : t*overflow_info = - if x >. y then - ([],{underflow=false; overflow=false}) - else - let (min_ik, max_ik) = range ik in - let underflow = min_ik >. x in - let overflow = max_ik <. y in - let v = if underflow || overflow then - begin - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (max_ik -. min_ik) in - let resdiff = Ints_t.abs (y -. x) in - if resdiff >. diff then - [range ik] - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if l <=. u then - [(l, u)] - else - (* Interval that wraps around (begins to the right of its end). We CAN represent such intervals *) - [(min_ik, u); (l, max_ik)] - else if not cast && should_ignore_overflow ik then - [Ints_t.max min_ik x, Ints_t.min max_ik y] - else - [range ik] - end - else - [(x,y)] - in - if suppress_ovwarn then (v, {underflow=false; overflow=false}) else (v, {underflow; overflow}) - - let norm_intvs ?(suppress_ovwarn=false) ?(cast=false) (ik:ikind) (xs: t) : t*overflow_info = - let res = List.map (norm_interval ~suppress_ovwarn ~cast ik) xs in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let binary_op_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> [op x y]) (BatList.cartesian_product x y) - - let binary_op_with_ovc (x: t) (y: t) op : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> - let res = List.map op (BatList.cartesian_product x y) in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let unary_op_with_norm op (ik:ikind) (x: t) = match x with - | [] -> ([],{overflow=false; underflow=false}) - | _ -> norm_intvs ik @@ List.concat_map (fun x -> [op x]) x - - let rec leq (xs: t) (ys: t) = - let leq_interval (al, au) (bl, bu) = al >=. bl && au <=. bu in - match xs, ys with - | [], _ -> true - | _, [] -> false - | (xl,xr)::xs', (yl,yr)::ys' -> - if leq_interval (xl,xr) (yl,yr) then - leq xs' ys - else if xr <. yl then - false - else - leq xs ys' - - let join ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let meet ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Meet |> - events_to_intervals - - let to_int = function - | [x] -> IArith.to_int x - | _ -> None - - let zero = [IArith.zero] - let one = [IArith.one] - let top_bool = [IArith.top_bool] - - let not_bool (x:t) = - let is_false x = equal x zero in - let is_true x = equal x one in - if is_true x then zero else if is_false x then one else top_bool - - let to_bool = function - | [(l,u)] when l =. Ints_t.zero && u =. Ints_t.zero -> Some false - | x -> if leq zero x then None else Some true - - let of_bool _ = function true -> one | false -> zero - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm_interval ~suppress_ovwarn ~cast:false ik (x,y) - - let of_int ik (x: int_t) = of_interval ik (x, x) - - let lt ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <. min_y then - of_bool ik true - else if min_x >=. max_y then - of_bool ik false - else - top_bool - - let le ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <=. min_y then - of_bool ik true - else if min_x >. max_y then - of_bool ik false - else - top_bool - - let gt ik x y = not_bool @@ le ik x y - - let ge ik x y = not_bool @@ lt ik x y - - let eq ik x y = match x, y with - | (a, b)::[], (c, d)::[] when a =. b && c =. d && a =. c -> - one - | _ -> - if is_bot (meet ik x y) then - zero - else - top_bool - - let ne ik x y = not_bool @@ eq ik x y - let interval_to_int i = Interval.to_int (Some i) - let interval_to_bool i = Interval.to_bool (Some i) - - let log f ik (i1, i2) = - match (interval_to_bool i1, interval_to_bool i2) with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - - let bit f ik (i1, i2) = - match (interval_to_int i1), (interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - - let bitcomp f ik (i1, i2) = - match (interval_to_int i1, interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{overflow=false; underflow=false})) - | _, _ -> (top_of ik,{overflow=false; underflow=false}) - - let logand ik x y = - let interval_logand = bit Ints_t.logand ik in - binop x y interval_logand - - let logor ik x y = - let interval_logor = bit Ints_t.logor ik in - binop x y interval_logor - - let logxor ik x y = - let interval_logxor = bit Ints_t.logxor ik in - binop x y interval_logxor - - let lognot ik x = - let interval_lognot i = - match interval_to_int i with - | Some x -> of_int ik (Ints_t.lognot x) |> fst - | _ -> top_of ik - in - unop x interval_lognot - - let shift_left ik x y = - let interval_shiftleft = bitcomp (fun x y -> Ints_t.shift_left x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftleft - - let shift_right ik x y = - let interval_shiftright = bitcomp (fun x y -> Ints_t.shift_right x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftright - - let c_lognot ik x = - let log1 f ik i1 = - match interval_to_bool i1 with - | Some x -> of_bool ik (f x) - | _ -> top_of ik - in - let interval_lognot = log1 not ik in - unop x interval_lognot - - let c_logand ik x y = - let interval_logand = log (&&) ik in - binop x y interval_logand - - let c_logor ik x y = - let interval_logor = log (||) ik in - binop x y interval_logor - - let add ?no_ov = binary_op_with_norm IArith.add - let sub ?no_ov = binary_op_with_norm IArith.sub - let mul ?no_ov = binary_op_with_norm IArith.mul - let neg ?no_ov = unary_op_with_norm IArith.neg - - let div ?no_ov ik x y = - let rec interval_div x (y1, y2) = begin - let top_of ik = top_of ik |> List.hd in - let is_zero v = v =. Ints_t.zero in - match y1, y2 with - | l, u when is_zero l && is_zero u -> top_of ik (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> interval_div x (Ints_t.one,y2) - | _, u when is_zero u -> interval_div x (y1, Ints_t.(neg one)) - | _ when leq (of_int ik (Ints_t.zero) |> fst) ([(y1,y2)]) -> top_of ik - | _ -> IArith.div x (y1, y2) - end - in binary_op_with_norm interval_div ik x y - - let rem ik x y = - let interval_rem (x, y) = - if Interval.is_top_of ik (Some x) && Interval.is_top_of ik (Some y) then - top_of ik - else - let (xl, xu) = x in let (yl, yu) = y in - let pos x = if x <. Ints_t.zero then Ints_t.neg x else x in - let b = (Ints_t.max (pos yl) (pos yu)) -. Ints_t.one in - let range = if xl >=. Ints_t.zero then (Ints_t.zero, Ints_t.min xu b) else (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit Ints_t.rem ik (x, y)) [range] - in - binop x y interval_rem - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik x = norm_intvs ~cast:true ik x - - (* - narrows down the extremeties of xs if they are equal to boundary values of the ikind with (possibly) narrower values from ys - *) - let narrow ik xs ys = match xs ,ys with - | [], _ -> [] | _ ,[] -> xs - | _, _ -> - let min_xs = minimal xs |> Option.get in - let max_xs = maximal xs |> Option.get in - let min_ys = minimal ys |> Option.get in - let max_ys = maximal ys |> Option.get in - let min_range,max_range = range ik in - let threshold = get_interval_threshold_widening () in - let min = if min_xs =. min_range || threshold && min_ys >. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in - let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in - xs - |> (function (_, y)::z -> (min, y)::z | _ -> []) - |> List.rev - |> (function (x, _)::z -> (x, max)::z | _ -> []) - |> List.rev - - (* - 1. partitions the intervals of xs by assigning each of them to the an interval in ys that includes it. - and joins all intervals in xs assigned to the same interval in ys as one interval. - 2. checks for every pair of adjacent pairs whether the pairs did approach (if you compare the intervals from xs and ys) and merges them if it is the case. - 3. checks whether partitions at the extremeties are approaching infinity (and expands them to infinity. in that case) - - The expansion (between a pair of adjacent partitions or at extremeties ) stops at a threshold. - *) - let widen ik xs ys = - let (min_ik,max_ik) = range ik in - let threshold = get_bool "ana.int.interval_threshold_widening" in - let upper_threshold (_,u) = IArith.upper_threshold u max_ik in - let lower_threshold (l,_) = IArith.lower_threshold l min_ik in - (*obtain partitioning of xs intervals according to the ys interval that includes them*) - let rec interval_sets_to_partitions (ik: ikind) (acc : (int_t * int_t) option) (xs: t) (ys: t)= - match xs,ys with - | _, [] -> [] - | [], (y::ys) -> (acc,y):: interval_sets_to_partitions ik None [] ys - | (x::xs), (y::ys) when Interval.leq (Some x) (Some y) -> interval_sets_to_partitions ik (Interval.join ik acc (Some x)) xs (y::ys) - | (x::xs), (y::ys) -> (acc,y) :: interval_sets_to_partitions ik None (x::xs) ys - in - let interval_sets_to_partitions ik xs ys = interval_sets_to_partitions ik None xs ys in - (*merge a pair of adjacent partitions*) - let merge_pair ik (a,b) (c,d) = - let new_a = function - | None -> Some (upper_threshold b, upper_threshold b) - | Some (ax,ay) -> Some (ax, upper_threshold b) - in - let new_c = function - | None -> Some (lower_threshold d, lower_threshold d) - | Some (cx,cy) -> Some (lower_threshold d, cy) - in - if threshold && (lower_threshold d +. Ints_t.one) >. (upper_threshold b) then - [(new_a a,(fst b, upper_threshold b)); (new_c c, (lower_threshold d, snd d))] - else - [(Interval.join ik a c, (Interval.join ik (Some b) (Some d) |> Option.get))] - in - let partitions_are_approaching part_left part_right = match part_left, part_right with - | (Some (_, left_x), (_, left_y)), (Some (right_x, _), (right_y, _)) -> (right_x -. left_x) >. (right_y -. left_y) - | _,_ -> false - in - (*merge all approaching pairs of adjacent partitions*) - let rec merge_list ik = function - | [] -> [] - | x::y::xs when partitions_are_approaching x y -> merge_list ik ((merge_pair ik x y) @ xs) - | x::xs -> x :: merge_list ik xs - in - (*expands left extremity*) - let widen_left = function - | [] -> [] - | (None,(lb,rb))::ts -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (None, (lt,rb))::ts - | (Some (la,ra), (lb,rb))::ts when lb <. la -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (Some (la,ra),(lt,rb))::ts - | x -> x - in - (*expands right extremity*) - let widen_right x = - let map_rightmost = function - | [] -> [] - | (None,(lb,rb))::ts -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (None, (lb,ut))::ts - | (Some (la,ra), (lb,rb))::ts when ra <. rb -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (Some (la,ra),(lb,ut))::ts - | x -> x - in - List.rev x |> map_rightmost |> List.rev - in - interval_sets_to_partitions ik xs ys |> merge_list ik |> widen_left |> widen_right |> List.map snd - - let starting ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (fst (range ik), n) - - let invariant_ikind e ik xs = - List.map (fun x -> Interval.invariant_ikind e ik (Some x)) xs |> - let open Invariant in List.fold_left (||) (bot ()) - - let modulo n k = - let result = Ints_t.rem n k in - if result >=. Ints_t.zero then result - else result +. k - - let refine_with_congruence ik (intvs: t) (cong: (int_t * int_t ) option): t = - let refine_with_congruence_interval ik (cong : (int_t * int_t ) option) (intv : (int_t * int_t ) option): t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =. Ints_t.zero && (c <. x || c >. y) then [] - else if m =. Ints_t.zero then - [(c, c)] - else - let (min_ik, max_ik) = range ik in - let rcx = - if x =. min_ik then x else - x +. (modulo (c -. x) (Ints_t.abs m)) in - let lcy = - if y =. max_ik then y else - y -. (modulo (y -. c) (Ints_t.abs m)) in - if rcx >. lcy then [] - else if rcx =. lcy then norm_interval ik (rcx, rcx) |> fst - else norm_interval ik (rcx, lcy) |> fst - | _ -> [] - in - List.concat_map (fun x -> refine_with_congruence_interval ik cong (Some x)) intvs - - let refine_with_interval ik xs = function None -> [] | Some (a,b) -> meet ik xs [(a,b)] - - let refine_with_incl_list ik intvs = function - | None -> intvs - | Some xs -> meet ik intvs (List.map (fun x -> (x,x)) xs) - - let excl_range_to_intervalset (ik: ikind) ((min, max): int_t * int_t) (excl: int_t): t = - let intv1 = (min, excl -. Ints_t.one) in - let intv2 = (excl +. Ints_t.one, max) in - norm_intvs ik ~suppress_ovwarn:true [intv1 ; intv2] |> fst - - let of_excl_list ik (excls: int_t list) = - let excl_list = List.map (excl_range_to_intervalset ik (range ik)) excls in - let res = List.fold_left (meet ik) (top_of ik) excl_list in - res - - let refine_with_excl_list ik (intv : t) = function - | None -> intv - | Some (xs, range) -> - let excl_to_intervalset (ik: ikind) ((rl, rh): (int64 * int64)) (excl: int_t): t = - excl_range_to_intervalset ik (Ints_t.of_bigint (Size.min_from_bit_range rl),Ints_t.of_bigint (Size.max_from_bit_range rh)) excl - in - let excl_list = List.map (excl_to_intervalset ik range) xs in - List.fold_left (meet ik) intv excl_list - - let project ik p t = t - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let list_pair_arb = QCheck.small_list pair_arb in - let canonize_randomly_generated_list = (fun x -> norm_intvs ik x |> fst) in - let shrink xs = GobQCheck.shrink list_pair_arb xs >|= canonize_randomly_generated_list - in QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) canonize_randomly_generated_list list_pair_arb) -end - -module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct - include D - - let add ?no_ov ik x y = fst @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = fst @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = fst @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = fst @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = fst @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = fst @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = fst @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = fst @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = fst @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = fst @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = fst @@ D.shift_left ik x y - - let shift_right ik x y = fst @@ D.shift_right ik x y -end - -module IntIkind = struct let ikind () = Cil.IInt end -module Interval = IntervalFunctor (IntOps.BigIntOps) -module Interval32 = IntDomWithDefaultIkind (IntDomLifter (SOverflowUnlifter (IntervalFunctor (IntOps.Int64Ops)))) (IntIkind) -module IntervalSet = IntervalSetFunctor (IntOps.BigIntOps) -module Integers (Ints_t : IntOps.IntOps): IkindUnawareS with type t = Ints_t.t and type int_t = Ints_t.t = (* no top/bot, order is <= *) -struct - include Printable.Std - let name () = "integers" - type t = Ints_t.t [@@deriving eq, ord, hash] - type int_t = Ints_t.t - let top () = raise Unknown - let bot () = raise Error - let top_of ik = top () - let bot_of ik = bot () - let show (x: Ints_t.t) = Ints_t.to_string x - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - (* is_top and is_bot are never called, but if they were, the Std impl would raise their exception, so we overwrite them: *) - let is_top _ = false - let is_bot _ = false - - let equal_to i x = if i > x then `Neq else `Top - let leq x y = x <= y - let join x y = if Ints_t.compare x y > 0 then x else y - let widen = join - let meet x y = if Ints_t.compare x y > 0 then y else x - let narrow = meet - - let of_bool x = if x then Ints_t.one else Ints_t.zero - let to_bool' x = x <> Ints_t.zero - let to_bool x = Some (to_bool' x) - let of_int x = x - let to_int x = Some x - - let neg = Ints_t.neg - let add = Ints_t.add (* TODO: signed overflow is undefined behavior! *) - let sub = Ints_t.sub - let mul = Ints_t.mul - let div = Ints_t.div - let rem = Ints_t.rem - let lt n1 n2 = of_bool (n1 < n2) - let gt n1 n2 = of_bool (n1 > n2) - let le n1 n2 = of_bool (n1 <= n2) - let ge n1 n2 = of_bool (n1 >= n2) - let eq n1 n2 = of_bool (n1 = n2) - let ne n1 n2 = of_bool (n1 <> n2) - let lognot = Ints_t.lognot - let logand = Ints_t.logand - let logor = Ints_t.logor - let logxor = Ints_t.logxor - let shift_left n1 n2 = Ints_t.shift_left n1 (Ints_t.to_int n2) - let shift_right n1 n2 = Ints_t.shift_right n1 (Ints_t.to_int n2) - let c_lognot n1 = of_bool (not (to_bool' n1)) - let c_logand n1 n2 = of_bool ((to_bool' n1) && (to_bool' n2)) - let c_logor n1 n2 = of_bool ((to_bool' n1) || (to_bool' n2)) - let cast_to ?(suppress_ovwarn=false) ?torg t x = failwith @@ "Cast_to not implemented for " ^ (name ()) ^ "." - let arbitrary ik = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 (* TODO: use ikind *) - let invariant _ _ = Invariant.none (* TODO *) -end - -module FlatPureIntegers: IkindUnawareS with type t = int64 and type int_t = int64 = (* Integers, but raises Unknown/Error on join/meet *) -struct - include Integers(IntOps.Int64Ops) - let top () = raise Unknown - let bot () = raise Error - let leq = equal - let pretty_diff () (x,y) = Pretty.dprintf "Integer %a instead of %a" pretty x pretty y - let join x y = if equal x y then x else top () - let meet x y = if equal x y then x else bot () -end - -module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) -struct - type int_t = Base.int_t - include Lattice.FlatConf (struct - include Printable.DefaultConf - let top_name = "Unknown int" - let bot_name = "Error int" - end) (Base) - - let top_of ik = top () - let bot_of ik = bot () - - - let name () = "flat integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ikind x = top_of ikind - let ending ?(suppress_ovwarn=false) ikind x = top_of ikind - let maximal x = None - let minimal x = None - - let lift1 f x = match x with - | `Lifted x -> - (try `Lifted (f x) with Unknown -> `Top | Error -> `Bot) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> - (try `Lifted (f x y) with Unknown -> `Top | Error -> `Bot) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) -struct - include Lattice.LiftPO (struct - include Printable.DefaultConf - let top_name = "MaxInt" - let bot_name = "MinInt" - end) (Base) - type int_t = Base.int_t - let top_of ik = top () - let bot_of ik = bot () - include StdTop (struct type nonrec t = t let top_of = top_of end) - - let name () = "lifted integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let lift1 f x = match x with - | `Lifted x -> `Lifted (f x) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> `Lifted (f x y) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Flattened = Flat (Integers (IntOps.Int64Ops)) -module Lifted = Lift (Integers (IntOps.Int64Ops)) - -module Reverse (Base: IkindUnawareS) = -struct - include Base - include (Lattice.Reverse (Base) : Lattice.S with type t := Base.t) -end - -module BISet = struct - include SetDomain.Make (IntOps.BigIntOps) - let is_singleton s = cardinal s = 1 -end - -(* The module [Exclusion] constains common functionality about handling of exclusion sets between [DefExc] and [Enums] *) -module Exclusion = -struct - module R = Interval32 - (* We use these types for the functions in this module to make the intended meaning more explicit *) - type t = Exc of BISet.t * Interval32.t - type inc = Inc of BISet.t [@@unboxed] - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.succ (Z.add (Z.neg (min_of_range r)) (max_of_range r)) - - let cardinality_BISet s = - Z.of_int (BISet.cardinal s) - - let leq_excl_incl (Exc (xs, r)) (Inc ys) = - (* For a <= b to hold, the cardinalities must fit, i.e. |a| <= |b|, which implies |min_r, max_r| - |xs| <= |ys|. We check this first. *) - let lower_bound_cardinality_a = Z.sub (cardinality_of_range r) (cardinality_BISet xs) in - let card_b = cardinality_BISet ys in - if Z.compare lower_bound_cardinality_a card_b > 0 then - false - else (* The cardinality did fit, so we check for all elements that are represented by range r, whether they are in (xs union ys) *) - let min_a = min_of_range r in - let max_a = max_of_range r in - GobZ.for_all_range (fun el -> BISet.mem el xs || BISet.mem el ys) (min_a, max_a) - - let leq (Exc (xs, r)) (Exc (ys, s)) = - let min_a, max_a = min_of_range r, max_of_range r in - let excluded_check = BISet.for_all (fun y -> BISet.mem y xs || Z.compare y min_a < 0 || Z.compare y max_a > 0) ys in (* if true, then the values ys, that are not in b, also do not occur in a *) - if not excluded_check - then false - else begin (* Check whether all elements that are in the range r, but not in s, are in xs, i.e. excluded. *) - if R.leq r s then true - else begin if Z.compare (cardinality_BISet xs) (Z.sub (cardinality_of_range r) (cardinality_of_range s)) >= 0 (* Check whether the number of excluded elements in a is as least as big as |min_r, max_r| - |min_s, max_s| *) - then - let min_b, max_b = min_of_range s, max_of_range s in - let leq1 = (* check whether the elements in [r_l; s_l-1] are all in xs, i.e. excluded *) - if Z.compare min_a min_b < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (min_a, Z.pred min_b) - else - true - in - let leq2 () = (* check whether the elements in [s_u+1; r_u] are all in xs, i.e. excluded *) - if Z.compare max_b max_a < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (Z.succ max_b, max_a) - else - true - in - leq1 && (leq2 ()) - else - false - end - end -end - -module DefExc : S with type int_t = Z.t = (* definite or set of excluded values *) -struct - module S = BISet - module R = Interval32 (* range for exclusion *) - - (* Ikind used for intervals representing the domain *) - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - - type t = [ - | `Excluded of S.t * R.t - | `Definite of Z.t - | `Bot - ] [@@deriving eq, ord, hash] - type int_t = Z.t - let name () = "def_exc" - - - let top_range = R.of_interval range_ikind (-99L, 99L) (* Since there is no top ikind we use a range that includes both ILongLong [-63,63] and IULongLong [0,64]. Only needed for intermediate range computation on longs. Correct range is set by cast. *) - let top () = `Excluded (S.empty (), top_range) - let bot () = `Bot - let top_of ik = `Excluded (S.empty (), size ik) - let bot_of ik = bot () - - let show x = - let short_size x = "("^R.show x^")" in - match x with - | `Bot -> "Error int" - | `Definite x -> Z.to_string x - (* Print the empty exclusion as if it was a distinct top element: *) - | `Excluded (s,l) when S.is_empty s -> "Unknown int" ^ short_size l - (* Prepend the exclusion sets with something: *) - | `Excluded (s,l) -> "Not " ^ S.show s ^ short_size l - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let maximal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.max_of_range r) - | `Bot -> None - - let minimal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.min_of_range r) - | `Bot -> None - - let in_range r i = - if Z.compare i Z.zero < 0 then - let lowerb = Exclusion.min_of_range r in - Z.compare lowerb i <= 0 - else - let upperb = Exclusion.max_of_range r in - Z.compare i upperb <= 0 - - let is_top x = x = top () - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Definite x -> if i = x then `Eq else `Neq - | `Excluded (s,r) -> if S.mem i s then `Neq else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik = function - | `Excluded (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - `Excluded (s, r) - else if ik = IBool then (* downcast to bool *) - if S.mem Z.zero s then - `Definite Z.one - else - `Excluded (S.empty(), r') - else - (* downcast: may overflow *) - (* let s' = S.map (Size.cast ik) s in *) - (* We want to filter out all i in s' where (t)x with x in r could be i. *) - (* Since this is hard to compute, we just keep all i in s' which overflowed, since those are safe - all i which did not overflow may now be possible due to overflow of r. *) - (* S.diff s' s, r' *) - (* The above is needed for test 21/03, but not sound! See example https://github.com/goblint/analyzer/pull/95#discussion_r483023140 *) - `Excluded (S.empty (), r') - | `Definite x -> `Definite (Size.cast ik x) - | `Bot -> `Bot - - (* Wraps definite values and excluded values according to the ikind. - * For an `Excluded s,r , assumes that r is already an overapproximation of the range of possible values. - * r might be larger than the possible range of this type; the range of the returned `Excluded set will be within the bounds of the ikind. - *) - let norm ik v = - match v with - | `Excluded (s, r) -> - let possibly_overflowed = not (R.leq r (size ik)) || not (S.for_all (in_range (size ik)) s) in - (* If no overflow occurred, just return x *) - if not possibly_overflowed then ( - v - ) - (* Else, if an overflow might have occurred but we should just ignore it *) - else if should_ignore_overflow ik then ( - let r = size ik in - (* filter out excluded elements that are not in the range *) - let mapped_excl = S.filter (in_range r) s in - `Excluded (mapped_excl, r) - ) - (* Else, if an overflow occurred that we should not treat with wrap-around, go to top *) - else if not (should_wrap ik) then ( - top_of ik - ) else ( - (* Else an overflow occurred that we should treat with wrap-around *) - let r = size ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - let mapped_excl = S.map (fun excl -> Size.cast ik excl) s in - match ik with - | IBool -> - begin match S.mem Z.zero mapped_excl, S.mem Z.one mapped_excl with - | false, false -> `Excluded (mapped_excl, r) (* Not {} -> Not {} *) - | true, false -> `Definite Z.one (* Not {0} -> 1 *) - | false, true -> `Definite Z.zero (* Not {1} -> 0 *) - | true, true -> `Bot (* Not {0, 1} -> bot *) - end - | ik -> - `Excluded (mapped_excl, r) - ) - | `Definite x -> - let min, max = Size.range ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - if should_wrap ik then ( - cast_to ik v - ) - else if Z.compare min x <= 0 && Z.compare x max <= 0 then ( - v - ) - else if should_ignore_overflow ik then ( - M.warn ~category:M.Category.Integer.overflow "DefExc: Value was outside of range, indicating overflow, but 'sem.int.signed_overflow' is 'assume_none' -> Returned Bot"; - `Bot - ) - else ( - top_of ik - ) - | `Bot -> `Bot - - let leq x y = match (x,y) with - (* `Bot <= x is always true *) - | `Bot, _ -> true - (* Anything except bot <= bot is always false *) - | _, `Bot -> false - (* Two known values are leq whenever equal *) - | `Definite (x: int_t), `Definite y -> x = y - (* A definite value is leq all exclusion sets that don't contain it *) - | `Definite x, `Excluded (s,r) -> in_range r x && not (S.mem x s) - (* No finite exclusion set can be leq than a definite value *) - | `Excluded (xs, xr), `Definite d -> - Exclusion.(leq_excl_incl (Exc (xs, xr)) (Inc (S.singleton d))) - | `Excluded (xs,xr), `Excluded (ys,yr) -> - Exclusion.(leq (Exc (xs,xr)) (Exc (ys, yr))) - - let join' ?range ik x y = - match (x,y) with - (* The least upper bound with the bottom element: *) - | `Bot, x -> x - | x, `Bot -> x - (* The case for two known values: *) - | `Definite (x: int_t), `Definite y -> - (* If they're equal, it's just THAT value *) - if x = y then `Definite x - (* Unless one of them is zero, we can exclude it: *) - else - let a,b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval range_ikind a) (R.of_interval range_ikind b) in - `Excluded ((if Z.equal x Z.zero || Z.equal y Z.zero then S.empty () else S.singleton Z.zero), r) - (* A known value and an exclusion set... the definite value should no - * longer be excluded: *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> - if not (in_range r x) then - let a = R.of_interval range_ikind (Size.min_range_sign_agnostic x) in - `Excluded (S.remove x s, R.join a r) - else - `Excluded (S.remove x s, r) - (* For two exclusion sets, only their intersection can be excluded: *) - | `Excluded (x,wx), `Excluded (y,wy) -> `Excluded (S.inter x y, range |? R.join wx wy) - - let join ik = join' ik - - - let widen ik x y = - if get_def_exc_widen_by_join () then - join' ik x y - else if equal x y then - x - else - join' ~range:(size ik) ik x y - - - let meet ik x y = - match (x,y) with - (* Greatest LOWER bound with the least element is trivial: *) - | `Bot, _ -> `Bot - | _, `Bot -> `Bot - (* Definite elements are either equal or the glb is bottom *) - | `Definite x, `Definite y -> if x = y then `Definite x else `Bot - (* The glb of a definite element and an exclusion set is either bottom or - * just the element itself, if it isn't in the exclusion set *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> if S.mem x s || not (in_range r x) then `Bot else `Definite x - (* The greatest lower bound of two exclusion sets is their union, this is - * just DeMorgans Law *) - | `Excluded (x,r1), `Excluded (y,r2) -> - let r' = R.meet r1 r2 in - let s' = S.union x y |> S.filter (in_range r') in - `Excluded (s', r') - - let narrow ik x y = x - - let of_int ik x = norm ik @@ `Definite x - let to_int x = match x with - | `Definite x -> Some x - | _ -> None - - let from_excl ikind (s: S.t) = norm ikind @@ `Excluded (s, size ikind) - - let of_bool_cmp ik x = of_int ik (if x then Z.one else Z.zero) - let of_bool = of_bool_cmp - let to_bool x = - match x with - | `Definite x -> Some (IntOps.BigIntOps.to_bool x) - | `Excluded (s,r) when S.mem Z.zero s -> Some true - | _ -> None - let top_bool = `Excluded (S.empty (), R.of_interval range_ikind (0L, 1L)) - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then S.singleton Z.zero else S.empty () in - norm ik @@ (`Excluded (ex, r)) - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let of_excl_list t l = - let r = size t in (* elements in l are excluded from the full range of t! *) - `Excluded (List.fold_right S.add l (S.empty ()), r) - let is_excl_list l = match l with `Excluded _ -> true | _ -> false - let to_excl_list (x:t) = match x with - | `Definite _ -> None - | `Excluded (s,r) -> Some (S.elements s, (Option.get (R.minimal r), Option.get (R.maximal r))) - | `Bot -> None - - let to_incl_list x = match x with - | `Definite x -> Some [x] - | `Excluded _ -> None - | `Bot -> None - - let apply_range f r = (* apply f to the min/max of the old range r to get a new range *) - (* If the Int64 might overflow on us during computation, we instead go to top_range *) - match R.minimal r, R.maximal r with - | _ -> - let rf m = (size % Size.min_for % f) (m r) in - let r1, r2 = rf Exclusion.min_of_range, rf Exclusion.max_of_range in - R.join r1 r2 - - (* Default behaviour for unary operators, simply maps the function to the - * DefExc data structure. *) - let lift1 f ik x = norm ik @@ match x with - | `Excluded (s,r) -> - let s' = S.map f s in - `Excluded (s', apply_range f r) - | `Definite x -> `Definite (f x) - | `Bot -> `Bot - - let lift2 f ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite _ - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (f x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - (* Default behaviour for binary operators that are injective in either - * argument, so that Exclusion Sets can be used: *) - let lift2_inj f ik x y = - let def_exc f x s r = `Excluded (S.map (f x) s, apply_range (f x) r) in - norm ik @@ - match x,y with - (* If both are exclusion sets, there isn't anything we can do: *) - | `Excluded _, `Excluded _ -> top () - (* A definite value should be applied to all members of the exclusion set *) - | `Definite x, `Excluded (s,r) -> def_exc f x s r - (* Same thing here, but we should flip the operator to map it properly *) - | `Excluded (s,r), `Definite x -> def_exc (Batteries.flip f) x s r - (* The good case: *) - | `Definite x, `Definite y -> `Definite (f x y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The equality check: *) - let eq ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x equal to an exclusion set, if it is a member then NO otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt false else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt false else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x = y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The inequality check: *) - let ne ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x unequal to an exclusion set, if it is a member then Yes otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt true else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt true else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x <> y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - let neg ?no_ov ik (x :t) = norm ik @@ lift1 Z.neg ik x - let add ?no_ov ik x y = norm ik @@ lift2_inj Z.add ik x y - - let sub ?no_ov ik x y = norm ik @@ lift2_inj Z.sub ik x y - let mul ?no_ov ik x y = norm ik @@ match x, y with - | `Definite z, (`Excluded _ | `Definite _) when Z.equal z Z.zero -> x - | (`Excluded _ | `Definite _), `Definite z when Z.equal z Z.zero -> y - | `Definite a, `Excluded (s,r) - (* Integer multiplication with even numbers is not injective. *) - (* Thus we cannot exclude the values to which the exclusion set would be mapped to. *) - | `Excluded (s,r),`Definite a when Z.equal (Z.rem a (Z.of_int 2)) Z.zero -> `Excluded (S.empty (), apply_range (Z.mul a) r) - | _ -> lift2_inj Z.mul ik x y - let div ?no_ov ik x y = lift2 Z.div ik x y - let rem ik x y = lift2 Z.rem ik x y - - (* Comparison handling copied from Enums. *) - let handle_bot x y f = match x, y with - | `Bot, `Bot -> `Bot - | `Bot, _ - | _, `Bot -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> f () - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let lognot = lift1 Z.lognot - - let logand ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite i -> - (* Except in two special cases *) - if Z.equal i Z.zero then - `Definite Z.zero - else if Z.equal i Z.one then - of_interval IBool (Z.zero, Z.one) - else - top () - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (Z.logand x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - norm ik @@ lift2 shift_op_big_int ik x y - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - (* TODO: lift does not treat Not {0} as true. *) - let c_logand ik x y = - match to_bool x, to_bool y with - | Some false, _ - | _, Some false -> - of_bool ik false - | _, _ -> - lift2 IntOps.BigIntOps.c_logand ik x y - let c_logor ik x y = - match to_bool x, to_bool y with - | Some true, _ - | _, Some true -> - of_bool ik true - | _, _ -> - lift2 IntOps.BigIntOps.c_logor ik x y - let c_lognot ik = eq ik (of_int ik Z.zero) - - let invariant_ikind e ik (x:t) = - match x with - | `Definite x -> - IntInvariant.of_int e ik x - | `Excluded (s, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let si = IntInvariant.of_excl_list e ik (S.elements s) in - Invariant.(ri && si) - | `Bot -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - let excluded s = from_excl ik s in - let definite x = of_int ik x in - let shrink = function - | `Excluded (s, _) -> GobQCheck.shrink (S.arbitrary ()) s >|= excluded (* S TODO: possibly shrink excluded to definite *) - | `Definite x -> (return `Bot) <+> (GobQCheck.shrink (IntOps.BigIntOps.arbitrary ()) x >|= definite) - | `Bot -> empty - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map excluded (S.arbitrary ()); - 10, QCheck.map definite (IntOps.BigIntOps.arbitrary ()); - 1, QCheck.always `Bot - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = a - let refine_with_interval ik a b = match a, b with - | x, Some(i) -> meet ik x (of_interval ik i) - | _ -> a - let refine_with_excl_list ik a b = match a, b with - | `Excluded (s, r), Some(ls, _) -> meet ik (`Excluded (s, r)) (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - let refine_with_incl_list ik a b = a - - let project ik p t = t -end (* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) module Enums : S with type int_t = Z.t = struct @@ -2742,35 +367,3 @@ module Enums : S with type int_t = Z.t = struct let project ik p t = t end - -module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct - - include D - - let lift v = (v, {overflow=false; underflow=false}) - - let add ?no_ov ik x y = lift @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = lift @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = lift @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = lift @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = lift @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = lift @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = lift @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = lift @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = lift @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = lift @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = lift @@ D.shift_left ik x y - - let shift_right ik x y = lift @@ D.shift_right ik x y - -end From 94581ee6820d7c0668d99c9f4447b1d190eb8426 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:00:28 +0300 Subject: [PATCH 599/689] Remove Enums from IntDomain0 --- src/cdomain/value/cdomains/intDomain0.ml | 367 ----------------------- 1 file changed, 367 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/intDomain0.ml index 8dd8b07f74..1cda533c55 100644 --- a/src/cdomain/value/cdomains/intDomain0.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -2376,373 +2376,6 @@ struct let project ik p t = t end -(* Inclusion/Exclusion sets. Go to top on arithmetic operations (except for some easy cases, e.g. multiplication with 0). Joins on widen, i.e. precise integers as long as not derived from arithmetic expressions. *) -module Enums : S with type int_t = Z.t = struct - module R = Interval32 (* range for exclusion *) - - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - type t = Inc of BISet.t | Exc of BISet.t * R.t [@@deriving eq, ord, hash] (* inclusion/exclusion set *) - - type int_t = Z.t - let name () = "enums" - let bot () = failwith "bot () not implemented for Enums" - let top () = failwith "top () not implemented for Enums" - let bot_of ik = Inc (BISet.empty ()) - let top_bool = Inc (BISet.of_list [Z.zero; Z.one]) - let top_of ik = - match ik with - | IBool -> top_bool - | _ -> Exc (BISet.empty (), size ik) - - let range ik = Size.range ik - -(* - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.add (Z.neg (min_of_range r)) (max_of_range r) *) - let value_in_range (min, max) v = Z.compare min v <= 0 && Z.compare v max <= 0 - - let show = function - | Inc xs when BISet.is_empty xs -> "bot" - | Inc xs -> "{" ^ (String.concat ", " (List.map Z.to_string (BISet.elements xs))) ^ "}" - | Exc (xs,r) -> "not {" ^ (String.concat ", " (List.map Z.to_string (BISet.elements xs))) ^ "} " ^ "("^R.show r^")" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - (* Normalization function for enums, that handles overflows for Inc. - As we do not compute on Excl, we do not have to perform any overflow handling for it. *) - let norm ikind v = - let min, max = range ikind in - (* Whether the value v lies within the values of the specified ikind. *) - let value_in_ikind v = - Z.compare min v <= 0 && Z.compare v max <= 0 - in - match v with - | Inc xs when BISet.for_all value_in_ikind xs -> v - | Inc xs -> - if should_wrap ikind then - Inc (BISet.map (Size.cast ikind) xs) - else if should_ignore_overflow ikind then - Inc (BISet.filter value_in_ikind xs) - else - top_of ikind - | Exc (xs, r) -> - (* The following assert should hold for Exc, therefore we do not have to overflow handling / normalization for it: - let range_in_ikind r = - R.leq r (size ikind) - in - let r_min, r_max = min_of_range r, max_of_range r in - assert (range_in_ikind r && BISet.for_all (value_in_range (r_min, r_max)) xs); *) - begin match ikind with - | IBool -> - begin match BISet.mem Z.zero xs, BISet.mem Z.one xs with - | false, false -> top_bool (* Not {} -> {0, 1} *) - | true, false -> Inc (BISet.singleton Z.one) (* Not {0} -> {1} *) - | false, true -> Inc (BISet.singleton Z.zero) (* Not {1} -> {0} *) - | true, true -> bot_of ikind (* Not {0, 1} -> bot *) - end - | _ -> - v - end - - - let equal_to i = function - | Inc x -> - if BISet.mem i x then - if BISet.is_singleton x then `Eq - else `Top - else `Neq - | Exc (x, r) -> - if BISet.mem i x then `Neq - else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik v = norm ik @@ match v with - | Exc (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - Exc (s, r) - else if ik = IBool then (* downcast to bool *) - if BISet.mem Z.zero s then - Inc (BISet.singleton Z.one) - else - Exc (BISet.empty(), r') - else (* downcast: may overflow *) - Exc ((BISet.empty ()), r') - | Inc xs -> - let casted_xs = BISet.map (Size.cast ik) xs in - if Cil.isSigned ik && not (BISet.equal xs casted_xs) - then top_of ik (* When casting into a signed type and the result does not fit, the behavior is implementation-defined *) - else Inc casted_xs - - let of_int ikind x = cast_to ikind (Inc (BISet.singleton x)) - - let of_interval ?(suppress_ovwarn=false) ik (x, y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then BISet.singleton Z.zero else BISet.empty () in - norm ik @@ (Exc (ex, r)) - - let join _ x y = - match x, y with - | Inc x, Inc y -> Inc (BISet.union x y) - | Exc (x,r1), Exc (y,r2) -> Exc (BISet.inter x y, R.join r1 r2) - | Exc (x,r), Inc y - | Inc y, Exc (x,r) -> - let r = if BISet.is_empty y - then r - else - let (min_el_range, max_el_range) = Batteries.Tuple2.mapn (fun x -> R.of_interval range_ikind (Size.min_range_sign_agnostic x)) (BISet.min_elt y, BISet.max_elt y) in - let range = R.join min_el_range max_el_range in - R.join r range - in - Exc (BISet.diff x y, r) - - let meet _ x y = - match x, y with - | Inc x, Inc y -> Inc (BISet.inter x y) - | Exc (x,r1), Exc (y,r2) -> - let r = R.meet r1 r2 in - let r_min, r_max = Exclusion.min_of_range r, Exclusion.max_of_range r in - let filter_by_range = BISet.filter (value_in_range (r_min, r_max)) in - (* We remove those elements from the exclusion set that do not fit in the range anyway *) - let excl = BISet.union (filter_by_range x) (filter_by_range y) in - Exc (excl, r) - | Inc x, Exc (y,r) - | Exc (y,r), Inc x -> Inc (BISet.diff x y) - - let widen = join - let narrow = meet - let leq a b = - match a, b with - | Inc xs, Exc (ys, r) -> - if BISet.is_empty xs - then true - else - let min_b, max_b = Exclusion.min_of_range r, Exclusion.max_of_range r in - let min_a, max_a = BISet.min_elt xs, BISet.max_elt xs in - (* Check that the xs fit into the range r *) - Z.compare min_b min_a <= 0 && Z.compare max_a max_b <= 0 && - (* && check that none of the values contained in xs is excluded, i.e. contained in ys. *) - BISet.for_all (fun x -> not (BISet.mem x ys)) xs - | Inc xs, Inc ys -> - BISet.subset xs ys - | Exc (xs, r), Exc (ys, s) -> - Exclusion.(leq (Exc (xs, r)) (Exc (ys, s))) - | Exc (xs, r), Inc ys -> - Exclusion.(leq_excl_incl (Exc (xs, r)) (Inc ys)) - - let handle_bot x y f = match is_bot x, is_bot y with - | false, false -> f () - | true, false - | false, true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | true, true -> Inc (BISet.empty ()) - - let lift1 f ikind v = norm ikind @@ match v with - | Inc x when BISet.is_empty x -> v (* Return bottom when value is bottom *) - | Inc x when BISet.is_singleton x -> Inc (BISet.singleton (f (BISet.choose x))) - | _ -> top_of ikind - - let lift2 f (ikind: Cil.ikind) u v = - handle_bot u v (fun () -> - norm ikind @@ match u, v with - | Inc x,Inc y when BISet.is_singleton x && BISet.is_singleton y -> Inc (BISet.singleton (f (BISet.choose x) (BISet.choose y))) - | _,_ -> top_of ikind) - - let lift2 f ikind a b = - try lift2 f ikind a b with Division_by_zero -> top_of ikind - - let neg ?no_ov = lift1 Z.neg - let add ?no_ov ikind a b = - match a, b with - | Inc z,x when BISet.is_singleton z && BISet.choose z = Z.zero -> x - | x,Inc z when BISet.is_singleton z && BISet.choose z = Z.zero -> x - | x,y -> lift2 Z.add ikind x y - let sub ?no_ov = lift2 Z.sub - let mul ?no_ov ikind a b = - match a, b with - | Inc one,x when BISet.is_singleton one && BISet.choose one = Z.one -> x - | x,Inc one when BISet.is_singleton one && BISet.choose one = Z.one -> x - | Inc zero,_ when BISet.is_singleton zero && BISet.choose zero = Z.zero -> a - | _,Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> b - | x,y -> lift2 Z.mul ikind x y - - let div ?no_ov ikind a b = match a, b with - | x,Inc one when BISet.is_singleton one && BISet.choose one = Z.one -> x - | _,Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> top_of ikind - | Inc zero,_ when BISet.is_singleton zero && BISet.choose zero = Z.zero -> a - | x,y -> lift2 Z.div ikind x y - - let rem = lift2 Z.rem - - let lognot = lift1 Z.lognot - let logand = lift2 Z.logand - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - handle_bot x y (fun () -> - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - lift2 shift_op_big_int ik x y) - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - - let of_bool ikind x = Inc (BISet.singleton (if x then Z.one else Z.zero)) - let to_bool = function - | Inc e when BISet.is_empty e -> None - | Exc (e,_) when BISet.is_empty e -> None - | Inc zero when BISet.is_singleton zero && BISet.choose zero = Z.zero -> Some false - | Inc xs when BISet.for_all ((<>) Z.zero) xs -> Some true - | Exc (xs,_) when BISet.exists ((=) Z.zero) xs -> Some true - | _ -> None - let to_int = function Inc x when BISet.is_singleton x -> Some (BISet.choose x) | _ -> None - - let to_excl_list = function Exc (x,r) when not (BISet.is_empty x) -> Some (BISet.elements x, (Option.get (R.minimal r), Option.get (R.maximal r))) | _ -> None - let of_excl_list ik xs = - let min_ik, max_ik = Size.range ik in - let exc = BISet.of_list @@ List.filter (value_in_range (min_ik, max_ik)) xs in - norm ik @@ Exc (exc, size ik) - let is_excl_list = BatOption.is_some % to_excl_list - let to_incl_list = function Inc s when not (BISet.is_empty s) -> Some (BISet.elements s) | _ -> None - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let c_lognot ik x = - if is_bot x - then x - else - match to_bool x with - | Some b -> of_bool ik (not b) - | None -> top_bool - - let c_logand = lift2 IntOps.BigIntOps.c_logand - let c_logor = lift2 IntOps.BigIntOps.c_logor - let maximal = function - | Inc xs when not (BISet.is_empty xs) -> Some (BISet.max_elt xs) - | Exc (excl,r) -> - let rec decrement_while_contained v = - if BISet.mem v excl - then decrement_while_contained (Z.pred v) - else v - in - let range_max = Exclusion.max_of_range r in - Some (decrement_while_contained range_max) - | _ (* bottom case *) -> None - - let minimal = function - | Inc xs when not (BISet.is_empty xs) -> Some (BISet.min_elt xs) - | Exc (excl,r) -> - let rec increment_while_contained v = - if BISet.mem v excl - then increment_while_contained (Z.succ v) - else v - in - let range_min = Exclusion.min_of_range r in - Some (increment_while_contained range_min) - | _ (* bottom case *) -> None - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let eq ik x y = - handle_bot x y (fun () -> - match x, y with - | Inc xs, Inc ys when BISet.is_singleton xs && BISet.is_singleton ys -> of_bool ik (Z.equal (BISet.choose xs) (BISet.choose ys)) - | _, _ -> - if is_bot (meet ik x y) then - (* If the meet is empty, there is no chance that concrete values are equal *) - of_bool ik false - else - top_bool) - - let ne ik x y = c_lognot ik (eq ik x y) - - let invariant_ikind e ik x = - match x with - | Inc ps -> - IntInvariant.of_incl_list e ik (BISet.elements ps) - | Exc (ns, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let nsi = IntInvariant.of_excl_list e ik (BISet.elements ns) in - Invariant.(ri && nsi) - - - let arbitrary ik = - let open QCheck.Iter in - let neg s = of_excl_list ik (BISet.elements s) in - let pos s = norm ik (Inc s) in - let shrink = function - | Exc (s, _) -> GobQCheck.shrink (BISet.arbitrary ()) s >|= neg (* S TODO: possibly shrink neg to pos *) - | Inc s -> GobQCheck.shrink (BISet.arbitrary ()) s >|= pos - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map neg (BISet.arbitrary ()); - 10, QCheck.map pos (BISet.arbitrary ()); - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = - let contains c m x = if Z.equal m Z.zero then Z.equal c x else Z.equal (Z.rem (Z.sub x c) m) Z.zero in - match a, b with - | Inc e, None -> bot_of ik - | Inc e, Some (c, m) -> Inc (BISet.filter (contains c m) e) - | _ -> a - - let refine_with_interval ik a b = a (* TODO: refine inclusion (exclusion?) set *) - - let refine_with_excl_list ik a b = - match b with - | Some (ls, _) -> meet ik a (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - - let refine_with_incl_list ik a b = - match a, b with - | Inc x, Some (ls) -> meet ik (Inc x) (Inc (BISet.of_list ls)) - | _ -> a - - let project ik p t = t -end - module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct include D From c4a3876e35c4d357f6abb4a91a1cc725326b0fe7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:02:32 +0300 Subject: [PATCH 600/689] Rename IntDomain0 -> DefExcDomain for split --- src/cdomain/value/cdomains/{intDomain0.ml => int/defExcDomain.ml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cdomain/value/cdomains/{intDomain0.ml => int/defExcDomain.ml} (100%) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/int/defExcDomain.ml similarity index 100% rename from src/cdomain/value/cdomains/intDomain0.ml rename to src/cdomain/value/cdomains/int/defExcDomain.ml From 108ab4410310978efe596c5a9bf922d17ab8b7e6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:02:59 +0300 Subject: [PATCH 601/689] Remove non-DefExcDomain parts --- .../value/cdomains/int/defExcDomain.ml | 1930 +---------------- 1 file changed, 1 insertion(+), 1929 deletions(-) diff --git a/src/cdomain/value/cdomains/int/defExcDomain.ml b/src/cdomain/value/cdomains/int/defExcDomain.ml index 1cda533c55..e747176631 100644 --- a/src/cdomain/value/cdomains/int/defExcDomain.ml +++ b/src/cdomain/value/cdomains/int/defExcDomain.ml @@ -1,1901 +1,5 @@ -open GobConfig -open GoblintCil -open Pretty -open PrecisionUtil +open IntDomain0 -module M = Messages - -let (%) = Batteries.(%) -let (|?) = Batteries.(|?) - -exception IncompatibleIKinds of string -exception Unknown -exception Error -exception ArithmeticOnIntegerBot of string - - - - -(** Define records that hold mutable variables representing different Configuration values. - * These values are used to keep track of whether or not the corresponding Config values are en-/disabled *) -type ana_int_config_values = { - mutable interval_threshold_widening : bool option; - mutable interval_narrow_by_meet : bool option; - mutable def_exc_widen_by_join : bool option; - mutable interval_threshold_widening_constants : string option; - mutable refinement : string option; -} - -let ana_int_config: ana_int_config_values = { - interval_threshold_widening = None; - interval_narrow_by_meet = None; - def_exc_widen_by_join = None; - interval_threshold_widening_constants = None; - refinement = None; -} - -let get_interval_threshold_widening () = - if ana_int_config.interval_threshold_widening = None then - ana_int_config.interval_threshold_widening <- Some (get_bool "ana.int.interval_threshold_widening"); - Option.get ana_int_config.interval_threshold_widening - -let get_interval_narrow_by_meet () = - if ana_int_config.interval_narrow_by_meet = None then - ana_int_config.interval_narrow_by_meet <- Some (get_bool "ana.int.interval_narrow_by_meet"); - Option.get ana_int_config.interval_narrow_by_meet - -let get_def_exc_widen_by_join () = - if ana_int_config.def_exc_widen_by_join = None then - ana_int_config.def_exc_widen_by_join <- Some (get_bool "ana.int.def_exc_widen_by_join"); - Option.get ana_int_config.def_exc_widen_by_join - -let get_interval_threshold_widening_constants () = - if ana_int_config.interval_threshold_widening_constants = None then - ana_int_config.interval_threshold_widening_constants <- Some (get_string "ana.int.interval_threshold_widening_constants"); - Option.get ana_int_config.interval_threshold_widening_constants - -let get_refinement () = - if ana_int_config.refinement = None then - ana_int_config.refinement <- Some (get_string "ana.int.refinement"); - Option.get ana_int_config.refinement - - - -(** Whether for a given ikind, we should compute with wrap-around arithmetic. - * Always for unsigned types, for signed types if 'sem.int.signed_overflow' is 'assume_wraparound' *) -let should_wrap ik = not (Cil.isSigned ik) || get_string "sem.int.signed_overflow" = "assume_wraparound" - -(** Whether for a given ikind, we should assume there are no overflows. - * Always false for unsigned types, true for signed types if 'sem.int.signed_overflow' is 'assume_none' *) -let should_ignore_overflow ik = Cil.isSigned ik && get_string "sem.int.signed_overflow" = "assume_none" - -let widening_thresholds = ResettableLazy.from_fun WideningThresholds.thresholds -let widening_thresholds_desc = ResettableLazy.from_fun (List.rev % WideningThresholds.thresholds) - -type overflow_info = { overflow: bool; underflow: bool;} - -let set_overflow_flag ~cast ~underflow ~overflow ik = - if !AnalysisState.executing_speculative_computations then - (* Do not produce warnings when the operations are not actually happening in code *) - () - else - let signed = Cil.isSigned ik in - if !AnalysisState.postsolving && signed && not cast then - AnalysisState.svcomp_may_overflow := true; - let sign = if signed then "Signed" else "Unsigned" in - match underflow, overflow with - | true, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190; CWE 191] "%s integer overflow and underflow" sign - | true, false -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 191] "%s integer underflow" sign - | false, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190] "%s integer overflow" sign - | false, false -> assert false - -let reset_lazy () = - ResettableLazy.reset widening_thresholds; - ResettableLazy.reset widening_thresholds_desc; - ana_int_config.interval_threshold_widening <- None; - ana_int_config.interval_narrow_by_meet <- None; - ana_int_config.def_exc_widen_by_join <- None; - ana_int_config.interval_threshold_widening_constants <- None; - ana_int_config.refinement <- None - -module type Arith = -sig - type t - val neg: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div: t -> t -> t - val rem: t -> t -> t - - val lt: t -> t -> t - val gt: t -> t -> t - val le: t -> t -> t - val ge: t -> t -> t - val eq: t -> t -> t - val ne: t -> t -> t - - val lognot: t -> t - val logand: t -> t -> t - val logor : t -> t -> t - val logxor: t -> t -> t - - val shift_left : t -> t -> t - val shift_right: t -> t -> t - - val c_lognot: t -> t - val c_logand: t -> t -> t - val c_logor : t -> t -> t - -end - -module type ArithIkind = -sig - type t - val neg: Cil.ikind -> t -> t - val add: Cil.ikind -> t -> t -> t - val sub: Cil.ikind -> t -> t -> t - val mul: Cil.ikind -> t -> t -> t - val div: Cil.ikind -> t -> t -> t - val rem: Cil.ikind -> t -> t -> t - - val lt: Cil.ikind -> t -> t -> t - val gt: Cil.ikind -> t -> t -> t - val le: Cil.ikind -> t -> t -> t - val ge: Cil.ikind -> t -> t -> t - val eq: Cil.ikind -> t -> t -> t - val ne: Cil.ikind -> t -> t -> t - - val lognot: Cil.ikind -> t -> t - val logand: Cil.ikind -> t -> t -> t - val logor : Cil.ikind -> t -> t -> t - val logxor: Cil.ikind -> t -> t -> t - - val shift_left : Cil.ikind -> t -> t -> t - val shift_right: Cil.ikind -> t -> t -> t - - val c_lognot: Cil.ikind -> t -> t - val c_logand: Cil.ikind -> t -> t -> t - val c_logor : Cil.ikind -> t -> t -> t - -end - -(* Shared functions between S and Z *) -module type B = -sig - include Lattice.S - type int_t - val bot_of: Cil.ikind -> t - val top_of: Cil.ikind -> t - val to_int: t -> int_t option - val equal_to: int_t -> t -> [`Eq | `Neq | `Top] - - val to_bool: t -> bool option - val to_excl_list: t -> (int_t list * (int64 * int64)) option - val of_excl_list: Cil.ikind -> int_t list -> t - val is_excl_list: t -> bool - - val to_incl_list: t -> int_t list option - - val maximal : t -> int_t option - val minimal : t -> int_t option - - val cast_to: ?suppress_ovwarn:bool -> ?torg:Cil.typ -> Cil.ikind -> t -> t -end - -(** Interface of IntDomain implementations that do not take ikinds for arithmetic operations yet. TODO: Should be ported to S in the future. *) -module type IkindUnawareS = -sig - include B - include Arith with type t := t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: int_t -> t - val of_bool: bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val arbitrary: unit -> t QCheck.arbitrary - val invariant: Cil.exp -> t -> Invariant.t -end - -(** Interface of IntDomain implementations taking an ikind for arithmetic operations *) -module type S = -sig - include B - include ArithIkind with type t:= t - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val neg : ?no_ov:bool -> Cil.ikind -> t -> t - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t - - val join: Cil.ikind -> t -> t -> t - val meet: Cil.ikind -> t -> t -> t - val narrow: Cil.ikind -> t -> t -> t - val widen: Cil.ikind -> t -> t -> t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val is_top_of: Cil.ikind -> t -> bool - val invariant_ikind : Cil.exp -> Cil.ikind -> t -> Invariant.t - - val refine_with_congruence: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_interval: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_excl_list: Cil.ikind -> t -> (int_t list * (int64 * int64)) option -> t - val refine_with_incl_list: Cil.ikind -> t -> int_t list option -> t - - val project: Cil.ikind -> int_precision -> t -> t - val arbitrary: Cil.ikind -> t QCheck.arbitrary -end - -module type SOverflow = -sig - - include S - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val neg : ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val of_int : Cil.ikind -> int_t -> t * overflow_info - - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t * overflow_info - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - - val shift_left : Cil.ikind -> t -> t -> t * overflow_info - - val shift_right : Cil.ikind -> t -> t -> t * overflow_info -end - -module type Y = -sig - (* include B *) - include B - include Arith with type t:= t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val is_top_of: Cil.ikind -> t -> bool - - val project: int_precision -> t -> t - val invariant: Cil.exp -> t -> Invariant.t -end - -module type Z = Y with type int_t = Z.t - - -module IntDomLifter (I : S) = -struct - open Cil - type int_t = I.int_t - type t = { v : I.t; ikind : CilType.Ikind.t } [@@deriving eq, ord, hash] - - let ikind {ikind; _} = ikind - - (* Helper functions *) - let check_ikinds x y = if x.ikind <> y.ikind then raise (IncompatibleIKinds (GobPretty.sprintf "ikinds %a and %a are incompatible. Values: %a and %a" CilType.Ikind.pretty x.ikind CilType.Ikind.pretty y.ikind I.pretty x.v I.pretty y.v)) - let lift op x = {x with v = op x.ikind x.v } - (* For logical operations the result is of type int *) - let lift_logical op x = {v = op x.ikind x.v; ikind = Cil.IInt} - let lift2 op x y = check_ikinds x y; {x with v = op x.ikind x.v y.v } - let lift2_cmp op x y = check_ikinds x y; {v = op x.ikind x.v y.v; ikind = Cil.IInt} - - let bot_of ikind = { v = I.bot_of ikind; ikind} - let bot () = failwith "bot () is not implemented for IntDomLifter." - let is_bot x = I.is_bot x.v - let top_of ikind = { v = I.top_of ikind; ikind} - let top () = failwith "top () is not implemented for IntDomLifter." - let is_top x = I.is_top x.v - - (* Leq does not check for ikind, because it is used in invariant with arguments of different type. - TODO: check ikinds here and fix invariant to work with right ikinds *) - let leq x y = I.leq x.v y.v - let join = lift2 I.join - let meet = lift2 I.meet - let widen = lift2 I.widen - let narrow = lift2 I.narrow - - let show x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - "⊤" - else - I.show x.v (* TODO add ikind to output *) - let pretty () x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - Pretty.text "⊤" - else - I.pretty () x.v (* TODO add ikind to output *) - let pretty_diff () (x, y) = I.pretty_diff () (x.v, y.v) (* TODO check ikinds, add them to output *) - let printXml o x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - BatPrintf.fprintf o "\n\n⊤\n\n\n" - else - I.printXml o x.v (* TODO add ikind to output *) - (* This is for debugging *) - let name () = "IntDomLifter(" ^ (I.name ()) ^ ")" - let to_yojson x = I.to_yojson x.v - let invariant e x = - let e' = Cilfacade.mkCast ~e ~newt:(TInt (x.ikind, [])) in - I.invariant_ikind e' x.ikind x.v - let tag x = I.tag x.v - let arbitrary ik = failwith @@ "Arbitrary not implement for " ^ (name ()) ^ "." - let to_int x = I.to_int x.v - let of_int ikind x = { v = I.of_int ikind x; ikind} - let equal_to i x = I.equal_to i x.v - let to_bool x = I.to_bool x.v - let of_bool ikind b = { v = I.of_bool ikind b; ikind} - let to_excl_list x = I.to_excl_list x.v - let of_excl_list ikind is = {v = I.of_excl_list ikind is; ikind} - let is_excl_list x = I.is_excl_list x.v - let to_incl_list x = I.to_incl_list x.v - let of_interval ?(suppress_ovwarn=false) ikind (lb,ub) = {v = I.of_interval ~suppress_ovwarn ikind (lb,ub); ikind} - let of_congruence ikind (c,m) = {v = I.of_congruence ikind (c,m); ikind} - let starting ?(suppress_ovwarn=false) ikind i = {v = I.starting ~suppress_ovwarn ikind i; ikind} - let ending ?(suppress_ovwarn=false) ikind i = {v = I.ending ~suppress_ovwarn ikind i; ikind} - let maximal x = I.maximal x.v - let minimal x = I.minimal x.v - - let neg = lift I.neg - let add = lift2 I.add - let sub = lift2 I.sub - let mul = lift2 I.mul - let div = lift2 I.div - let rem = lift2 I.rem - let lt = lift2_cmp I.lt - let gt = lift2_cmp I.gt - let le = lift2_cmp I.le - let ge = lift2_cmp I.ge - let eq = lift2_cmp I.eq - let ne = lift2_cmp I.ne - let lognot = lift I.lognot - let logand = lift2 I.logand - let logor = lift2 I.logor - let logxor = lift2 I.logxor - let shift_left x y = {x with v = I.shift_left x.ikind x.v y.v } (* TODO check ikinds*) - let shift_right x y = {x with v = I.shift_right x.ikind x.v y.v } (* TODO check ikinds*) - let c_lognot = lift_logical I.c_lognot - let c_logand = lift2 I.c_logand - let c_logor = lift2 I.c_logor - - let cast_to ?(suppress_ovwarn=false) ?torg ikind x = {v = I.cast_to ~suppress_ovwarn ~torg:(TInt(x.ikind,[])) ikind x.v; ikind} - - let is_top_of ik x = ik = x.ikind && I.is_top_of ik x.v - - let relift x = { v = I.relift x.v; ikind = x.ikind } - - let project p v = { v = I.project v.ikind p v.v; ikind = v.ikind } -end - -module type Ikind = -sig - val ikind: unit -> Cil.ikind -end - -module PtrDiffIkind : Ikind = -struct - let ikind = Cilfacade.ptrdiff_ikind -end - -module IntDomWithDefaultIkind (I: Y) (Ik: Ikind) : Y with type t = I.t and type int_t = I.int_t = -struct - include I - let top () = I.top_of (Ik.ikind ()) - let bot () = I.bot_of (Ik.ikind ()) -end - -module Size = struct (* size in bits as int, range as int64 *) - open Cil - let sign x = if Z.compare x Z.zero < 0 then `Signed else `Unsigned - - let top_typ = TInt (ILongLong, []) - let min_for x = intKindForValue x (sign x = `Unsigned) - let bit = function (* bits needed for representation *) - | IBool -> 1 - | ik -> bytesSizeOfInt ik * 8 - let is_int64_big_int x = Z.fits_int64 x - let card ik = (* cardinality *) - let b = bit ik in - Z.shift_left Z.one b - let bits ik = (* highest bits for neg/pos values *) - let s = bit ik in - if isSigned ik then s-1, s-1 else 0, s - let bits_i64 ik = BatTuple.Tuple2.mapn Int64.of_int (bits ik) - let range ik = - let a,b = bits ik in - let x = if isSigned ik then Z.neg (Z.shift_left Z.one a) (* -2^a *) else Z.zero in - let y = Z.pred (Z.shift_left Z.one b) in (* 2^b - 1 *) - x,y - - let is_cast_injective ~from_type ~to_type = - let (from_min, from_max) = range (Cilfacade.get_ikind from_type) in - let (to_min, to_max) = range (Cilfacade.get_ikind to_type) in - if M.tracing then M.trace "int" "is_cast_injective %a (%a, %a) -> %a (%a, %a)" CilType.Typ.pretty from_type GobZ.pretty from_min GobZ.pretty from_max CilType.Typ.pretty to_type GobZ.pretty to_min GobZ.pretty to_max; - Z.compare to_min from_min <= 0 && Z.compare from_max to_max <= 0 - - let cast t x = (* TODO: overflow is implementation-dependent! *) - if t = IBool then - (* C11 6.3.1.2 Boolean type *) - if Z.equal x Z.zero then Z.zero else Z.one - else - let a,b = range t in - let c = card t in - let y = Z.erem x c in - let y = if Z.gt y b then Z.sub y c - else if Z.lt y a then Z.add y c - else y - in - if M.tracing then M.tracel "cast" "Cast %a to range [%a, %a] (%a) = %a (%s in int64)" GobZ.pretty x GobZ.pretty a GobZ.pretty b GobZ.pretty c GobZ.pretty y (if is_int64_big_int y then "fits" else "does not fit"); - y - - let min_range_sign_agnostic x = - let size ik = - let a,b = bits_i64 ik in - Int64.neg a,b - in - if sign x = `Signed then - size (min_for x) - else - let a, b = size (min_for x) in - if b <= 64L then - let upper_bound_less = Int64.sub b 1L in - let max_one_less = Z.(pred @@ shift_left Z.one (Int64.to_int upper_bound_less)) in - if x <= max_one_less then - a, upper_bound_less - else - a,b - else - a, b - - (* From the number of bits used to represent a positive value, determines the maximal representable value *) - let max_from_bit_range pos_bits = Z.(pred @@ shift_left Z.one (to_int (Z.of_int64 pos_bits))) - - (* From the number of bits used to represent a non-positive value, determines the minimal representable value *) - let min_from_bit_range neg_bits = Z.(if neg_bits = 0L then Z.zero else neg @@ shift_left Z.one (to_int (neg (Z.of_int64 neg_bits)))) - -end - - -module StdTop (B: sig type t val top_of: Cil.ikind -> t end) = struct - open B - (* these should be overwritten for better precision if possible: *) - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ik x = top_of ik - let ending ?(suppress_ovwarn=false) ik x = top_of ik - let maximal x = None - let minimal x = None -end - -module Std (B: sig - type t - val name: unit -> string - val top_of: Cil.ikind -> t - val bot_of: Cil.ikind -> t - val show: t -> string - val equal: t -> t -> bool - end) = struct - include Printable.StdLeaf - let name = B.name (* overwrite the one from Printable.Std *) - open B - let is_top x = failwith "is_top not implemented for IntDomain.Std" - let is_bot x = B.equal x (bot_of Cil.IInt) (* Here we assume that the representation of bottom is independent of the ikind - This may be true for intdomain implementations, but not e.g. for IntDomLifter. *) - let is_top_of ik x = B.equal x (top_of ik) - - (* all output is based on B.show *) - include Printable.SimpleShow ( - struct - type nonrec t = t - let show = show - end - ) - let pretty_diff () (x,y) = dprintf "%s: %a instead of %a" (name ()) pretty x pretty y - - include StdTop (B) -end - -(* Textbook interval arithmetic, without any overflow handling etc. *) -module IntervalArith (Ints_t : IntOps.IntOps) = struct - let min4 a b c d = Ints_t.min (Ints_t.min a b) (Ints_t.min c d) - let max4 a b c d = Ints_t.max (Ints_t.max a b) (Ints_t.max c d) - - let mul (x1, x2) (y1, y2) = - let x1y1 = (Ints_t.mul x1 y1) in - let x1y2 = (Ints_t.mul x1 y2) in - let x2y1 = (Ints_t.mul x2 y1) in - let x2y2 = (Ints_t.mul x2 y2) in - (min4 x1y1 x1y2 x2y1 x2y2, max4 x1y1 x1y2 x2y1 x2y2) - - let shift_left (x1,x2) (y1,y2) = - let y1p = Ints_t.shift_left Ints_t.one y1 in - let y2p = Ints_t.shift_left Ints_t.one y2 in - mul (x1, x2) (y1p, y2p) - - let div (x1, x2) (y1, y2) = - let x1y1n = (Ints_t.div x1 y1) in - let x1y2n = (Ints_t.div x1 y2) in - let x2y1n = (Ints_t.div x2 y1) in - let x2y2n = (Ints_t.div x2 y2) in - let x1y1p = (Ints_t.div x1 y1) in - let x1y2p = (Ints_t.div x1 y2) in - let x2y1p = (Ints_t.div x2 y1) in - let x2y2p = (Ints_t.div x2 y2) in - (min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p) - - let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2) - let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1) - - let neg (x1, x2) = (Ints_t.neg x2, Ints_t.neg x1) - - let one = (Ints_t.one, Ints_t.one) - let zero = (Ints_t.zero, Ints_t.zero) - let top_bool = (Ints_t.zero, Ints_t.one) - - let to_int (x1, x2) = - if Ints_t.equal x1 x2 then Some x1 else None - - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let max_ik' = Ints_t.to_bigint max_ik in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let min_ik' = Ints_t.to_bigint min_ik in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let is_upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - List.exists (Z.equal u) ts - let is_lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - List.exists (Z.equal l) ts -end - -module IntInvariant = -struct - let of_int e ik x = - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.none - - let of_incl_list e ik ps = - match ps with - | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> - assert (List.mem Z.zero ps); - assert (List.mem Z.one ps); - Invariant.none - | [_] when get_bool "witness.invariant.exact" -> - Invariant.none - | _ :: _ :: _ - | [_] | [] -> - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) (Invariant.bot ()) ps - - let of_interval_opt e ik = function - | (Some x1, Some x2) when Z.equal x1 x2 -> - of_int e ik x1 - | x1_opt, x2_opt -> - let (min_ik, max_ik) = Size.range ik in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = - match x1_opt, inexact_type_bounds with - | Some x1, false when Z.equal min_ik x1 -> Invariant.none - | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) - | None, _ -> Invariant.none - in - let i2 = - match x2_opt, inexact_type_bounds with - | Some x2, false when Z.equal x2 max_ik -> Invariant.none - | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) - | None, _ -> Invariant.none - in - Invariant.(i1 && i2) - - let of_interval e ik (x1, x2) = - of_interval_opt e ik (Some x1, Some x2) - - let of_excl_list e ik ns = - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) (Invariant.top ()) ns -end - -module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = -struct - let name () = "intervals" - type int_t = Ints_t.t - type t = (Ints_t.t * Ints_t.t) option [@@deriving eq, ord, hash] - module IArith = IntervalArith (Ints_t) - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - let top_of ik = Some (range ik) - let bot () = None - let bot_of ik = bot () (* TODO: improve *) - - let show = function None -> "bottom" | Some (x,y) -> "["^Ints_t.to_string x^","^Ints_t.to_string y^"]" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) -> - if a = b && b = i then `Eq else if Ints_t.compare a i <= 0 && Ints_t.compare i b <=0 then `Top else `Neq - - let norm ?(suppress_ovwarn=false) ?(cast=false) ik : (t -> t * overflow_info) = function None -> (None, {underflow=false; overflow=false}) | Some (x,y) -> - if Ints_t.compare x y > 0 then - (None,{underflow=false; overflow=false}) - else ( - let (min_ik, max_ik) = range ik in - let underflow = Ints_t.compare min_ik x > 0 in - let overflow = Ints_t.compare max_ik y < 0 in - let ov_info = { underflow = underflow && not suppress_ovwarn; overflow = overflow && not suppress_ovwarn } in - let v = - if underflow || overflow then - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (Ints_t.sub max_ik min_ik) in - let resdiff = Ints_t.abs (Ints_t.sub y x) in - if Ints_t.compare resdiff diff > 0 then - top_of ik - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if Ints_t.compare l u <= 0 then - Some (l, u) - else - (* Interval that wraps around (begins to the right of its end). We can not represent such intervals *) - top_of ik - else if not cast && should_ignore_overflow ik then - let tl, tu = BatOption.get @@ top_of ik in - Some (Ints_t.max tl x, Ints_t.min tu y) - else - top_of ik - else - Some (x,y) - in - (v, ov_info) - ) - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0 - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst - - let meet ik (x:t) y = - match x, y with - | None, z | z, None -> None - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.max x1 y1, Ints_t.min x2 y2) |> fst - - (* TODO: change to_int signature so it returns a big_int *) - let to_int x = Option.bind x (IArith.to_int) - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm ~suppress_ovwarn ik @@ Some (x,y) - let of_int ik (x: int_t) = of_interval ik (x,x) - let zero = Some IArith.zero - let one = Some IArith.one - let top_bool = Some IArith.top_bool - - let of_bool _ik = function true -> one | false -> zero - let to_bool (a: t) = match a with - | None -> None - | Some (l, u) when Ints_t.compare l Ints_t.zero = 0 && Ints_t.compare u Ints_t.zero = 0 -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (fst (range ik), n) - - (* TODO: change signature of maximal, minimal to return big_int*) - let maximal = function None -> None | Some (x,y) -> Some y - let minimal = function None -> None | Some (x,y) -> Some x - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - - let widen ik x y = - match x, y with - | None, z | z, None -> z - | Some (l0,u0), Some (l1,u1) -> - let (min_ik, max_ik) = range ik in - let threshold = get_interval_threshold_widening () in - let l2 = - if Ints_t.compare l0 l1 = 0 then l0 - else if threshold then IArith.lower_threshold l1 min_ik - else min_ik - in - let u2 = - if Ints_t.compare u0 u1 = 0 then u0 - else if threshold then IArith.upper_threshold u1 max_ik - else max_ik - in - norm ik @@ Some (l2,u2) |> fst - let widen ik x y = - let r = widen ik x y in - if M.tracing && not (equal x y) then M.tracel "int" "interval widen %a %a -> %a" pretty x pretty y pretty r; - assert (leq x y); (* TODO: remove for performance reasons? *) - r - - let narrow ik x y = - match x, y with - | _,None | None, _ -> None - | Some (x1,x2), Some (y1,y2) -> - let threshold = get_interval_threshold_widening () in - let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in - norm ik @@ Some (lr,ur) |> fst - - - let narrow ik x y = - if get_interval_narrow_by_meet () then - meet ik x y - else - narrow ik x y - - let log f ~annihilator ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, _ when x = annihilator -> of_bool ik annihilator - | _, Some y when y = annihilator -> of_bool ik annihilator - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) ~annihilator:true - let c_logand = log (&&) ~annihilator:false - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let bit f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - let bitcomp f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{underflow=false; overflow=false})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let logxor = bit (fun _ik -> Ints_t.logxor) - - let logand ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (Ints_t.logand x y) |> fst with Division_by_zero -> top_of ik) - | _, Some y when Ints_t.equal y Ints_t.zero -> of_int ik Ints_t.zero |> fst - | _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst - | _ -> top_of ik - - let logor = bit (fun _ik -> Ints_t.logor) - - let bit1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_int i1 with - | Some x -> of_int ik (f ik x) |> fst - | _ -> top_of ik - - let lognot = bit1 (fun _ik -> Ints_t.lognot) - let shift_right = bitcomp (fun _ik x y -> Ints_t.shift_right x (Ints_t.to_int y)) - - let neg ?no_ov ik = function None -> (None,{underflow=false; overflow=false}) | Some x -> norm ik @@ Some (IArith.neg x) - - let binary_op_with_norm ?no_ov op ik x y = match x, y with - | None, None -> (None, {overflow=false; underflow= false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some x, Some y -> norm ik @@ Some (op x y) - - let add ?no_ov = binary_op_with_norm IArith.add - let mul ?no_ov = binary_op_with_norm IArith.mul - let sub ?no_ov = binary_op_with_norm IArith.sub - - let shift_left ik a b = - match is_bot a, is_bot b with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show a) (show b))) - | _ -> - match a, minimal b, maximal b with - | Some a, Some bl, Some bu when (Ints_t.compare bl Ints_t.zero >= 0) -> - (try - let r = IArith.shift_left a (Ints_t.to_int bl, Ints_t.to_int bu) in - norm ik @@ Some r - with Z.Overflow -> (top_of ik,{underflow=false; overflow=true})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let rem ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (xl, xu), Some (yl, yu) -> - if is_top_of ik x && is_top_of ik y then - (* This is needed to preserve soundness also on things bigger than int32 e.g. *) - (* x: 3803957176L -> T in Interval32 *) - (* y: 4209861404L -> T in Interval32 *) - (* x % y: 3803957176L -> T in Interval32 *) - (* T in Interval32 is [-2147483648,2147483647] *) - (* the code below computes [-2147483647,2147483647] for this though which is unsound *) - top_of ik - else - (* If we have definite values, Ints_t.rem will give a definite result. - * Otherwise we meet with a [range] the result can be in. - * This range is [0, min xu b] if x is positive, and [max xl -b, min xu b] if x can be negative. - * The precise bound b is one smaller than the maximum bound. Negative y give the same result as positive. *) - let pos x = if Ints_t.compare x Ints_t.zero < 0 then Ints_t.neg x else x in - let b = Ints_t.sub (Ints_t.max (pos yl) (pos yu)) Ints_t.one in - let range = if Ints_t.compare xl Ints_t.zero>= 0 then Some (Ints_t.zero, Ints_t.min xu b) else Some (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit (fun _ik -> Ints_t.rem) ik x y) range - - let rec div ?no_ov ik x y = - match x, y with - | None, None -> (bot (),{underflow=false; overflow=false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | (Some (x1,x2) as x), (Some (y1,y2) as y) -> - begin - let is_zero v = Ints_t.compare v Ints_t.zero = 0 in - match y1, y2 with - | l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false}) (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2)) - | _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one))) - | _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false}) - | _ -> binary_op_with_norm IArith.div ik x y - end - - let ne ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik true - else if Ints_t.compare x2 y1 <= 0 && Ints_t.compare y2 x1 <= 0 then - of_bool ik false - else top_bool - - let eq ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 && Ints_t.compare x2 y1 <= 0 then - of_bool ik true - else if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik false - else top_bool - - let ge ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 then of_bool ik true - else if Ints_t.compare x2 y1 < 0 then of_bool ik false - else top_bool - - let le ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 <= 0 then of_bool ik true - else if Ints_t.compare y2 x1 < 0 then of_bool ik false - else top_bool - - let gt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 then of_bool ik true - else if Ints_t.compare x2 y1 <= 0 then of_bool ik false - else top_bool - - let lt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 < 0 then of_bool ik true - else if Ints_t.compare y2 x1 <= 0 then of_bool ik false - else top_bool - - let invariant_ikind e ik = function - | Some (x1, x2) -> - let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in - IntInvariant.of_interval e ik (x1', x2') - | None -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let shrink = function - | Some (l, u) -> (return None) <+> (GobQCheck.shrink pair_arb (l, u) >|= of_interval ik >|= fst) - | None -> empty - in - QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) (fun x -> of_interval ik x |> fst ) pair_arb) - - let modulo n k = - let result = Ints_t.rem n k in - if Ints_t.compare result Ints_t.zero >= 0 then result - else Ints_t.add result k - - let refine_with_congruence ik (intv : t) (cong : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if Ints_t.equal m Ints_t.zero && (Ints_t.compare c x < 0 || Ints_t.compare c y > 0) then None - else if Ints_t.equal m Ints_t.zero then - Some (c, c) - else - let (min_ik, max_ik) = range ik in - let rcx = - if Ints_t.equal x min_ik then x else - Ints_t.add x (modulo (Ints_t.sub c x) (Ints_t.abs m)) in - let lcy = - if Ints_t.equal y max_ik then y else - Ints_t.sub y (modulo (Ints_t.sub y c) (Ints_t.abs m)) in - if Ints_t.compare rcx lcy > 0 then None - else if Ints_t.equal rcx lcy then norm ik @@ Some (rcx, rcx) |> fst - else norm ik @@ Some (rcx, lcy) |> fst - | _ -> None - - let refine_with_congruence ik x y = - let refn = refine_with_congruence ik x y in - if M.tracing then M.trace "refine" "int_refine_with_congruence %a %a -> %a" pretty x pretty y pretty refn; - refn - - let refine_with_interval ik a b = meet ik a b - - let refine_with_excl_list ik (intv : t) (excl : (int_t list * (int64 * int64)) option) : t = - match intv, excl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls, (rl, rh)) -> - let rec shrink op b = - let new_b = (op b (Ints_t.of_int(Bool.to_int(BatList.mem_cmp Ints_t.compare b ls)))) in - if not (Ints_t.equal b new_b) then shrink op new_b else new_b - in - let (min_ik, max_ik) = range ik in - let l' = if Ints_t.equal l min_ik then l else shrink Ints_t.add l in - let u' = if Ints_t.equal u max_ik then u else shrink Ints_t.sub u in - let intv' = norm ik @@ Some (l', u') |> fst in - let range = norm ~suppress_ovwarn:true ik (Some (Ints_t.of_bigint (Size.min_from_bit_range rl), Ints_t.of_bigint (Size.max_from_bit_range rh))) |> fst in - meet ik intv' range - - let refine_with_incl_list ik (intv: t) (incl : (int_t list) option) : t = - match intv, incl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls) -> - let rec min m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> min (Some x) xs | Some m -> if Ints_t.compare m x < 0 then min (Some m) xs else min (Some x) xs in - let rec max m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> max (Some x) xs | Some m -> if Ints_t.compare m x > 0 then max (Some m) xs else max (Some x) xs in - match min None ls, max None ls with - | Some m1, Some m2 -> refine_with_interval ik (Some(l, u)) (Some (m1, m2)) - | _, _-> intv - - let project ik p t = t -end - -(** IntervalSetFunctor that is not just disjunctive completion of intervals, but attempts to be precise for wraparound arithmetic for unsigned types *) -module IntervalSetFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) list = -struct - - module Interval = IntervalFunctor (Ints_t) - module IArith = IntervalArith (Ints_t) - - - let name () = "interval_sets" - - type int_t = Ints_t.t - - let (>.) a b = Ints_t.compare a b > 0 - let (=.) a b = Ints_t.compare a b = 0 - let (<.) a b = Ints_t.compare a b < 0 - let (>=.) a b = Ints_t.compare a b >= 0 - let (<=.) a b = Ints_t.compare a b <= 0 - let (+.) a b = Ints_t.add a b - let (-.) a b = Ints_t.sub a b - - (* - Each domain's element is guaranteed to be in canonical form. That is, each interval contained - inside the set does not overlap with each other and they are not adjacent. - *) - type t = (Ints_t.t * Ints_t.t) list [@@deriving eq, hash, ord] - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - - let top_of ik = [range ik] - - let bot () = [] - - let bot_of ik = bot () - - let show (x: t) = - let show_interval i = Printf.sprintf "[%s, %s]" (Ints_t.to_string (fst i)) (Ints_t.to_string (snd i)) in - List.fold_left (fun acc i -> (show_interval i) :: acc) [] x |> List.rev |> String.concat ", " |> Printf.sprintf "[%s]" - - (* New type definition for the sweeping line algorithm used for implementing join/meet functions. *) - type event = Enter of Ints_t.t | Exit of Ints_t.t - - let unbox_event = function Enter x -> x | Exit x -> x - - let cmp_events x y = - (* Deliberately comparing ints first => Cannot be derived *) - let res = Ints_t.compare (unbox_event x) (unbox_event y) in - if res <> 0 then res - else - begin - match (x, y) with - | (Enter _, Exit _) -> -1 - | (Exit _, Enter _) -> 1 - | (_, _) -> 0 - end - - let interval_set_to_events (xs: t) = - List.concat_map (fun (a, b) -> [Enter a; Exit b]) xs - - let two_interval_sets_to_events (xs: t) (ys: t) = - let xs = interval_set_to_events xs in - let ys = interval_set_to_events ys in - List.merge cmp_events xs ys - - (* Using the sweeping line algorithm, combined_event_list returns a new event list representing the intervals in which at least n intervals in xs overlap - This function is used for both join and meet operations with different parameter n: 1 for join, 2 for meet *) - let combined_event_list lattice_op (xs:event list) = - let l = match lattice_op with `Join -> 1 | `Meet -> 2 in - let aux (interval_count, acc) = function - | Enter x -> (interval_count + 1, if (interval_count + 1) >= l && interval_count < l then (Enter x)::acc else acc) - | Exit x -> (interval_count - 1, if interval_count >= l && (interval_count - 1) < l then (Exit x)::acc else acc) - in - List.fold_left aux (0, []) xs |> snd |> List.rev - - let rec events_to_intervals = function - | [] -> [] - | (Enter x)::(Exit y)::xs -> (x, y)::(events_to_intervals xs) - | _ -> failwith "Invalid events list" - - let remove_empty_gaps (xs: t) = - let aux acc (l, r) = match acc with - | ((a, b)::acc') when (b +. Ints_t.one) >=. l -> (a, r)::acc' - | _ -> (l, r)::acc - in - List.fold_left aux [] xs |> List.rev - - let canonize (xs: t) = - interval_set_to_events xs |> - List.sort cmp_events |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let unop (x: t) op = match x with - | [] -> [] - | _ -> canonize @@ List.concat_map op x - - let binop (x: t) (y: t) op : t = match x, y with - | [], _ -> [] - | _, [] -> [] - | _, _ -> canonize @@ List.concat_map op (BatList.cartesian_product x y) - - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let minimal = function - | [] -> None - | (x, _)::_ -> Some x - - let maximal = function - | [] -> None - | xs -> Some (BatList.last xs |> snd) - - let equal_to_interval i (a, b) = - if a =. b && b =. i then - `Eq - else if a <=. i && i <=. b then - `Top - else - `Neq - - let equal_to i xs = match List.map (equal_to_interval i) xs with - | [] -> failwith "unsupported: equal_to with bottom" - | [`Eq] -> `Eq - | ys when List.for_all ((=) `Neq) ys -> `Neq - | _ -> `Top - - let norm_interval ?(suppress_ovwarn=false) ?(cast=false) ik (x,y) : t*overflow_info = - if x >. y then - ([],{underflow=false; overflow=false}) - else - let (min_ik, max_ik) = range ik in - let underflow = min_ik >. x in - let overflow = max_ik <. y in - let v = if underflow || overflow then - begin - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (max_ik -. min_ik) in - let resdiff = Ints_t.abs (y -. x) in - if resdiff >. diff then - [range ik] - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if l <=. u then - [(l, u)] - else - (* Interval that wraps around (begins to the right of its end). We CAN represent such intervals *) - [(min_ik, u); (l, max_ik)] - else if not cast && should_ignore_overflow ik then - [Ints_t.max min_ik x, Ints_t.min max_ik y] - else - [range ik] - end - else - [(x,y)] - in - if suppress_ovwarn then (v, {underflow=false; overflow=false}) else (v, {underflow; overflow}) - - let norm_intvs ?(suppress_ovwarn=false) ?(cast=false) (ik:ikind) (xs: t) : t*overflow_info = - let res = List.map (norm_interval ~suppress_ovwarn ~cast ik) xs in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let binary_op_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> [op x y]) (BatList.cartesian_product x y) - - let binary_op_with_ovc (x: t) (y: t) op : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> - let res = List.map op (BatList.cartesian_product x y) in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let unary_op_with_norm op (ik:ikind) (x: t) = match x with - | [] -> ([],{overflow=false; underflow=false}) - | _ -> norm_intvs ik @@ List.concat_map (fun x -> [op x]) x - - let rec leq (xs: t) (ys: t) = - let leq_interval (al, au) (bl, bu) = al >=. bl && au <=. bu in - match xs, ys with - | [], _ -> true - | _, [] -> false - | (xl,xr)::xs', (yl,yr)::ys' -> - if leq_interval (xl,xr) (yl,yr) then - leq xs' ys - else if xr <. yl then - false - else - leq xs ys' - - let join ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let meet ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Meet |> - events_to_intervals - - let to_int = function - | [x] -> IArith.to_int x - | _ -> None - - let zero = [IArith.zero] - let one = [IArith.one] - let top_bool = [IArith.top_bool] - - let not_bool (x:t) = - let is_false x = equal x zero in - let is_true x = equal x one in - if is_true x then zero else if is_false x then one else top_bool - - let to_bool = function - | [(l,u)] when l =. Ints_t.zero && u =. Ints_t.zero -> Some false - | x -> if leq zero x then None else Some true - - let of_bool _ = function true -> one | false -> zero - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm_interval ~suppress_ovwarn ~cast:false ik (x,y) - - let of_int ik (x: int_t) = of_interval ik (x, x) - - let lt ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <. min_y then - of_bool ik true - else if min_x >=. max_y then - of_bool ik false - else - top_bool - - let le ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <=. min_y then - of_bool ik true - else if min_x >. max_y then - of_bool ik false - else - top_bool - - let gt ik x y = not_bool @@ le ik x y - - let ge ik x y = not_bool @@ lt ik x y - - let eq ik x y = match x, y with - | (a, b)::[], (c, d)::[] when a =. b && c =. d && a =. c -> - one - | _ -> - if is_bot (meet ik x y) then - zero - else - top_bool - - let ne ik x y = not_bool @@ eq ik x y - let interval_to_int i = Interval.to_int (Some i) - let interval_to_bool i = Interval.to_bool (Some i) - - let log f ik (i1, i2) = - match (interval_to_bool i1, interval_to_bool i2) with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - - let bit f ik (i1, i2) = - match (interval_to_int i1), (interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - - let bitcomp f ik (i1, i2) = - match (interval_to_int i1, interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{overflow=false; underflow=false})) - | _, _ -> (top_of ik,{overflow=false; underflow=false}) - - let logand ik x y = - let interval_logand = bit Ints_t.logand ik in - binop x y interval_logand - - let logor ik x y = - let interval_logor = bit Ints_t.logor ik in - binop x y interval_logor - - let logxor ik x y = - let interval_logxor = bit Ints_t.logxor ik in - binop x y interval_logxor - - let lognot ik x = - let interval_lognot i = - match interval_to_int i with - | Some x -> of_int ik (Ints_t.lognot x) |> fst - | _ -> top_of ik - in - unop x interval_lognot - - let shift_left ik x y = - let interval_shiftleft = bitcomp (fun x y -> Ints_t.shift_left x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftleft - - let shift_right ik x y = - let interval_shiftright = bitcomp (fun x y -> Ints_t.shift_right x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftright - - let c_lognot ik x = - let log1 f ik i1 = - match interval_to_bool i1 with - | Some x -> of_bool ik (f x) - | _ -> top_of ik - in - let interval_lognot = log1 not ik in - unop x interval_lognot - - let c_logand ik x y = - let interval_logand = log (&&) ik in - binop x y interval_logand - - let c_logor ik x y = - let interval_logor = log (||) ik in - binop x y interval_logor - - let add ?no_ov = binary_op_with_norm IArith.add - let sub ?no_ov = binary_op_with_norm IArith.sub - let mul ?no_ov = binary_op_with_norm IArith.mul - let neg ?no_ov = unary_op_with_norm IArith.neg - - let div ?no_ov ik x y = - let rec interval_div x (y1, y2) = begin - let top_of ik = top_of ik |> List.hd in - let is_zero v = v =. Ints_t.zero in - match y1, y2 with - | l, u when is_zero l && is_zero u -> top_of ik (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> interval_div x (Ints_t.one,y2) - | _, u when is_zero u -> interval_div x (y1, Ints_t.(neg one)) - | _ when leq (of_int ik (Ints_t.zero) |> fst) ([(y1,y2)]) -> top_of ik - | _ -> IArith.div x (y1, y2) - end - in binary_op_with_norm interval_div ik x y - - let rem ik x y = - let interval_rem (x, y) = - if Interval.is_top_of ik (Some x) && Interval.is_top_of ik (Some y) then - top_of ik - else - let (xl, xu) = x in let (yl, yu) = y in - let pos x = if x <. Ints_t.zero then Ints_t.neg x else x in - let b = (Ints_t.max (pos yl) (pos yu)) -. Ints_t.one in - let range = if xl >=. Ints_t.zero then (Ints_t.zero, Ints_t.min xu b) else (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit Ints_t.rem ik (x, y)) [range] - in - binop x y interval_rem - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik x = norm_intvs ~cast:true ik x - - (* - narrows down the extremeties of xs if they are equal to boundary values of the ikind with (possibly) narrower values from ys - *) - let narrow ik xs ys = match xs ,ys with - | [], _ -> [] | _ ,[] -> xs - | _, _ -> - let min_xs = minimal xs |> Option.get in - let max_xs = maximal xs |> Option.get in - let min_ys = minimal ys |> Option.get in - let max_ys = maximal ys |> Option.get in - let min_range,max_range = range ik in - let threshold = get_interval_threshold_widening () in - let min = if min_xs =. min_range || threshold && min_ys >. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in - let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in - xs - |> (function (_, y)::z -> (min, y)::z | _ -> []) - |> List.rev - |> (function (x, _)::z -> (x, max)::z | _ -> []) - |> List.rev - - (* - 1. partitions the intervals of xs by assigning each of them to the an interval in ys that includes it. - and joins all intervals in xs assigned to the same interval in ys as one interval. - 2. checks for every pair of adjacent pairs whether the pairs did approach (if you compare the intervals from xs and ys) and merges them if it is the case. - 3. checks whether partitions at the extremeties are approaching infinity (and expands them to infinity. in that case) - - The expansion (between a pair of adjacent partitions or at extremeties ) stops at a threshold. - *) - let widen ik xs ys = - let (min_ik,max_ik) = range ik in - let threshold = get_bool "ana.int.interval_threshold_widening" in - let upper_threshold (_,u) = IArith.upper_threshold u max_ik in - let lower_threshold (l,_) = IArith.lower_threshold l min_ik in - (*obtain partitioning of xs intervals according to the ys interval that includes them*) - let rec interval_sets_to_partitions (ik: ikind) (acc : (int_t * int_t) option) (xs: t) (ys: t)= - match xs,ys with - | _, [] -> [] - | [], (y::ys) -> (acc,y):: interval_sets_to_partitions ik None [] ys - | (x::xs), (y::ys) when Interval.leq (Some x) (Some y) -> interval_sets_to_partitions ik (Interval.join ik acc (Some x)) xs (y::ys) - | (x::xs), (y::ys) -> (acc,y) :: interval_sets_to_partitions ik None (x::xs) ys - in - let interval_sets_to_partitions ik xs ys = interval_sets_to_partitions ik None xs ys in - (*merge a pair of adjacent partitions*) - let merge_pair ik (a,b) (c,d) = - let new_a = function - | None -> Some (upper_threshold b, upper_threshold b) - | Some (ax,ay) -> Some (ax, upper_threshold b) - in - let new_c = function - | None -> Some (lower_threshold d, lower_threshold d) - | Some (cx,cy) -> Some (lower_threshold d, cy) - in - if threshold && (lower_threshold d +. Ints_t.one) >. (upper_threshold b) then - [(new_a a,(fst b, upper_threshold b)); (new_c c, (lower_threshold d, snd d))] - else - [(Interval.join ik a c, (Interval.join ik (Some b) (Some d) |> Option.get))] - in - let partitions_are_approaching part_left part_right = match part_left, part_right with - | (Some (_, left_x), (_, left_y)), (Some (right_x, _), (right_y, _)) -> (right_x -. left_x) >. (right_y -. left_y) - | _,_ -> false - in - (*merge all approaching pairs of adjacent partitions*) - let rec merge_list ik = function - | [] -> [] - | x::y::xs when partitions_are_approaching x y -> merge_list ik ((merge_pair ik x y) @ xs) - | x::xs -> x :: merge_list ik xs - in - (*expands left extremity*) - let widen_left = function - | [] -> [] - | (None,(lb,rb))::ts -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (None, (lt,rb))::ts - | (Some (la,ra), (lb,rb))::ts when lb <. la -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (Some (la,ra),(lt,rb))::ts - | x -> x - in - (*expands right extremity*) - let widen_right x = - let map_rightmost = function - | [] -> [] - | (None,(lb,rb))::ts -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (None, (lb,ut))::ts - | (Some (la,ra), (lb,rb))::ts when ra <. rb -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (Some (la,ra),(lb,ut))::ts - | x -> x - in - List.rev x |> map_rightmost |> List.rev - in - interval_sets_to_partitions ik xs ys |> merge_list ik |> widen_left |> widen_right |> List.map snd - - let starting ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (fst (range ik), n) - - let invariant_ikind e ik xs = - List.map (fun x -> Interval.invariant_ikind e ik (Some x)) xs |> - let open Invariant in List.fold_left (||) (bot ()) - - let modulo n k = - let result = Ints_t.rem n k in - if result >=. Ints_t.zero then result - else result +. k - - let refine_with_congruence ik (intvs: t) (cong: (int_t * int_t ) option): t = - let refine_with_congruence_interval ik (cong : (int_t * int_t ) option) (intv : (int_t * int_t ) option): t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =. Ints_t.zero && (c <. x || c >. y) then [] - else if m =. Ints_t.zero then - [(c, c)] - else - let (min_ik, max_ik) = range ik in - let rcx = - if x =. min_ik then x else - x +. (modulo (c -. x) (Ints_t.abs m)) in - let lcy = - if y =. max_ik then y else - y -. (modulo (y -. c) (Ints_t.abs m)) in - if rcx >. lcy then [] - else if rcx =. lcy then norm_interval ik (rcx, rcx) |> fst - else norm_interval ik (rcx, lcy) |> fst - | _ -> [] - in - List.concat_map (fun x -> refine_with_congruence_interval ik cong (Some x)) intvs - - let refine_with_interval ik xs = function None -> [] | Some (a,b) -> meet ik xs [(a,b)] - - let refine_with_incl_list ik intvs = function - | None -> intvs - | Some xs -> meet ik intvs (List.map (fun x -> (x,x)) xs) - - let excl_range_to_intervalset (ik: ikind) ((min, max): int_t * int_t) (excl: int_t): t = - let intv1 = (min, excl -. Ints_t.one) in - let intv2 = (excl +. Ints_t.one, max) in - norm_intvs ik ~suppress_ovwarn:true [intv1 ; intv2] |> fst - - let of_excl_list ik (excls: int_t list) = - let excl_list = List.map (excl_range_to_intervalset ik (range ik)) excls in - let res = List.fold_left (meet ik) (top_of ik) excl_list in - res - - let refine_with_excl_list ik (intv : t) = function - | None -> intv - | Some (xs, range) -> - let excl_to_intervalset (ik: ikind) ((rl, rh): (int64 * int64)) (excl: int_t): t = - excl_range_to_intervalset ik (Ints_t.of_bigint (Size.min_from_bit_range rl),Ints_t.of_bigint (Size.max_from_bit_range rh)) excl - in - let excl_list = List.map (excl_to_intervalset ik range) xs in - List.fold_left (meet ik) intv excl_list - - let project ik p t = t - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let list_pair_arb = QCheck.small_list pair_arb in - let canonize_randomly_generated_list = (fun x -> norm_intvs ik x |> fst) in - let shrink xs = GobQCheck.shrink list_pair_arb xs >|= canonize_randomly_generated_list - in QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) canonize_randomly_generated_list list_pair_arb) -end - -module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct - include D - - let add ?no_ov ik x y = fst @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = fst @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = fst @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = fst @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = fst @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = fst @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = fst @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = fst @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = fst @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = fst @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = fst @@ D.shift_left ik x y - - let shift_right ik x y = fst @@ D.shift_right ik x y -end - -module IntIkind = struct let ikind () = Cil.IInt end -module Interval = IntervalFunctor (IntOps.BigIntOps) -module Interval32 = IntDomWithDefaultIkind (IntDomLifter (SOverflowUnlifter (IntervalFunctor (IntOps.Int64Ops)))) (IntIkind) -module IntervalSet = IntervalSetFunctor (IntOps.BigIntOps) -module Integers (Ints_t : IntOps.IntOps): IkindUnawareS with type t = Ints_t.t and type int_t = Ints_t.t = (* no top/bot, order is <= *) -struct - include Printable.Std - let name () = "integers" - type t = Ints_t.t [@@deriving eq, ord, hash] - type int_t = Ints_t.t - let top () = raise Unknown - let bot () = raise Error - let top_of ik = top () - let bot_of ik = bot () - let show (x: Ints_t.t) = Ints_t.to_string x - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - (* is_top and is_bot are never called, but if they were, the Std impl would raise their exception, so we overwrite them: *) - let is_top _ = false - let is_bot _ = false - - let equal_to i x = if i > x then `Neq else `Top - let leq x y = x <= y - let join x y = if Ints_t.compare x y > 0 then x else y - let widen = join - let meet x y = if Ints_t.compare x y > 0 then y else x - let narrow = meet - - let of_bool x = if x then Ints_t.one else Ints_t.zero - let to_bool' x = x <> Ints_t.zero - let to_bool x = Some (to_bool' x) - let of_int x = x - let to_int x = Some x - - let neg = Ints_t.neg - let add = Ints_t.add (* TODO: signed overflow is undefined behavior! *) - let sub = Ints_t.sub - let mul = Ints_t.mul - let div = Ints_t.div - let rem = Ints_t.rem - let lt n1 n2 = of_bool (n1 < n2) - let gt n1 n2 = of_bool (n1 > n2) - let le n1 n2 = of_bool (n1 <= n2) - let ge n1 n2 = of_bool (n1 >= n2) - let eq n1 n2 = of_bool (n1 = n2) - let ne n1 n2 = of_bool (n1 <> n2) - let lognot = Ints_t.lognot - let logand = Ints_t.logand - let logor = Ints_t.logor - let logxor = Ints_t.logxor - let shift_left n1 n2 = Ints_t.shift_left n1 (Ints_t.to_int n2) - let shift_right n1 n2 = Ints_t.shift_right n1 (Ints_t.to_int n2) - let c_lognot n1 = of_bool (not (to_bool' n1)) - let c_logand n1 n2 = of_bool ((to_bool' n1) && (to_bool' n2)) - let c_logor n1 n2 = of_bool ((to_bool' n1) || (to_bool' n2)) - let cast_to ?(suppress_ovwarn=false) ?torg t x = failwith @@ "Cast_to not implemented for " ^ (name ()) ^ "." - let arbitrary ik = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 (* TODO: use ikind *) - let invariant _ _ = Invariant.none (* TODO *) -end - -module FlatPureIntegers: IkindUnawareS with type t = int64 and type int_t = int64 = (* Integers, but raises Unknown/Error on join/meet *) -struct - include Integers(IntOps.Int64Ops) - let top () = raise Unknown - let bot () = raise Error - let leq = equal - let pretty_diff () (x,y) = Pretty.dprintf "Integer %a instead of %a" pretty x pretty y - let join x y = if equal x y then x else top () - let meet x y = if equal x y then x else bot () -end - -module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) -struct - type int_t = Base.int_t - include Lattice.FlatConf (struct - include Printable.DefaultConf - let top_name = "Unknown int" - let bot_name = "Error int" - end) (Base) - - let top_of ik = top () - let bot_of ik = bot () - - - let name () = "flat integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ikind x = top_of ikind - let ending ?(suppress_ovwarn=false) ikind x = top_of ikind - let maximal x = None - let minimal x = None - - let lift1 f x = match x with - | `Lifted x -> - (try `Lifted (f x) with Unknown -> `Top | Error -> `Bot) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> - (try `Lifted (f x y) with Unknown -> `Top | Error -> `Bot) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) -struct - include Lattice.LiftPO (struct - include Printable.DefaultConf - let top_name = "MaxInt" - let bot_name = "MinInt" - end) (Base) - type int_t = Base.int_t - let top_of ik = top () - let bot_of ik = bot () - include StdTop (struct type nonrec t = t let top_of = top_of end) - - let name () = "lifted integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let lift1 f x = match x with - | `Lifted x -> `Lifted (f x) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> `Lifted (f x y) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Flattened = Flat (Integers (IntOps.Int64Ops)) -module Lifted = Lift (Integers (IntOps.Int64Ops)) - -module Reverse (Base: IkindUnawareS) = -struct - include Base - include (Lattice.Reverse (Base) : Lattice.S with type t := Base.t) -end - -module BISet = struct - include SetDomain.Make (IntOps.BigIntOps) - let is_singleton s = cardinal s = 1 -end - -(* The module [Exclusion] constains common functionality about handling of exclusion sets between [DefExc] and [Enums] *) -module Exclusion = -struct - module R = Interval32 - (* We use these types for the functions in this module to make the intended meaning more explicit *) - type t = Exc of BISet.t * Interval32.t - type inc = Inc of BISet.t [@@unboxed] - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.succ (Z.add (Z.neg (min_of_range r)) (max_of_range r)) - - let cardinality_BISet s = - Z.of_int (BISet.cardinal s) - - let leq_excl_incl (Exc (xs, r)) (Inc ys) = - (* For a <= b to hold, the cardinalities must fit, i.e. |a| <= |b|, which implies |min_r, max_r| - |xs| <= |ys|. We check this first. *) - let lower_bound_cardinality_a = Z.sub (cardinality_of_range r) (cardinality_BISet xs) in - let card_b = cardinality_BISet ys in - if Z.compare lower_bound_cardinality_a card_b > 0 then - false - else (* The cardinality did fit, so we check for all elements that are represented by range r, whether they are in (xs union ys) *) - let min_a = min_of_range r in - let max_a = max_of_range r in - GobZ.for_all_range (fun el -> BISet.mem el xs || BISet.mem el ys) (min_a, max_a) - - let leq (Exc (xs, r)) (Exc (ys, s)) = - let min_a, max_a = min_of_range r, max_of_range r in - let excluded_check = BISet.for_all (fun y -> BISet.mem y xs || Z.compare y min_a < 0 || Z.compare y max_a > 0) ys in (* if true, then the values ys, that are not in b, also do not occur in a *) - if not excluded_check - then false - else begin (* Check whether all elements that are in the range r, but not in s, are in xs, i.e. excluded. *) - if R.leq r s then true - else begin if Z.compare (cardinality_BISet xs) (Z.sub (cardinality_of_range r) (cardinality_of_range s)) >= 0 (* Check whether the number of excluded elements in a is as least as big as |min_r, max_r| - |min_s, max_s| *) - then - let min_b, max_b = min_of_range s, max_of_range s in - let leq1 = (* check whether the elements in [r_l; s_l-1] are all in xs, i.e. excluded *) - if Z.compare min_a min_b < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (min_a, Z.pred min_b) - else - true - in - let leq2 () = (* check whether the elements in [s_u+1; r_u] are all in xs, i.e. excluded *) - if Z.compare max_b max_a < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (Z.succ max_b, max_a) - else - true - in - leq1 && (leq2 ()) - else - false - end - end -end module DefExc : S with type int_t = Z.t = (* definite or set of excluded values *) struct @@ -2375,35 +479,3 @@ struct let project ik p t = t end - -module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct - - include D - - let lift v = (v, {overflow=false; underflow=false}) - - let add ?no_ov ik x y = lift @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = lift @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = lift @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = lift @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = lift @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = lift @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = lift @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = lift @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = lift @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = lift @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = lift @@ D.shift_left ik x y - - let shift_right ik x y = lift @@ D.shift_right ik x y - -end From a35c289d246d2fc55ea993f53ded147db91c0ae1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:03:24 +0300 Subject: [PATCH 602/689] Remove DefExc from IntDomain0 --- src/cdomain/value/cdomains/intDomain0.ml | 479 ----------------------- 1 file changed, 479 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/intDomain0.ml index 1cda533c55..0bcfa6ae44 100644 --- a/src/cdomain/value/cdomains/intDomain0.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -1897,485 +1897,6 @@ struct end end -module DefExc : S with type int_t = Z.t = (* definite or set of excluded values *) -struct - module S = BISet - module R = Interval32 (* range for exclusion *) - - (* Ikind used for intervals representing the domain *) - let range_ikind = Cil.IInt - let size t = R.of_interval range_ikind (let a,b = Size.bits_i64 t in Int64.neg a,b) - - - type t = [ - | `Excluded of S.t * R.t - | `Definite of Z.t - | `Bot - ] [@@deriving eq, ord, hash] - type int_t = Z.t - let name () = "def_exc" - - - let top_range = R.of_interval range_ikind (-99L, 99L) (* Since there is no top ikind we use a range that includes both ILongLong [-63,63] and IULongLong [0,64]. Only needed for intermediate range computation on longs. Correct range is set by cast. *) - let top () = `Excluded (S.empty (), top_range) - let bot () = `Bot - let top_of ik = `Excluded (S.empty (), size ik) - let bot_of ik = bot () - - let show x = - let short_size x = "("^R.show x^")" in - match x with - | `Bot -> "Error int" - | `Definite x -> Z.to_string x - (* Print the empty exclusion as if it was a distinct top element: *) - | `Excluded (s,l) when S.is_empty s -> "Unknown int" ^ short_size l - (* Prepend the exclusion sets with something: *) - | `Excluded (s,l) -> "Not " ^ S.show s ^ short_size l - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let maximal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.max_of_range r) - | `Bot -> None - - let minimal = function - | `Definite x -> Some x - | `Excluded (s,r) -> Some (Exclusion.min_of_range r) - | `Bot -> None - - let in_range r i = - if Z.compare i Z.zero < 0 then - let lowerb = Exclusion.min_of_range r in - Z.compare lowerb i <= 0 - else - let upperb = Exclusion.max_of_range r in - Z.compare i upperb <= 0 - - let is_top x = x = top () - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Definite x -> if i = x then `Eq else `Neq - | `Excluded (s,r) -> if S.mem i s then `Neq else `Top - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik = function - | `Excluded (s,r) -> - let r' = size ik in - if R.leq r r' then (* upcast -> no change *) - `Excluded (s, r) - else if ik = IBool then (* downcast to bool *) - if S.mem Z.zero s then - `Definite Z.one - else - `Excluded (S.empty(), r') - else - (* downcast: may overflow *) - (* let s' = S.map (Size.cast ik) s in *) - (* We want to filter out all i in s' where (t)x with x in r could be i. *) - (* Since this is hard to compute, we just keep all i in s' which overflowed, since those are safe - all i which did not overflow may now be possible due to overflow of r. *) - (* S.diff s' s, r' *) - (* The above is needed for test 21/03, but not sound! See example https://github.com/goblint/analyzer/pull/95#discussion_r483023140 *) - `Excluded (S.empty (), r') - | `Definite x -> `Definite (Size.cast ik x) - | `Bot -> `Bot - - (* Wraps definite values and excluded values according to the ikind. - * For an `Excluded s,r , assumes that r is already an overapproximation of the range of possible values. - * r might be larger than the possible range of this type; the range of the returned `Excluded set will be within the bounds of the ikind. - *) - let norm ik v = - match v with - | `Excluded (s, r) -> - let possibly_overflowed = not (R.leq r (size ik)) || not (S.for_all (in_range (size ik)) s) in - (* If no overflow occurred, just return x *) - if not possibly_overflowed then ( - v - ) - (* Else, if an overflow might have occurred but we should just ignore it *) - else if should_ignore_overflow ik then ( - let r = size ik in - (* filter out excluded elements that are not in the range *) - let mapped_excl = S.filter (in_range r) s in - `Excluded (mapped_excl, r) - ) - (* Else, if an overflow occurred that we should not treat with wrap-around, go to top *) - else if not (should_wrap ik) then ( - top_of ik - ) else ( - (* Else an overflow occurred that we should treat with wrap-around *) - let r = size ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - let mapped_excl = S.map (fun excl -> Size.cast ik excl) s in - match ik with - | IBool -> - begin match S.mem Z.zero mapped_excl, S.mem Z.one mapped_excl with - | false, false -> `Excluded (mapped_excl, r) (* Not {} -> Not {} *) - | true, false -> `Definite Z.one (* Not {0} -> 1 *) - | false, true -> `Definite Z.zero (* Not {1} -> 0 *) - | true, true -> `Bot (* Not {0, 1} -> bot *) - end - | ik -> - `Excluded (mapped_excl, r) - ) - | `Definite x -> - let min, max = Size.range ik in - (* Perform a wrap-around for unsigned values and for signed values (if configured). *) - if should_wrap ik then ( - cast_to ik v - ) - else if Z.compare min x <= 0 && Z.compare x max <= 0 then ( - v - ) - else if should_ignore_overflow ik then ( - M.warn ~category:M.Category.Integer.overflow "DefExc: Value was outside of range, indicating overflow, but 'sem.int.signed_overflow' is 'assume_none' -> Returned Bot"; - `Bot - ) - else ( - top_of ik - ) - | `Bot -> `Bot - - let leq x y = match (x,y) with - (* `Bot <= x is always true *) - | `Bot, _ -> true - (* Anything except bot <= bot is always false *) - | _, `Bot -> false - (* Two known values are leq whenever equal *) - | `Definite (x: int_t), `Definite y -> x = y - (* A definite value is leq all exclusion sets that don't contain it *) - | `Definite x, `Excluded (s,r) -> in_range r x && not (S.mem x s) - (* No finite exclusion set can be leq than a definite value *) - | `Excluded (xs, xr), `Definite d -> - Exclusion.(leq_excl_incl (Exc (xs, xr)) (Inc (S.singleton d))) - | `Excluded (xs,xr), `Excluded (ys,yr) -> - Exclusion.(leq (Exc (xs,xr)) (Exc (ys, yr))) - - let join' ?range ik x y = - match (x,y) with - (* The least upper bound with the bottom element: *) - | `Bot, x -> x - | x, `Bot -> x - (* The case for two known values: *) - | `Definite (x: int_t), `Definite y -> - (* If they're equal, it's just THAT value *) - if x = y then `Definite x - (* Unless one of them is zero, we can exclude it: *) - else - let a,b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval range_ikind a) (R.of_interval range_ikind b) in - `Excluded ((if Z.equal x Z.zero || Z.equal y Z.zero then S.empty () else S.singleton Z.zero), r) - (* A known value and an exclusion set... the definite value should no - * longer be excluded: *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> - if not (in_range r x) then - let a = R.of_interval range_ikind (Size.min_range_sign_agnostic x) in - `Excluded (S.remove x s, R.join a r) - else - `Excluded (S.remove x s, r) - (* For two exclusion sets, only their intersection can be excluded: *) - | `Excluded (x,wx), `Excluded (y,wy) -> `Excluded (S.inter x y, range |? R.join wx wy) - - let join ik = join' ik - - - let widen ik x y = - if get_def_exc_widen_by_join () then - join' ik x y - else if equal x y then - x - else - join' ~range:(size ik) ik x y - - - let meet ik x y = - match (x,y) with - (* Greatest LOWER bound with the least element is trivial: *) - | `Bot, _ -> `Bot - | _, `Bot -> `Bot - (* Definite elements are either equal or the glb is bottom *) - | `Definite x, `Definite y -> if x = y then `Definite x else `Bot - (* The glb of a definite element and an exclusion set is either bottom or - * just the element itself, if it isn't in the exclusion set *) - | `Excluded (s,r), `Definite x - | `Definite x, `Excluded (s,r) -> if S.mem x s || not (in_range r x) then `Bot else `Definite x - (* The greatest lower bound of two exclusion sets is their union, this is - * just DeMorgans Law *) - | `Excluded (x,r1), `Excluded (y,r2) -> - let r' = R.meet r1 r2 in - let s' = S.union x y |> S.filter (in_range r') in - `Excluded (s', r') - - let narrow ik x y = x - - let of_int ik x = norm ik @@ `Definite x - let to_int x = match x with - | `Definite x -> Some x - | _ -> None - - let from_excl ikind (s: S.t) = norm ikind @@ `Excluded (s, size ikind) - - let of_bool_cmp ik x = of_int ik (if x then Z.one else Z.zero) - let of_bool = of_bool_cmp - let to_bool x = - match x with - | `Definite x -> Some (IntOps.BigIntOps.to_bool x) - | `Excluded (s,r) when S.mem Z.zero s -> Some true - | _ -> None - let top_bool = `Excluded (S.empty (), R.of_interval range_ikind (0L, 1L)) - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = - if Z.compare x y = 0 then - of_int ik x - else - let a, b = Size.min_range_sign_agnostic x, Size.min_range_sign_agnostic y in - let r = R.join (R.of_interval ~suppress_ovwarn range_ikind a) (R.of_interval ~suppress_ovwarn range_ikind b) in - let ex = if Z.gt x Z.zero || Z.lt y Z.zero then S.singleton Z.zero else S.empty () in - norm ik @@ (`Excluded (ex, r)) - - let starting ?(suppress_ovwarn=false) ikind x = - let _,u_ik = Size.range ikind in - of_interval ~suppress_ovwarn ikind (x, u_ik) - - let ending ?(suppress_ovwarn=false) ikind x = - let l_ik,_ = Size.range ikind in - of_interval ~suppress_ovwarn ikind (l_ik, x) - - let of_excl_list t l = - let r = size t in (* elements in l are excluded from the full range of t! *) - `Excluded (List.fold_right S.add l (S.empty ()), r) - let is_excl_list l = match l with `Excluded _ -> true | _ -> false - let to_excl_list (x:t) = match x with - | `Definite _ -> None - | `Excluded (s,r) -> Some (S.elements s, (Option.get (R.minimal r), Option.get (R.maximal r))) - | `Bot -> None - - let to_incl_list x = match x with - | `Definite x -> Some [x] - | `Excluded _ -> None - | `Bot -> None - - let apply_range f r = (* apply f to the min/max of the old range r to get a new range *) - (* If the Int64 might overflow on us during computation, we instead go to top_range *) - match R.minimal r, R.maximal r with - | _ -> - let rf m = (size % Size.min_for % f) (m r) in - let r1, r2 = rf Exclusion.min_of_range, rf Exclusion.max_of_range in - R.join r1 r2 - - (* Default behaviour for unary operators, simply maps the function to the - * DefExc data structure. *) - let lift1 f ik x = norm ik @@ match x with - | `Excluded (s,r) -> - let s' = S.map f s in - `Excluded (s', apply_range f r) - | `Definite x -> `Definite (f x) - | `Bot -> `Bot - - let lift2 f ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite _ - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (f x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - (* Default behaviour for binary operators that are injective in either - * argument, so that Exclusion Sets can be used: *) - let lift2_inj f ik x y = - let def_exc f x s r = `Excluded (S.map (f x) s, apply_range (f x) r) in - norm ik @@ - match x,y with - (* If both are exclusion sets, there isn't anything we can do: *) - | `Excluded _, `Excluded _ -> top () - (* A definite value should be applied to all members of the exclusion set *) - | `Definite x, `Excluded (s,r) -> def_exc f x s r - (* Same thing here, but we should flip the operator to map it properly *) - | `Excluded (s,r), `Definite x -> def_exc (Batteries.flip f) x s r - (* The good case: *) - | `Definite x, `Definite y -> `Definite (f x y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The equality check: *) - let eq ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x equal to an exclusion set, if it is a member then NO otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt false else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt false else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x = y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - (* The inequality check: *) - let ne ik x y = match x,y with - (* Not much to do with two exclusion sets: *) - | `Excluded _, `Excluded _ -> top () - (* Is x unequal to an exclusion set, if it is a member then Yes otherwise we - * don't know: *) - | `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt true else top () - | `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt true else top () - (* The good case: *) - | `Definite x, `Definite y -> of_bool IInt (x <> y) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - - let neg ?no_ov ik (x :t) = norm ik @@ lift1 Z.neg ik x - let add ?no_ov ik x y = norm ik @@ lift2_inj Z.add ik x y - - let sub ?no_ov ik x y = norm ik @@ lift2_inj Z.sub ik x y - let mul ?no_ov ik x y = norm ik @@ match x, y with - | `Definite z, (`Excluded _ | `Definite _) when Z.equal z Z.zero -> x - | (`Excluded _ | `Definite _), `Definite z when Z.equal z Z.zero -> y - | `Definite a, `Excluded (s,r) - (* Integer multiplication with even numbers is not injective. *) - (* Thus we cannot exclude the values to which the exclusion set would be mapped to. *) - | `Excluded (s,r),`Definite a when Z.equal (Z.rem a (Z.of_int 2)) Z.zero -> `Excluded (S.empty (), apply_range (Z.mul a) r) - | _ -> lift2_inj Z.mul ik x y - let div ?no_ov ik x y = lift2 Z.div ik x y - let rem ik x y = lift2 Z.rem ik x y - - (* Comparison handling copied from Enums. *) - let handle_bot x y f = match x, y with - | `Bot, `Bot -> `Bot - | `Bot, _ - | _, `Bot -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> f () - - let lt ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let gt ik x y = lt ik y x - - let le ik x y = - handle_bot x y (fun () -> - match minimal x, maximal x, minimal y, maximal y with - | _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true - | Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false - | _, _, _, _ -> top_bool) - - let ge ik x y = le ik y x - - let lognot = lift1 Z.lognot - - let logand ik x y = norm ik (match x,y with - (* We don't bother with exclusion sets: *) - | `Excluded _, `Definite i -> - (* Except in two special cases *) - if Z.equal i Z.zero then - `Definite Z.zero - else if Z.equal i Z.one then - of_interval IBool (Z.zero, Z.one) - else - top () - | `Definite _, `Excluded _ - | `Excluded _, `Excluded _ -> top () - (* The good case: *) - | `Definite x, `Definite y -> - (try `Definite (Z.logand x y) with | Division_by_zero -> top ()) - | `Bot, `Bot -> `Bot - | _ -> - (* If only one of them is bottom, we raise an exception that eval_rv will catch *) - raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))) - - - let logor = lift2 Z.logor - let logxor = lift2 Z.logxor - - let shift (shift_op: int_t -> int -> int_t) (ik: Cil.ikind) (x: t) (y: t) = - (* BigInt only accepts int as second argument for shifts; perform conversion here *) - let shift_op_big_int a (b: int_t) = - let (b : int) = Z.to_int b in - shift_op a b - in - (* If one of the parameters of the shift is negative, the result is undefined *) - let is_negative = GobOption.for_all (fun x -> Z.lt x Z.zero) in - if is_negative (minimal x) || is_negative (minimal y) then - top_of ik - else - norm ik @@ lift2 shift_op_big_int ik x y - - let shift_left = - shift Z.shift_left - - let shift_right = - shift Z.shift_right - (* TODO: lift does not treat Not {0} as true. *) - let c_logand ik x y = - match to_bool x, to_bool y with - | Some false, _ - | _, Some false -> - of_bool ik false - | _, _ -> - lift2 IntOps.BigIntOps.c_logand ik x y - let c_logor ik x y = - match to_bool x, to_bool y with - | Some true, _ - | _, Some true -> - of_bool ik true - | _, _ -> - lift2 IntOps.BigIntOps.c_logor ik x y - let c_lognot ik = eq ik (of_int ik Z.zero) - - let invariant_ikind e ik (x:t) = - match x with - | `Definite x -> - IntInvariant.of_int e ik x - | `Excluded (s, r) -> - (* Emit range invariant if tighter than ikind bounds. - This can be more precise than interval, which has been widened. *) - let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in - let ri = IntInvariant.of_interval e ik (rmin, rmax) in - let si = IntInvariant.of_excl_list e ik (S.elements s) in - Invariant.(ri && si) - | `Bot -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - let excluded s = from_excl ik s in - let definite x = of_int ik x in - let shrink = function - | `Excluded (s, _) -> GobQCheck.shrink (S.arbitrary ()) s >|= excluded (* S TODO: possibly shrink excluded to definite *) - | `Definite x -> (return `Bot) <+> (GobQCheck.shrink (IntOps.BigIntOps.arbitrary ()) x >|= definite) - | `Bot -> empty - in - QCheck.frequency ~shrink ~print:show [ - 20, QCheck.map excluded (S.arbitrary ()); - 10, QCheck.map definite (IntOps.BigIntOps.arbitrary ()); - 1, QCheck.always `Bot - ] (* S TODO: decide frequencies *) - - let refine_with_congruence ik a b = a - let refine_with_interval ik a b = match a, b with - | x, Some(i) -> meet ik x (of_interval ik i) - | _ -> a - let refine_with_excl_list ik a b = match a, b with - | `Excluded (s, r), Some(ls, _) -> meet ik (`Excluded (s, r)) (of_excl_list ik ls) (* TODO: refine with excl range? *) - | _ -> a - let refine_with_incl_list ik a b = a - - let project ik p t = t -end - module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct include D From da3f5367d01bc71af446ba0a456307d69c68ed21 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:06:25 +0300 Subject: [PATCH 603/689] Rename IntDomain0 -> IntervalSetDomain for split --- .../value/cdomains/{intDomain0.ml => int/intervalSetDomain.ml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cdomain/value/cdomains/{intDomain0.ml => int/intervalSetDomain.ml} (100%) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/int/intervalSetDomain.ml similarity index 100% rename from src/cdomain/value/cdomains/intDomain0.ml rename to src/cdomain/value/cdomains/int/intervalSetDomain.ml From e0ff2239a0323c62dda30a6617ee176bb8c1abba Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:06:48 +0300 Subject: [PATCH 604/689] Remove non-IntervalSetDomain parts --- .../value/cdomains/int/intervalSetDomain.ml | 1395 +---------------- 1 file changed, 1 insertion(+), 1394 deletions(-) diff --git a/src/cdomain/value/cdomains/int/intervalSetDomain.ml b/src/cdomain/value/cdomains/int/intervalSetDomain.ml index 0bcfa6ae44..20d647ce62 100644 --- a/src/cdomain/value/cdomains/int/intervalSetDomain.ml +++ b/src/cdomain/value/cdomains/int/intervalSetDomain.ml @@ -1,1051 +1,5 @@ -open GobConfig -open GoblintCil -open Pretty -open PrecisionUtil - -module M = Messages - -let (%) = Batteries.(%) -let (|?) = Batteries.(|?) - -exception IncompatibleIKinds of string -exception Unknown -exception Error -exception ArithmeticOnIntegerBot of string - - - - -(** Define records that hold mutable variables representing different Configuration values. - * These values are used to keep track of whether or not the corresponding Config values are en-/disabled *) -type ana_int_config_values = { - mutable interval_threshold_widening : bool option; - mutable interval_narrow_by_meet : bool option; - mutable def_exc_widen_by_join : bool option; - mutable interval_threshold_widening_constants : string option; - mutable refinement : string option; -} - -let ana_int_config: ana_int_config_values = { - interval_threshold_widening = None; - interval_narrow_by_meet = None; - def_exc_widen_by_join = None; - interval_threshold_widening_constants = None; - refinement = None; -} - -let get_interval_threshold_widening () = - if ana_int_config.interval_threshold_widening = None then - ana_int_config.interval_threshold_widening <- Some (get_bool "ana.int.interval_threshold_widening"); - Option.get ana_int_config.interval_threshold_widening - -let get_interval_narrow_by_meet () = - if ana_int_config.interval_narrow_by_meet = None then - ana_int_config.interval_narrow_by_meet <- Some (get_bool "ana.int.interval_narrow_by_meet"); - Option.get ana_int_config.interval_narrow_by_meet - -let get_def_exc_widen_by_join () = - if ana_int_config.def_exc_widen_by_join = None then - ana_int_config.def_exc_widen_by_join <- Some (get_bool "ana.int.def_exc_widen_by_join"); - Option.get ana_int_config.def_exc_widen_by_join - -let get_interval_threshold_widening_constants () = - if ana_int_config.interval_threshold_widening_constants = None then - ana_int_config.interval_threshold_widening_constants <- Some (get_string "ana.int.interval_threshold_widening_constants"); - Option.get ana_int_config.interval_threshold_widening_constants - -let get_refinement () = - if ana_int_config.refinement = None then - ana_int_config.refinement <- Some (get_string "ana.int.refinement"); - Option.get ana_int_config.refinement - - - -(** Whether for a given ikind, we should compute with wrap-around arithmetic. - * Always for unsigned types, for signed types if 'sem.int.signed_overflow' is 'assume_wraparound' *) -let should_wrap ik = not (Cil.isSigned ik) || get_string "sem.int.signed_overflow" = "assume_wraparound" - -(** Whether for a given ikind, we should assume there are no overflows. - * Always false for unsigned types, true for signed types if 'sem.int.signed_overflow' is 'assume_none' *) -let should_ignore_overflow ik = Cil.isSigned ik && get_string "sem.int.signed_overflow" = "assume_none" - -let widening_thresholds = ResettableLazy.from_fun WideningThresholds.thresholds -let widening_thresholds_desc = ResettableLazy.from_fun (List.rev % WideningThresholds.thresholds) - -type overflow_info = { overflow: bool; underflow: bool;} - -let set_overflow_flag ~cast ~underflow ~overflow ik = - if !AnalysisState.executing_speculative_computations then - (* Do not produce warnings when the operations are not actually happening in code *) - () - else - let signed = Cil.isSigned ik in - if !AnalysisState.postsolving && signed && not cast then - AnalysisState.svcomp_may_overflow := true; - let sign = if signed then "Signed" else "Unsigned" in - match underflow, overflow with - | true, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190; CWE 191] "%s integer overflow and underflow" sign - | true, false -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 191] "%s integer underflow" sign - | false, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190] "%s integer overflow" sign - | false, false -> assert false - -let reset_lazy () = - ResettableLazy.reset widening_thresholds; - ResettableLazy.reset widening_thresholds_desc; - ana_int_config.interval_threshold_widening <- None; - ana_int_config.interval_narrow_by_meet <- None; - ana_int_config.def_exc_widen_by_join <- None; - ana_int_config.interval_threshold_widening_constants <- None; - ana_int_config.refinement <- None - -module type Arith = -sig - type t - val neg: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div: t -> t -> t - val rem: t -> t -> t - - val lt: t -> t -> t - val gt: t -> t -> t - val le: t -> t -> t - val ge: t -> t -> t - val eq: t -> t -> t - val ne: t -> t -> t - - val lognot: t -> t - val logand: t -> t -> t - val logor : t -> t -> t - val logxor: t -> t -> t - - val shift_left : t -> t -> t - val shift_right: t -> t -> t - - val c_lognot: t -> t - val c_logand: t -> t -> t - val c_logor : t -> t -> t +open IntDomain0 -end - -module type ArithIkind = -sig - type t - val neg: Cil.ikind -> t -> t - val add: Cil.ikind -> t -> t -> t - val sub: Cil.ikind -> t -> t -> t - val mul: Cil.ikind -> t -> t -> t - val div: Cil.ikind -> t -> t -> t - val rem: Cil.ikind -> t -> t -> t - - val lt: Cil.ikind -> t -> t -> t - val gt: Cil.ikind -> t -> t -> t - val le: Cil.ikind -> t -> t -> t - val ge: Cil.ikind -> t -> t -> t - val eq: Cil.ikind -> t -> t -> t - val ne: Cil.ikind -> t -> t -> t - - val lognot: Cil.ikind -> t -> t - val logand: Cil.ikind -> t -> t -> t - val logor : Cil.ikind -> t -> t -> t - val logxor: Cil.ikind -> t -> t -> t - - val shift_left : Cil.ikind -> t -> t -> t - val shift_right: Cil.ikind -> t -> t -> t - - val c_lognot: Cil.ikind -> t -> t - val c_logand: Cil.ikind -> t -> t -> t - val c_logor : Cil.ikind -> t -> t -> t - -end - -(* Shared functions between S and Z *) -module type B = -sig - include Lattice.S - type int_t - val bot_of: Cil.ikind -> t - val top_of: Cil.ikind -> t - val to_int: t -> int_t option - val equal_to: int_t -> t -> [`Eq | `Neq | `Top] - - val to_bool: t -> bool option - val to_excl_list: t -> (int_t list * (int64 * int64)) option - val of_excl_list: Cil.ikind -> int_t list -> t - val is_excl_list: t -> bool - - val to_incl_list: t -> int_t list option - - val maximal : t -> int_t option - val minimal : t -> int_t option - - val cast_to: ?suppress_ovwarn:bool -> ?torg:Cil.typ -> Cil.ikind -> t -> t -end - -(** Interface of IntDomain implementations that do not take ikinds for arithmetic operations yet. TODO: Should be ported to S in the future. *) -module type IkindUnawareS = -sig - include B - include Arith with type t := t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: int_t -> t - val of_bool: bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val arbitrary: unit -> t QCheck.arbitrary - val invariant: Cil.exp -> t -> Invariant.t -end - -(** Interface of IntDomain implementations taking an ikind for arithmetic operations *) -module type S = -sig - include B - include ArithIkind with type t:= t - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val neg : ?no_ov:bool -> Cil.ikind -> t -> t - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t - - val join: Cil.ikind -> t -> t -> t - val meet: Cil.ikind -> t -> t -> t - val narrow: Cil.ikind -> t -> t -> t - val widen: Cil.ikind -> t -> t -> t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val is_top_of: Cil.ikind -> t -> bool - val invariant_ikind : Cil.exp -> Cil.ikind -> t -> Invariant.t - - val refine_with_congruence: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_interval: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_excl_list: Cil.ikind -> t -> (int_t list * (int64 * int64)) option -> t - val refine_with_incl_list: Cil.ikind -> t -> int_t list option -> t - - val project: Cil.ikind -> int_precision -> t -> t - val arbitrary: Cil.ikind -> t QCheck.arbitrary -end - -module type SOverflow = -sig - - include S - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val neg : ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val of_int : Cil.ikind -> int_t -> t * overflow_info - - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t * overflow_info - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - - val shift_left : Cil.ikind -> t -> t -> t * overflow_info - - val shift_right : Cil.ikind -> t -> t -> t * overflow_info -end - -module type Y = -sig - (* include B *) - include B - include Arith with type t:= t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val is_top_of: Cil.ikind -> t -> bool - - val project: int_precision -> t -> t - val invariant: Cil.exp -> t -> Invariant.t -end - -module type Z = Y with type int_t = Z.t - - -module IntDomLifter (I : S) = -struct - open Cil - type int_t = I.int_t - type t = { v : I.t; ikind : CilType.Ikind.t } [@@deriving eq, ord, hash] - - let ikind {ikind; _} = ikind - - (* Helper functions *) - let check_ikinds x y = if x.ikind <> y.ikind then raise (IncompatibleIKinds (GobPretty.sprintf "ikinds %a and %a are incompatible. Values: %a and %a" CilType.Ikind.pretty x.ikind CilType.Ikind.pretty y.ikind I.pretty x.v I.pretty y.v)) - let lift op x = {x with v = op x.ikind x.v } - (* For logical operations the result is of type int *) - let lift_logical op x = {v = op x.ikind x.v; ikind = Cil.IInt} - let lift2 op x y = check_ikinds x y; {x with v = op x.ikind x.v y.v } - let lift2_cmp op x y = check_ikinds x y; {v = op x.ikind x.v y.v; ikind = Cil.IInt} - - let bot_of ikind = { v = I.bot_of ikind; ikind} - let bot () = failwith "bot () is not implemented for IntDomLifter." - let is_bot x = I.is_bot x.v - let top_of ikind = { v = I.top_of ikind; ikind} - let top () = failwith "top () is not implemented for IntDomLifter." - let is_top x = I.is_top x.v - - (* Leq does not check for ikind, because it is used in invariant with arguments of different type. - TODO: check ikinds here and fix invariant to work with right ikinds *) - let leq x y = I.leq x.v y.v - let join = lift2 I.join - let meet = lift2 I.meet - let widen = lift2 I.widen - let narrow = lift2 I.narrow - - let show x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - "⊤" - else - I.show x.v (* TODO add ikind to output *) - let pretty () x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - Pretty.text "⊤" - else - I.pretty () x.v (* TODO add ikind to output *) - let pretty_diff () (x, y) = I.pretty_diff () (x.v, y.v) (* TODO check ikinds, add them to output *) - let printXml o x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - BatPrintf.fprintf o "\n\n⊤\n\n\n" - else - I.printXml o x.v (* TODO add ikind to output *) - (* This is for debugging *) - let name () = "IntDomLifter(" ^ (I.name ()) ^ ")" - let to_yojson x = I.to_yojson x.v - let invariant e x = - let e' = Cilfacade.mkCast ~e ~newt:(TInt (x.ikind, [])) in - I.invariant_ikind e' x.ikind x.v - let tag x = I.tag x.v - let arbitrary ik = failwith @@ "Arbitrary not implement for " ^ (name ()) ^ "." - let to_int x = I.to_int x.v - let of_int ikind x = { v = I.of_int ikind x; ikind} - let equal_to i x = I.equal_to i x.v - let to_bool x = I.to_bool x.v - let of_bool ikind b = { v = I.of_bool ikind b; ikind} - let to_excl_list x = I.to_excl_list x.v - let of_excl_list ikind is = {v = I.of_excl_list ikind is; ikind} - let is_excl_list x = I.is_excl_list x.v - let to_incl_list x = I.to_incl_list x.v - let of_interval ?(suppress_ovwarn=false) ikind (lb,ub) = {v = I.of_interval ~suppress_ovwarn ikind (lb,ub); ikind} - let of_congruence ikind (c,m) = {v = I.of_congruence ikind (c,m); ikind} - let starting ?(suppress_ovwarn=false) ikind i = {v = I.starting ~suppress_ovwarn ikind i; ikind} - let ending ?(suppress_ovwarn=false) ikind i = {v = I.ending ~suppress_ovwarn ikind i; ikind} - let maximal x = I.maximal x.v - let minimal x = I.minimal x.v - - let neg = lift I.neg - let add = lift2 I.add - let sub = lift2 I.sub - let mul = lift2 I.mul - let div = lift2 I.div - let rem = lift2 I.rem - let lt = lift2_cmp I.lt - let gt = lift2_cmp I.gt - let le = lift2_cmp I.le - let ge = lift2_cmp I.ge - let eq = lift2_cmp I.eq - let ne = lift2_cmp I.ne - let lognot = lift I.lognot - let logand = lift2 I.logand - let logor = lift2 I.logor - let logxor = lift2 I.logxor - let shift_left x y = {x with v = I.shift_left x.ikind x.v y.v } (* TODO check ikinds*) - let shift_right x y = {x with v = I.shift_right x.ikind x.v y.v } (* TODO check ikinds*) - let c_lognot = lift_logical I.c_lognot - let c_logand = lift2 I.c_logand - let c_logor = lift2 I.c_logor - - let cast_to ?(suppress_ovwarn=false) ?torg ikind x = {v = I.cast_to ~suppress_ovwarn ~torg:(TInt(x.ikind,[])) ikind x.v; ikind} - - let is_top_of ik x = ik = x.ikind && I.is_top_of ik x.v - - let relift x = { v = I.relift x.v; ikind = x.ikind } - - let project p v = { v = I.project v.ikind p v.v; ikind = v.ikind } -end - -module type Ikind = -sig - val ikind: unit -> Cil.ikind -end - -module PtrDiffIkind : Ikind = -struct - let ikind = Cilfacade.ptrdiff_ikind -end - -module IntDomWithDefaultIkind (I: Y) (Ik: Ikind) : Y with type t = I.t and type int_t = I.int_t = -struct - include I - let top () = I.top_of (Ik.ikind ()) - let bot () = I.bot_of (Ik.ikind ()) -end - -module Size = struct (* size in bits as int, range as int64 *) - open Cil - let sign x = if Z.compare x Z.zero < 0 then `Signed else `Unsigned - - let top_typ = TInt (ILongLong, []) - let min_for x = intKindForValue x (sign x = `Unsigned) - let bit = function (* bits needed for representation *) - | IBool -> 1 - | ik -> bytesSizeOfInt ik * 8 - let is_int64_big_int x = Z.fits_int64 x - let card ik = (* cardinality *) - let b = bit ik in - Z.shift_left Z.one b - let bits ik = (* highest bits for neg/pos values *) - let s = bit ik in - if isSigned ik then s-1, s-1 else 0, s - let bits_i64 ik = BatTuple.Tuple2.mapn Int64.of_int (bits ik) - let range ik = - let a,b = bits ik in - let x = if isSigned ik then Z.neg (Z.shift_left Z.one a) (* -2^a *) else Z.zero in - let y = Z.pred (Z.shift_left Z.one b) in (* 2^b - 1 *) - x,y - - let is_cast_injective ~from_type ~to_type = - let (from_min, from_max) = range (Cilfacade.get_ikind from_type) in - let (to_min, to_max) = range (Cilfacade.get_ikind to_type) in - if M.tracing then M.trace "int" "is_cast_injective %a (%a, %a) -> %a (%a, %a)" CilType.Typ.pretty from_type GobZ.pretty from_min GobZ.pretty from_max CilType.Typ.pretty to_type GobZ.pretty to_min GobZ.pretty to_max; - Z.compare to_min from_min <= 0 && Z.compare from_max to_max <= 0 - - let cast t x = (* TODO: overflow is implementation-dependent! *) - if t = IBool then - (* C11 6.3.1.2 Boolean type *) - if Z.equal x Z.zero then Z.zero else Z.one - else - let a,b = range t in - let c = card t in - let y = Z.erem x c in - let y = if Z.gt y b then Z.sub y c - else if Z.lt y a then Z.add y c - else y - in - if M.tracing then M.tracel "cast" "Cast %a to range [%a, %a] (%a) = %a (%s in int64)" GobZ.pretty x GobZ.pretty a GobZ.pretty b GobZ.pretty c GobZ.pretty y (if is_int64_big_int y then "fits" else "does not fit"); - y - - let min_range_sign_agnostic x = - let size ik = - let a,b = bits_i64 ik in - Int64.neg a,b - in - if sign x = `Signed then - size (min_for x) - else - let a, b = size (min_for x) in - if b <= 64L then - let upper_bound_less = Int64.sub b 1L in - let max_one_less = Z.(pred @@ shift_left Z.one (Int64.to_int upper_bound_less)) in - if x <= max_one_less then - a, upper_bound_less - else - a,b - else - a, b - - (* From the number of bits used to represent a positive value, determines the maximal representable value *) - let max_from_bit_range pos_bits = Z.(pred @@ shift_left Z.one (to_int (Z.of_int64 pos_bits))) - - (* From the number of bits used to represent a non-positive value, determines the minimal representable value *) - let min_from_bit_range neg_bits = Z.(if neg_bits = 0L then Z.zero else neg @@ shift_left Z.one (to_int (neg (Z.of_int64 neg_bits)))) - -end - - -module StdTop (B: sig type t val top_of: Cil.ikind -> t end) = struct - open B - (* these should be overwritten for better precision if possible: *) - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ik x = top_of ik - let ending ?(suppress_ovwarn=false) ik x = top_of ik - let maximal x = None - let minimal x = None -end - -module Std (B: sig - type t - val name: unit -> string - val top_of: Cil.ikind -> t - val bot_of: Cil.ikind -> t - val show: t -> string - val equal: t -> t -> bool - end) = struct - include Printable.StdLeaf - let name = B.name (* overwrite the one from Printable.Std *) - open B - let is_top x = failwith "is_top not implemented for IntDomain.Std" - let is_bot x = B.equal x (bot_of Cil.IInt) (* Here we assume that the representation of bottom is independent of the ikind - This may be true for intdomain implementations, but not e.g. for IntDomLifter. *) - let is_top_of ik x = B.equal x (top_of ik) - - (* all output is based on B.show *) - include Printable.SimpleShow ( - struct - type nonrec t = t - let show = show - end - ) - let pretty_diff () (x,y) = dprintf "%s: %a instead of %a" (name ()) pretty x pretty y - - include StdTop (B) -end - -(* Textbook interval arithmetic, without any overflow handling etc. *) -module IntervalArith (Ints_t : IntOps.IntOps) = struct - let min4 a b c d = Ints_t.min (Ints_t.min a b) (Ints_t.min c d) - let max4 a b c d = Ints_t.max (Ints_t.max a b) (Ints_t.max c d) - - let mul (x1, x2) (y1, y2) = - let x1y1 = (Ints_t.mul x1 y1) in - let x1y2 = (Ints_t.mul x1 y2) in - let x2y1 = (Ints_t.mul x2 y1) in - let x2y2 = (Ints_t.mul x2 y2) in - (min4 x1y1 x1y2 x2y1 x2y2, max4 x1y1 x1y2 x2y1 x2y2) - - let shift_left (x1,x2) (y1,y2) = - let y1p = Ints_t.shift_left Ints_t.one y1 in - let y2p = Ints_t.shift_left Ints_t.one y2 in - mul (x1, x2) (y1p, y2p) - - let div (x1, x2) (y1, y2) = - let x1y1n = (Ints_t.div x1 y1) in - let x1y2n = (Ints_t.div x1 y2) in - let x2y1n = (Ints_t.div x2 y1) in - let x2y2n = (Ints_t.div x2 y2) in - let x1y1p = (Ints_t.div x1 y1) in - let x1y2p = (Ints_t.div x1 y2) in - let x2y1p = (Ints_t.div x2 y1) in - let x2y2p = (Ints_t.div x2 y2) in - (min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p) - - let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2) - let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1) - - let neg (x1, x2) = (Ints_t.neg x2, Ints_t.neg x1) - - let one = (Ints_t.one, Ints_t.one) - let zero = (Ints_t.zero, Ints_t.zero) - let top_bool = (Ints_t.zero, Ints_t.one) - - let to_int (x1, x2) = - if Ints_t.equal x1 x2 then Some x1 else None - - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let max_ik' = Ints_t.to_bigint max_ik in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let min_ik' = Ints_t.to_bigint min_ik in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let is_upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - List.exists (Z.equal u) ts - let is_lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - List.exists (Z.equal l) ts -end - -module IntInvariant = -struct - let of_int e ik x = - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.none - - let of_incl_list e ik ps = - match ps with - | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> - assert (List.mem Z.zero ps); - assert (List.mem Z.one ps); - Invariant.none - | [_] when get_bool "witness.invariant.exact" -> - Invariant.none - | _ :: _ :: _ - | [_] | [] -> - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) (Invariant.bot ()) ps - - let of_interval_opt e ik = function - | (Some x1, Some x2) when Z.equal x1 x2 -> - of_int e ik x1 - | x1_opt, x2_opt -> - let (min_ik, max_ik) = Size.range ik in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = - match x1_opt, inexact_type_bounds with - | Some x1, false when Z.equal min_ik x1 -> Invariant.none - | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) - | None, _ -> Invariant.none - in - let i2 = - match x2_opt, inexact_type_bounds with - | Some x2, false when Z.equal x2 max_ik -> Invariant.none - | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) - | None, _ -> Invariant.none - in - Invariant.(i1 && i2) - - let of_interval e ik (x1, x2) = - of_interval_opt e ik (Some x1, Some x2) - - let of_excl_list e ik ns = - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) (Invariant.top ()) ns -end - -module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = -struct - let name () = "intervals" - type int_t = Ints_t.t - type t = (Ints_t.t * Ints_t.t) option [@@deriving eq, ord, hash] - module IArith = IntervalArith (Ints_t) - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - let top_of ik = Some (range ik) - let bot () = None - let bot_of ik = bot () (* TODO: improve *) - - let show = function None -> "bottom" | Some (x,y) -> "["^Ints_t.to_string x^","^Ints_t.to_string y^"]" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) -> - if a = b && b = i then `Eq else if Ints_t.compare a i <= 0 && Ints_t.compare i b <=0 then `Top else `Neq - - let norm ?(suppress_ovwarn=false) ?(cast=false) ik : (t -> t * overflow_info) = function None -> (None, {underflow=false; overflow=false}) | Some (x,y) -> - if Ints_t.compare x y > 0 then - (None,{underflow=false; overflow=false}) - else ( - let (min_ik, max_ik) = range ik in - let underflow = Ints_t.compare min_ik x > 0 in - let overflow = Ints_t.compare max_ik y < 0 in - let ov_info = { underflow = underflow && not suppress_ovwarn; overflow = overflow && not suppress_ovwarn } in - let v = - if underflow || overflow then - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (Ints_t.sub max_ik min_ik) in - let resdiff = Ints_t.abs (Ints_t.sub y x) in - if Ints_t.compare resdiff diff > 0 then - top_of ik - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if Ints_t.compare l u <= 0 then - Some (l, u) - else - (* Interval that wraps around (begins to the right of its end). We can not represent such intervals *) - top_of ik - else if not cast && should_ignore_overflow ik then - let tl, tu = BatOption.get @@ top_of ik in - Some (Ints_t.max tl x, Ints_t.min tu y) - else - top_of ik - else - Some (x,y) - in - (v, ov_info) - ) - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0 - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst - - let meet ik (x:t) y = - match x, y with - | None, z | z, None -> None - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.max x1 y1, Ints_t.min x2 y2) |> fst - - (* TODO: change to_int signature so it returns a big_int *) - let to_int x = Option.bind x (IArith.to_int) - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm ~suppress_ovwarn ik @@ Some (x,y) - let of_int ik (x: int_t) = of_interval ik (x,x) - let zero = Some IArith.zero - let one = Some IArith.one - let top_bool = Some IArith.top_bool - - let of_bool _ik = function true -> one | false -> zero - let to_bool (a: t) = match a with - | None -> None - | Some (l, u) when Ints_t.compare l Ints_t.zero = 0 && Ints_t.compare u Ints_t.zero = 0 -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (fst (range ik), n) - - (* TODO: change signature of maximal, minimal to return big_int*) - let maximal = function None -> None | Some (x,y) -> Some y - let minimal = function None -> None | Some (x,y) -> Some x - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - - let widen ik x y = - match x, y with - | None, z | z, None -> z - | Some (l0,u0), Some (l1,u1) -> - let (min_ik, max_ik) = range ik in - let threshold = get_interval_threshold_widening () in - let l2 = - if Ints_t.compare l0 l1 = 0 then l0 - else if threshold then IArith.lower_threshold l1 min_ik - else min_ik - in - let u2 = - if Ints_t.compare u0 u1 = 0 then u0 - else if threshold then IArith.upper_threshold u1 max_ik - else max_ik - in - norm ik @@ Some (l2,u2) |> fst - let widen ik x y = - let r = widen ik x y in - if M.tracing && not (equal x y) then M.tracel "int" "interval widen %a %a -> %a" pretty x pretty y pretty r; - assert (leq x y); (* TODO: remove for performance reasons? *) - r - - let narrow ik x y = - match x, y with - | _,None | None, _ -> None - | Some (x1,x2), Some (y1,y2) -> - let threshold = get_interval_threshold_widening () in - let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in - norm ik @@ Some (lr,ur) |> fst - - - let narrow ik x y = - if get_interval_narrow_by_meet () then - meet ik x y - else - narrow ik x y - - let log f ~annihilator ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, _ when x = annihilator -> of_bool ik annihilator - | _, Some y when y = annihilator -> of_bool ik annihilator - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) ~annihilator:true - let c_logand = log (&&) ~annihilator:false - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let bit f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - let bitcomp f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{underflow=false; overflow=false})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let logxor = bit (fun _ik -> Ints_t.logxor) - - let logand ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (Ints_t.logand x y) |> fst with Division_by_zero -> top_of ik) - | _, Some y when Ints_t.equal y Ints_t.zero -> of_int ik Ints_t.zero |> fst - | _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst - | _ -> top_of ik - - let logor = bit (fun _ik -> Ints_t.logor) - - let bit1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_int i1 with - | Some x -> of_int ik (f ik x) |> fst - | _ -> top_of ik - - let lognot = bit1 (fun _ik -> Ints_t.lognot) - let shift_right = bitcomp (fun _ik x y -> Ints_t.shift_right x (Ints_t.to_int y)) - - let neg ?no_ov ik = function None -> (None,{underflow=false; overflow=false}) | Some x -> norm ik @@ Some (IArith.neg x) - - let binary_op_with_norm ?no_ov op ik x y = match x, y with - | None, None -> (None, {overflow=false; underflow= false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some x, Some y -> norm ik @@ Some (op x y) - - let add ?no_ov = binary_op_with_norm IArith.add - let mul ?no_ov = binary_op_with_norm IArith.mul - let sub ?no_ov = binary_op_with_norm IArith.sub - - let shift_left ik a b = - match is_bot a, is_bot b with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show a) (show b))) - | _ -> - match a, minimal b, maximal b with - | Some a, Some bl, Some bu when (Ints_t.compare bl Ints_t.zero >= 0) -> - (try - let r = IArith.shift_left a (Ints_t.to_int bl, Ints_t.to_int bu) in - norm ik @@ Some r - with Z.Overflow -> (top_of ik,{underflow=false; overflow=true})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let rem ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (xl, xu), Some (yl, yu) -> - if is_top_of ik x && is_top_of ik y then - (* This is needed to preserve soundness also on things bigger than int32 e.g. *) - (* x: 3803957176L -> T in Interval32 *) - (* y: 4209861404L -> T in Interval32 *) - (* x % y: 3803957176L -> T in Interval32 *) - (* T in Interval32 is [-2147483648,2147483647] *) - (* the code below computes [-2147483647,2147483647] for this though which is unsound *) - top_of ik - else - (* If we have definite values, Ints_t.rem will give a definite result. - * Otherwise we meet with a [range] the result can be in. - * This range is [0, min xu b] if x is positive, and [max xl -b, min xu b] if x can be negative. - * The precise bound b is one smaller than the maximum bound. Negative y give the same result as positive. *) - let pos x = if Ints_t.compare x Ints_t.zero < 0 then Ints_t.neg x else x in - let b = Ints_t.sub (Ints_t.max (pos yl) (pos yu)) Ints_t.one in - let range = if Ints_t.compare xl Ints_t.zero>= 0 then Some (Ints_t.zero, Ints_t.min xu b) else Some (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit (fun _ik -> Ints_t.rem) ik x y) range - - let rec div ?no_ov ik x y = - match x, y with - | None, None -> (bot (),{underflow=false; overflow=false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | (Some (x1,x2) as x), (Some (y1,y2) as y) -> - begin - let is_zero v = Ints_t.compare v Ints_t.zero = 0 in - match y1, y2 with - | l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false}) (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2)) - | _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one))) - | _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false}) - | _ -> binary_op_with_norm IArith.div ik x y - end - - let ne ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik true - else if Ints_t.compare x2 y1 <= 0 && Ints_t.compare y2 x1 <= 0 then - of_bool ik false - else top_bool - - let eq ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 && Ints_t.compare x2 y1 <= 0 then - of_bool ik true - else if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik false - else top_bool - - let ge ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 then of_bool ik true - else if Ints_t.compare x2 y1 < 0 then of_bool ik false - else top_bool - - let le ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 <= 0 then of_bool ik true - else if Ints_t.compare y2 x1 < 0 then of_bool ik false - else top_bool - - let gt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 then of_bool ik true - else if Ints_t.compare x2 y1 <= 0 then of_bool ik false - else top_bool - - let lt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 < 0 then of_bool ik true - else if Ints_t.compare y2 x1 <= 0 then of_bool ik false - else top_bool - - let invariant_ikind e ik = function - | Some (x1, x2) -> - let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in - IntInvariant.of_interval e ik (x1', x2') - | None -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let shrink = function - | Some (l, u) -> (return None) <+> (GobQCheck.shrink pair_arb (l, u) >|= of_interval ik >|= fst) - | None -> empty - in - QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) (fun x -> of_interval ik x |> fst ) pair_arb) - - let modulo n k = - let result = Ints_t.rem n k in - if Ints_t.compare result Ints_t.zero >= 0 then result - else Ints_t.add result k - - let refine_with_congruence ik (intv : t) (cong : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if Ints_t.equal m Ints_t.zero && (Ints_t.compare c x < 0 || Ints_t.compare c y > 0) then None - else if Ints_t.equal m Ints_t.zero then - Some (c, c) - else - let (min_ik, max_ik) = range ik in - let rcx = - if Ints_t.equal x min_ik then x else - Ints_t.add x (modulo (Ints_t.sub c x) (Ints_t.abs m)) in - let lcy = - if Ints_t.equal y max_ik then y else - Ints_t.sub y (modulo (Ints_t.sub y c) (Ints_t.abs m)) in - if Ints_t.compare rcx lcy > 0 then None - else if Ints_t.equal rcx lcy then norm ik @@ Some (rcx, rcx) |> fst - else norm ik @@ Some (rcx, lcy) |> fst - | _ -> None - - let refine_with_congruence ik x y = - let refn = refine_with_congruence ik x y in - if M.tracing then M.trace "refine" "int_refine_with_congruence %a %a -> %a" pretty x pretty y pretty refn; - refn - - let refine_with_interval ik a b = meet ik a b - - let refine_with_excl_list ik (intv : t) (excl : (int_t list * (int64 * int64)) option) : t = - match intv, excl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls, (rl, rh)) -> - let rec shrink op b = - let new_b = (op b (Ints_t.of_int(Bool.to_int(BatList.mem_cmp Ints_t.compare b ls)))) in - if not (Ints_t.equal b new_b) then shrink op new_b else new_b - in - let (min_ik, max_ik) = range ik in - let l' = if Ints_t.equal l min_ik then l else shrink Ints_t.add l in - let u' = if Ints_t.equal u max_ik then u else shrink Ints_t.sub u in - let intv' = norm ik @@ Some (l', u') |> fst in - let range = norm ~suppress_ovwarn:true ik (Some (Ints_t.of_bigint (Size.min_from_bit_range rl), Ints_t.of_bigint (Size.max_from_bit_range rh))) |> fst in - meet ik intv' range - - let refine_with_incl_list ik (intv: t) (incl : (int_t list) option) : t = - match intv, incl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls) -> - let rec min m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> min (Some x) xs | Some m -> if Ints_t.compare m x < 0 then min (Some m) xs else min (Some x) xs in - let rec max m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> max (Some x) xs | Some m -> if Ints_t.compare m x > 0 then max (Some m) xs else max (Some x) xs in - match min None ls, max None ls with - | Some m1, Some m2 -> refine_with_interval ik (Some(l, u)) (Some (m1, m2)) - | _, _-> intv - - let project ik p t = t -end (** IntervalSetFunctor that is not just disjunctive completion of intervals, but attempts to be precise for wraparound arithmetic for unsigned types *) module IntervalSetFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) list = @@ -1581,350 +535,3 @@ struct let shrink xs = GobQCheck.shrink list_pair_arb xs >|= canonize_randomly_generated_list in QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) canonize_randomly_generated_list list_pair_arb) end - -module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct - include D - - let add ?no_ov ik x y = fst @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = fst @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = fst @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = fst @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = fst @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = fst @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = fst @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = fst @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = fst @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = fst @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = fst @@ D.shift_left ik x y - - let shift_right ik x y = fst @@ D.shift_right ik x y -end - -module IntIkind = struct let ikind () = Cil.IInt end -module Interval = IntervalFunctor (IntOps.BigIntOps) -module Interval32 = IntDomWithDefaultIkind (IntDomLifter (SOverflowUnlifter (IntervalFunctor (IntOps.Int64Ops)))) (IntIkind) -module IntervalSet = IntervalSetFunctor (IntOps.BigIntOps) -module Integers (Ints_t : IntOps.IntOps): IkindUnawareS with type t = Ints_t.t and type int_t = Ints_t.t = (* no top/bot, order is <= *) -struct - include Printable.Std - let name () = "integers" - type t = Ints_t.t [@@deriving eq, ord, hash] - type int_t = Ints_t.t - let top () = raise Unknown - let bot () = raise Error - let top_of ik = top () - let bot_of ik = bot () - let show (x: Ints_t.t) = Ints_t.to_string x - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - (* is_top and is_bot are never called, but if they were, the Std impl would raise their exception, so we overwrite them: *) - let is_top _ = false - let is_bot _ = false - - let equal_to i x = if i > x then `Neq else `Top - let leq x y = x <= y - let join x y = if Ints_t.compare x y > 0 then x else y - let widen = join - let meet x y = if Ints_t.compare x y > 0 then y else x - let narrow = meet - - let of_bool x = if x then Ints_t.one else Ints_t.zero - let to_bool' x = x <> Ints_t.zero - let to_bool x = Some (to_bool' x) - let of_int x = x - let to_int x = Some x - - let neg = Ints_t.neg - let add = Ints_t.add (* TODO: signed overflow is undefined behavior! *) - let sub = Ints_t.sub - let mul = Ints_t.mul - let div = Ints_t.div - let rem = Ints_t.rem - let lt n1 n2 = of_bool (n1 < n2) - let gt n1 n2 = of_bool (n1 > n2) - let le n1 n2 = of_bool (n1 <= n2) - let ge n1 n2 = of_bool (n1 >= n2) - let eq n1 n2 = of_bool (n1 = n2) - let ne n1 n2 = of_bool (n1 <> n2) - let lognot = Ints_t.lognot - let logand = Ints_t.logand - let logor = Ints_t.logor - let logxor = Ints_t.logxor - let shift_left n1 n2 = Ints_t.shift_left n1 (Ints_t.to_int n2) - let shift_right n1 n2 = Ints_t.shift_right n1 (Ints_t.to_int n2) - let c_lognot n1 = of_bool (not (to_bool' n1)) - let c_logand n1 n2 = of_bool ((to_bool' n1) && (to_bool' n2)) - let c_logor n1 n2 = of_bool ((to_bool' n1) || (to_bool' n2)) - let cast_to ?(suppress_ovwarn=false) ?torg t x = failwith @@ "Cast_to not implemented for " ^ (name ()) ^ "." - let arbitrary ik = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 (* TODO: use ikind *) - let invariant _ _ = Invariant.none (* TODO *) -end - -module FlatPureIntegers: IkindUnawareS with type t = int64 and type int_t = int64 = (* Integers, but raises Unknown/Error on join/meet *) -struct - include Integers(IntOps.Int64Ops) - let top () = raise Unknown - let bot () = raise Error - let leq = equal - let pretty_diff () (x,y) = Pretty.dprintf "Integer %a instead of %a" pretty x pretty y - let join x y = if equal x y then x else top () - let meet x y = if equal x y then x else bot () -end - -module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) -struct - type int_t = Base.int_t - include Lattice.FlatConf (struct - include Printable.DefaultConf - let top_name = "Unknown int" - let bot_name = "Error int" - end) (Base) - - let top_of ik = top () - let bot_of ik = bot () - - - let name () = "flat integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ikind x = top_of ikind - let ending ?(suppress_ovwarn=false) ikind x = top_of ikind - let maximal x = None - let minimal x = None - - let lift1 f x = match x with - | `Lifted x -> - (try `Lifted (f x) with Unknown -> `Top | Error -> `Bot) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> - (try `Lifted (f x y) with Unknown -> `Top | Error -> `Bot) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) -struct - include Lattice.LiftPO (struct - include Printable.DefaultConf - let top_name = "MaxInt" - let bot_name = "MinInt" - end) (Base) - type int_t = Base.int_t - let top_of ik = top () - let bot_of ik = bot () - include StdTop (struct type nonrec t = t let top_of = top_of end) - - let name () = "lifted integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let lift1 f x = match x with - | `Lifted x -> `Lifted (f x) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> `Lifted (f x y) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Flattened = Flat (Integers (IntOps.Int64Ops)) -module Lifted = Lift (Integers (IntOps.Int64Ops)) - -module Reverse (Base: IkindUnawareS) = -struct - include Base - include (Lattice.Reverse (Base) : Lattice.S with type t := Base.t) -end - -module BISet = struct - include SetDomain.Make (IntOps.BigIntOps) - let is_singleton s = cardinal s = 1 -end - -(* The module [Exclusion] constains common functionality about handling of exclusion sets between [DefExc] and [Enums] *) -module Exclusion = -struct - module R = Interval32 - (* We use these types for the functions in this module to make the intended meaning more explicit *) - type t = Exc of BISet.t * Interval32.t - type inc = Inc of BISet.t [@@unboxed] - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.succ (Z.add (Z.neg (min_of_range r)) (max_of_range r)) - - let cardinality_BISet s = - Z.of_int (BISet.cardinal s) - - let leq_excl_incl (Exc (xs, r)) (Inc ys) = - (* For a <= b to hold, the cardinalities must fit, i.e. |a| <= |b|, which implies |min_r, max_r| - |xs| <= |ys|. We check this first. *) - let lower_bound_cardinality_a = Z.sub (cardinality_of_range r) (cardinality_BISet xs) in - let card_b = cardinality_BISet ys in - if Z.compare lower_bound_cardinality_a card_b > 0 then - false - else (* The cardinality did fit, so we check for all elements that are represented by range r, whether they are in (xs union ys) *) - let min_a = min_of_range r in - let max_a = max_of_range r in - GobZ.for_all_range (fun el -> BISet.mem el xs || BISet.mem el ys) (min_a, max_a) - - let leq (Exc (xs, r)) (Exc (ys, s)) = - let min_a, max_a = min_of_range r, max_of_range r in - let excluded_check = BISet.for_all (fun y -> BISet.mem y xs || Z.compare y min_a < 0 || Z.compare y max_a > 0) ys in (* if true, then the values ys, that are not in b, also do not occur in a *) - if not excluded_check - then false - else begin (* Check whether all elements that are in the range r, but not in s, are in xs, i.e. excluded. *) - if R.leq r s then true - else begin if Z.compare (cardinality_BISet xs) (Z.sub (cardinality_of_range r) (cardinality_of_range s)) >= 0 (* Check whether the number of excluded elements in a is as least as big as |min_r, max_r| - |min_s, max_s| *) - then - let min_b, max_b = min_of_range s, max_of_range s in - let leq1 = (* check whether the elements in [r_l; s_l-1] are all in xs, i.e. excluded *) - if Z.compare min_a min_b < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (min_a, Z.pred min_b) - else - true - in - let leq2 () = (* check whether the elements in [s_u+1; r_u] are all in xs, i.e. excluded *) - if Z.compare max_b max_a < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (Z.succ max_b, max_a) - else - true - in - leq1 && (leq2 ()) - else - false - end - end -end - -module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct - - include D - - let lift v = (v, {overflow=false; underflow=false}) - - let add ?no_ov ik x y = lift @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = lift @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = lift @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = lift @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = lift @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = lift @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = lift @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = lift @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = lift @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = lift @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = lift @@ D.shift_left ik x y - - let shift_right ik x y = lift @@ D.shift_right ik x y - -end From 3720ea2d30ffef85a3344f7ba99e3f860e15f0ab Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:07:58 +0300 Subject: [PATCH 605/689] Remove IntervalSetFunctor from IntDomain0 --- src/cdomain/value/cdomains/intDomain0.ml | 535 ----------------------- 1 file changed, 535 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/intDomain0.ml index 0bcfa6ae44..833de85ee4 100644 --- a/src/cdomain/value/cdomains/intDomain0.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -1047,541 +1047,6 @@ struct let project ik p t = t end -(** IntervalSetFunctor that is not just disjunctive completion of intervals, but attempts to be precise for wraparound arithmetic for unsigned types *) -module IntervalSetFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) list = -struct - - module Interval = IntervalFunctor (Ints_t) - module IArith = IntervalArith (Ints_t) - - - let name () = "interval_sets" - - type int_t = Ints_t.t - - let (>.) a b = Ints_t.compare a b > 0 - let (=.) a b = Ints_t.compare a b = 0 - let (<.) a b = Ints_t.compare a b < 0 - let (>=.) a b = Ints_t.compare a b >= 0 - let (<=.) a b = Ints_t.compare a b <= 0 - let (+.) a b = Ints_t.add a b - let (-.) a b = Ints_t.sub a b - - (* - Each domain's element is guaranteed to be in canonical form. That is, each interval contained - inside the set does not overlap with each other and they are not adjacent. - *) - type t = (Ints_t.t * Ints_t.t) list [@@deriving eq, hash, ord] - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - - let top_of ik = [range ik] - - let bot () = [] - - let bot_of ik = bot () - - let show (x: t) = - let show_interval i = Printf.sprintf "[%s, %s]" (Ints_t.to_string (fst i)) (Ints_t.to_string (snd i)) in - List.fold_left (fun acc i -> (show_interval i) :: acc) [] x |> List.rev |> String.concat ", " |> Printf.sprintf "[%s]" - - (* New type definition for the sweeping line algorithm used for implementing join/meet functions. *) - type event = Enter of Ints_t.t | Exit of Ints_t.t - - let unbox_event = function Enter x -> x | Exit x -> x - - let cmp_events x y = - (* Deliberately comparing ints first => Cannot be derived *) - let res = Ints_t.compare (unbox_event x) (unbox_event y) in - if res <> 0 then res - else - begin - match (x, y) with - | (Enter _, Exit _) -> -1 - | (Exit _, Enter _) -> 1 - | (_, _) -> 0 - end - - let interval_set_to_events (xs: t) = - List.concat_map (fun (a, b) -> [Enter a; Exit b]) xs - - let two_interval_sets_to_events (xs: t) (ys: t) = - let xs = interval_set_to_events xs in - let ys = interval_set_to_events ys in - List.merge cmp_events xs ys - - (* Using the sweeping line algorithm, combined_event_list returns a new event list representing the intervals in which at least n intervals in xs overlap - This function is used for both join and meet operations with different parameter n: 1 for join, 2 for meet *) - let combined_event_list lattice_op (xs:event list) = - let l = match lattice_op with `Join -> 1 | `Meet -> 2 in - let aux (interval_count, acc) = function - | Enter x -> (interval_count + 1, if (interval_count + 1) >= l && interval_count < l then (Enter x)::acc else acc) - | Exit x -> (interval_count - 1, if interval_count >= l && (interval_count - 1) < l then (Exit x)::acc else acc) - in - List.fold_left aux (0, []) xs |> snd |> List.rev - - let rec events_to_intervals = function - | [] -> [] - | (Enter x)::(Exit y)::xs -> (x, y)::(events_to_intervals xs) - | _ -> failwith "Invalid events list" - - let remove_empty_gaps (xs: t) = - let aux acc (l, r) = match acc with - | ((a, b)::acc') when (b +. Ints_t.one) >=. l -> (a, r)::acc' - | _ -> (l, r)::acc - in - List.fold_left aux [] xs |> List.rev - - let canonize (xs: t) = - interval_set_to_events xs |> - List.sort cmp_events |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let unop (x: t) op = match x with - | [] -> [] - | _ -> canonize @@ List.concat_map op x - - let binop (x: t) (y: t) op : t = match x, y with - | [], _ -> [] - | _, [] -> [] - | _, _ -> canonize @@ List.concat_map op (BatList.cartesian_product x y) - - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let minimal = function - | [] -> None - | (x, _)::_ -> Some x - - let maximal = function - | [] -> None - | xs -> Some (BatList.last xs |> snd) - - let equal_to_interval i (a, b) = - if a =. b && b =. i then - `Eq - else if a <=. i && i <=. b then - `Top - else - `Neq - - let equal_to i xs = match List.map (equal_to_interval i) xs with - | [] -> failwith "unsupported: equal_to with bottom" - | [`Eq] -> `Eq - | ys when List.for_all ((=) `Neq) ys -> `Neq - | _ -> `Top - - let norm_interval ?(suppress_ovwarn=false) ?(cast=false) ik (x,y) : t*overflow_info = - if x >. y then - ([],{underflow=false; overflow=false}) - else - let (min_ik, max_ik) = range ik in - let underflow = min_ik >. x in - let overflow = max_ik <. y in - let v = if underflow || overflow then - begin - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (max_ik -. min_ik) in - let resdiff = Ints_t.abs (y -. x) in - if resdiff >. diff then - [range ik] - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if l <=. u then - [(l, u)] - else - (* Interval that wraps around (begins to the right of its end). We CAN represent such intervals *) - [(min_ik, u); (l, max_ik)] - else if not cast && should_ignore_overflow ik then - [Ints_t.max min_ik x, Ints_t.min max_ik y] - else - [range ik] - end - else - [(x,y)] - in - if suppress_ovwarn then (v, {underflow=false; overflow=false}) else (v, {underflow; overflow}) - - let norm_intvs ?(suppress_ovwarn=false) ?(cast=false) (ik:ikind) (xs: t) : t*overflow_info = - let res = List.map (norm_interval ~suppress_ovwarn ~cast ik) xs in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let binary_op_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> [op x y]) (BatList.cartesian_product x y) - - let binary_op_with_ovc (x: t) (y: t) op : t*overflow_info = match x, y with - | [], _ -> ([],{overflow=false; underflow=false}) - | _, [] -> ([],{overflow=false; underflow=false}) - | _, _ -> - let res = List.map op (BatList.cartesian_product x y) in - let intvs = List.concat_map fst res in - let underflow = List.exists (fun (_,{underflow; _}) -> underflow) res in - let overflow = List.exists (fun (_,{overflow; _}) -> underflow) res in - (canonize intvs,{underflow; overflow}) - - let unary_op_with_norm op (ik:ikind) (x: t) = match x with - | [] -> ([],{overflow=false; underflow=false}) - | _ -> norm_intvs ik @@ List.concat_map (fun x -> [op x]) x - - let rec leq (xs: t) (ys: t) = - let leq_interval (al, au) (bl, bu) = al >=. bl && au <=. bu in - match xs, ys with - | [], _ -> true - | _, [] -> false - | (xl,xr)::xs', (yl,yr)::ys' -> - if leq_interval (xl,xr) (yl,yr) then - leq xs' ys - else if xr <. yl then - false - else - leq xs ys' - - let join ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Join |> - events_to_intervals |> - remove_empty_gaps - - let meet ik (x: t) (y: t): t = - two_interval_sets_to_events x y |> - combined_event_list `Meet |> - events_to_intervals - - let to_int = function - | [x] -> IArith.to_int x - | _ -> None - - let zero = [IArith.zero] - let one = [IArith.one] - let top_bool = [IArith.top_bool] - - let not_bool (x:t) = - let is_false x = equal x zero in - let is_true x = equal x one in - if is_true x then zero else if is_false x then one else top_bool - - let to_bool = function - | [(l,u)] when l =. Ints_t.zero && u =. Ints_t.zero -> Some false - | x -> if leq zero x then None else Some true - - let of_bool _ = function true -> one | false -> zero - - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm_interval ~suppress_ovwarn ~cast:false ik (x,y) - - let of_int ik (x: int_t) = of_interval ik (x, x) - - let lt ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <. min_y then - of_bool ik true - else if min_x >=. max_y then - of_bool ik false - else - top_bool - - let le ik x y = - match x, y with - | [], [] -> bot_of ik - | [], _ | _, [] -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | _, _ -> - let (max_x, min_y) = (maximal x |> Option.get, minimal y |> Option.get) in - let (min_x, max_y) = (minimal x |> Option.get, maximal y |> Option.get) in - if max_x <=. min_y then - of_bool ik true - else if min_x >. max_y then - of_bool ik false - else - top_bool - - let gt ik x y = not_bool @@ le ik x y - - let ge ik x y = not_bool @@ lt ik x y - - let eq ik x y = match x, y with - | (a, b)::[], (c, d)::[] when a =. b && c =. d && a =. c -> - one - | _ -> - if is_bot (meet ik x y) then - zero - else - top_bool - - let ne ik x y = not_bool @@ eq ik x y - let interval_to_int i = Interval.to_int (Some i) - let interval_to_bool i = Interval.to_bool (Some i) - - let log f ik (i1, i2) = - match (interval_to_bool i1, interval_to_bool i2) with - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - - let bit f ik (i1, i2) = - match (interval_to_int i1), (interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - - let bitcomp f ik (i1, i2) = - match (interval_to_int i1, interval_to_int i2) with - | Some x, Some y -> (try of_int ik (f x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{overflow=false; underflow=false})) - | _, _ -> (top_of ik,{overflow=false; underflow=false}) - - let logand ik x y = - let interval_logand = bit Ints_t.logand ik in - binop x y interval_logand - - let logor ik x y = - let interval_logor = bit Ints_t.logor ik in - binop x y interval_logor - - let logxor ik x y = - let interval_logxor = bit Ints_t.logxor ik in - binop x y interval_logxor - - let lognot ik x = - let interval_lognot i = - match interval_to_int i with - | Some x -> of_int ik (Ints_t.lognot x) |> fst - | _ -> top_of ik - in - unop x interval_lognot - - let shift_left ik x y = - let interval_shiftleft = bitcomp (fun x y -> Ints_t.shift_left x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftleft - - let shift_right ik x y = - let interval_shiftright = bitcomp (fun x y -> Ints_t.shift_right x (Ints_t.to_int y)) ik in - binary_op_with_ovc x y interval_shiftright - - let c_lognot ik x = - let log1 f ik i1 = - match interval_to_bool i1 with - | Some x -> of_bool ik (f x) - | _ -> top_of ik - in - let interval_lognot = log1 not ik in - unop x interval_lognot - - let c_logand ik x y = - let interval_logand = log (&&) ik in - binop x y interval_logand - - let c_logor ik x y = - let interval_logor = log (||) ik in - binop x y interval_logor - - let add ?no_ov = binary_op_with_norm IArith.add - let sub ?no_ov = binary_op_with_norm IArith.sub - let mul ?no_ov = binary_op_with_norm IArith.mul - let neg ?no_ov = unary_op_with_norm IArith.neg - - let div ?no_ov ik x y = - let rec interval_div x (y1, y2) = begin - let top_of ik = top_of ik |> List.hd in - let is_zero v = v =. Ints_t.zero in - match y1, y2 with - | l, u when is_zero l && is_zero u -> top_of ik (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> interval_div x (Ints_t.one,y2) - | _, u when is_zero u -> interval_div x (y1, Ints_t.(neg one)) - | _ when leq (of_int ik (Ints_t.zero) |> fst) ([(y1,y2)]) -> top_of ik - | _ -> IArith.div x (y1, y2) - end - in binary_op_with_norm interval_div ik x y - - let rem ik x y = - let interval_rem (x, y) = - if Interval.is_top_of ik (Some x) && Interval.is_top_of ik (Some y) then - top_of ik - else - let (xl, xu) = x in let (yl, yu) = y in - let pos x = if x <. Ints_t.zero then Ints_t.neg x else x in - let b = (Ints_t.max (pos yl) (pos yu)) -. Ints_t.one in - let range = if xl >=. Ints_t.zero then (Ints_t.zero, Ints_t.min xu b) else (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit Ints_t.rem ik (x, y)) [range] - in - binop x y interval_rem - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov ik x = norm_intvs ~cast:true ik x - - (* - narrows down the extremeties of xs if they are equal to boundary values of the ikind with (possibly) narrower values from ys - *) - let narrow ik xs ys = match xs ,ys with - | [], _ -> [] | _ ,[] -> xs - | _, _ -> - let min_xs = minimal xs |> Option.get in - let max_xs = maximal xs |> Option.get in - let min_ys = minimal ys |> Option.get in - let max_ys = maximal ys |> Option.get in - let min_range,max_range = range ik in - let threshold = get_interval_threshold_widening () in - let min = if min_xs =. min_range || threshold && min_ys >. min_xs && IArith.is_lower_threshold min_xs then min_ys else min_xs in - let max = if max_xs =. max_range || threshold && max_ys <. max_xs && IArith.is_upper_threshold max_xs then max_ys else max_xs in - xs - |> (function (_, y)::z -> (min, y)::z | _ -> []) - |> List.rev - |> (function (x, _)::z -> (x, max)::z | _ -> []) - |> List.rev - - (* - 1. partitions the intervals of xs by assigning each of them to the an interval in ys that includes it. - and joins all intervals in xs assigned to the same interval in ys as one interval. - 2. checks for every pair of adjacent pairs whether the pairs did approach (if you compare the intervals from xs and ys) and merges them if it is the case. - 3. checks whether partitions at the extremeties are approaching infinity (and expands them to infinity. in that case) - - The expansion (between a pair of adjacent partitions or at extremeties ) stops at a threshold. - *) - let widen ik xs ys = - let (min_ik,max_ik) = range ik in - let threshold = get_bool "ana.int.interval_threshold_widening" in - let upper_threshold (_,u) = IArith.upper_threshold u max_ik in - let lower_threshold (l,_) = IArith.lower_threshold l min_ik in - (*obtain partitioning of xs intervals according to the ys interval that includes them*) - let rec interval_sets_to_partitions (ik: ikind) (acc : (int_t * int_t) option) (xs: t) (ys: t)= - match xs,ys with - | _, [] -> [] - | [], (y::ys) -> (acc,y):: interval_sets_to_partitions ik None [] ys - | (x::xs), (y::ys) when Interval.leq (Some x) (Some y) -> interval_sets_to_partitions ik (Interval.join ik acc (Some x)) xs (y::ys) - | (x::xs), (y::ys) -> (acc,y) :: interval_sets_to_partitions ik None (x::xs) ys - in - let interval_sets_to_partitions ik xs ys = interval_sets_to_partitions ik None xs ys in - (*merge a pair of adjacent partitions*) - let merge_pair ik (a,b) (c,d) = - let new_a = function - | None -> Some (upper_threshold b, upper_threshold b) - | Some (ax,ay) -> Some (ax, upper_threshold b) - in - let new_c = function - | None -> Some (lower_threshold d, lower_threshold d) - | Some (cx,cy) -> Some (lower_threshold d, cy) - in - if threshold && (lower_threshold d +. Ints_t.one) >. (upper_threshold b) then - [(new_a a,(fst b, upper_threshold b)); (new_c c, (lower_threshold d, snd d))] - else - [(Interval.join ik a c, (Interval.join ik (Some b) (Some d) |> Option.get))] - in - let partitions_are_approaching part_left part_right = match part_left, part_right with - | (Some (_, left_x), (_, left_y)), (Some (right_x, _), (right_y, _)) -> (right_x -. left_x) >. (right_y -. left_y) - | _,_ -> false - in - (*merge all approaching pairs of adjacent partitions*) - let rec merge_list ik = function - | [] -> [] - | x::y::xs when partitions_are_approaching x y -> merge_list ik ((merge_pair ik x y) @ xs) - | x::xs -> x :: merge_list ik xs - in - (*expands left extremity*) - let widen_left = function - | [] -> [] - | (None,(lb,rb))::ts -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (None, (lt,rb))::ts - | (Some (la,ra), (lb,rb))::ts when lb <. la -> let lt = if threshold then lower_threshold (lb,lb) else min_ik in (Some (la,ra),(lt,rb))::ts - | x -> x - in - (*expands right extremity*) - let widen_right x = - let map_rightmost = function - | [] -> [] - | (None,(lb,rb))::ts -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (None, (lb,ut))::ts - | (Some (la,ra), (lb,rb))::ts when ra <. rb -> let ut = if threshold then upper_threshold (rb,rb) else max_ik in (Some (la,ra),(lb,ut))::ts - | x -> x - in - List.rev x |> map_rightmost |> List.rev - in - interval_sets_to_partitions ik xs ys |> merge_list ik |> widen_left |> widen_right |> List.map snd - - let starting ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = norm_interval ik ~suppress_ovwarn (fst (range ik), n) - - let invariant_ikind e ik xs = - List.map (fun x -> Interval.invariant_ikind e ik (Some x)) xs |> - let open Invariant in List.fold_left (||) (bot ()) - - let modulo n k = - let result = Ints_t.rem n k in - if result >=. Ints_t.zero then result - else result +. k - - let refine_with_congruence ik (intvs: t) (cong: (int_t * int_t ) option): t = - let refine_with_congruence_interval ik (cong : (int_t * int_t ) option) (intv : (int_t * int_t ) option): t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if m =. Ints_t.zero && (c <. x || c >. y) then [] - else if m =. Ints_t.zero then - [(c, c)] - else - let (min_ik, max_ik) = range ik in - let rcx = - if x =. min_ik then x else - x +. (modulo (c -. x) (Ints_t.abs m)) in - let lcy = - if y =. max_ik then y else - y -. (modulo (y -. c) (Ints_t.abs m)) in - if rcx >. lcy then [] - else if rcx =. lcy then norm_interval ik (rcx, rcx) |> fst - else norm_interval ik (rcx, lcy) |> fst - | _ -> [] - in - List.concat_map (fun x -> refine_with_congruence_interval ik cong (Some x)) intvs - - let refine_with_interval ik xs = function None -> [] | Some (a,b) -> meet ik xs [(a,b)] - - let refine_with_incl_list ik intvs = function - | None -> intvs - | Some xs -> meet ik intvs (List.map (fun x -> (x,x)) xs) - - let excl_range_to_intervalset (ik: ikind) ((min, max): int_t * int_t) (excl: int_t): t = - let intv1 = (min, excl -. Ints_t.one) in - let intv2 = (excl +. Ints_t.one, max) in - norm_intvs ik ~suppress_ovwarn:true [intv1 ; intv2] |> fst - - let of_excl_list ik (excls: int_t list) = - let excl_list = List.map (excl_range_to_intervalset ik (range ik)) excls in - let res = List.fold_left (meet ik) (top_of ik) excl_list in - res - - let refine_with_excl_list ik (intv : t) = function - | None -> intv - | Some (xs, range) -> - let excl_to_intervalset (ik: ikind) ((rl, rh): (int64 * int64)) (excl: int_t): t = - excl_range_to_intervalset ik (Ints_t.of_bigint (Size.min_from_bit_range rl),Ints_t.of_bigint (Size.max_from_bit_range rh)) excl - in - let excl_list = List.map (excl_to_intervalset ik range) xs in - List.fold_left (meet ik) intv excl_list - - let project ik p t = t - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let list_pair_arb = QCheck.small_list pair_arb in - let canonize_randomly_generated_list = (fun x -> norm_intvs ik x |> fst) in - let shrink xs = GobQCheck.shrink list_pair_arb xs >|= canonize_randomly_generated_list - in QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) canonize_randomly_generated_list list_pair_arb) -end - module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct include D From 3b5b9dfdd555f80b2108a15e44c084bb07366023 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:10:16 +0300 Subject: [PATCH 606/689] Rename IntDomain0 -> IntervalDomain for split --- .../value/cdomains/{intDomain0.ml => int/intervalDomain.ml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/cdomain/value/cdomains/{intDomain0.ml => int/intervalDomain.ml} (100%) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/int/intervalDomain.ml similarity index 100% rename from src/cdomain/value/cdomains/intDomain0.ml rename to src/cdomain/value/cdomains/int/intervalDomain.ml From 58725d34b132054a073290f07e6dd59b3049e849 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:10:43 +0300 Subject: [PATCH 607/689] Remove non-IntervalDomain parts --- .../value/cdomains/int/intervalDomain.ml | 983 +----------------- 1 file changed, 1 insertion(+), 982 deletions(-) diff --git a/src/cdomain/value/cdomains/int/intervalDomain.ml b/src/cdomain/value/cdomains/int/intervalDomain.ml index 67d7da2125..eff6bfff3e 100644 --- a/src/cdomain/value/cdomains/int/intervalDomain.ml +++ b/src/cdomain/value/cdomains/int/intervalDomain.ml @@ -1,639 +1,5 @@ -open GobConfig -open GoblintCil -open Pretty -open PrecisionUtil +open IntDomain0 -module M = Messages - -let (%) = Batteries.(%) -let (|?) = Batteries.(|?) - -exception IncompatibleIKinds of string -exception Unknown -exception Error -exception ArithmeticOnIntegerBot of string - - - - -(** Define records that hold mutable variables representing different Configuration values. - * These values are used to keep track of whether or not the corresponding Config values are en-/disabled *) -type ana_int_config_values = { - mutable interval_threshold_widening : bool option; - mutable interval_narrow_by_meet : bool option; - mutable def_exc_widen_by_join : bool option; - mutable interval_threshold_widening_constants : string option; - mutable refinement : string option; -} - -let ana_int_config: ana_int_config_values = { - interval_threshold_widening = None; - interval_narrow_by_meet = None; - def_exc_widen_by_join = None; - interval_threshold_widening_constants = None; - refinement = None; -} - -let get_interval_threshold_widening () = - if ana_int_config.interval_threshold_widening = None then - ana_int_config.interval_threshold_widening <- Some (get_bool "ana.int.interval_threshold_widening"); - Option.get ana_int_config.interval_threshold_widening - -let get_interval_narrow_by_meet () = - if ana_int_config.interval_narrow_by_meet = None then - ana_int_config.interval_narrow_by_meet <- Some (get_bool "ana.int.interval_narrow_by_meet"); - Option.get ana_int_config.interval_narrow_by_meet - -let get_def_exc_widen_by_join () = - if ana_int_config.def_exc_widen_by_join = None then - ana_int_config.def_exc_widen_by_join <- Some (get_bool "ana.int.def_exc_widen_by_join"); - Option.get ana_int_config.def_exc_widen_by_join - -let get_interval_threshold_widening_constants () = - if ana_int_config.interval_threshold_widening_constants = None then - ana_int_config.interval_threshold_widening_constants <- Some (get_string "ana.int.interval_threshold_widening_constants"); - Option.get ana_int_config.interval_threshold_widening_constants - -let get_refinement () = - if ana_int_config.refinement = None then - ana_int_config.refinement <- Some (get_string "ana.int.refinement"); - Option.get ana_int_config.refinement - - - -(** Whether for a given ikind, we should compute with wrap-around arithmetic. - * Always for unsigned types, for signed types if 'sem.int.signed_overflow' is 'assume_wraparound' *) -let should_wrap ik = not (Cil.isSigned ik) || get_string "sem.int.signed_overflow" = "assume_wraparound" - -(** Whether for a given ikind, we should assume there are no overflows. - * Always false for unsigned types, true for signed types if 'sem.int.signed_overflow' is 'assume_none' *) -let should_ignore_overflow ik = Cil.isSigned ik && get_string "sem.int.signed_overflow" = "assume_none" - -let widening_thresholds = ResettableLazy.from_fun WideningThresholds.thresholds -let widening_thresholds_desc = ResettableLazy.from_fun (List.rev % WideningThresholds.thresholds) - -type overflow_info = { overflow: bool; underflow: bool;} - -let set_overflow_flag ~cast ~underflow ~overflow ik = - if !AnalysisState.executing_speculative_computations then - (* Do not produce warnings when the operations are not actually happening in code *) - () - else - let signed = Cil.isSigned ik in - if !AnalysisState.postsolving && signed && not cast then - AnalysisState.svcomp_may_overflow := true; - let sign = if signed then "Signed" else "Unsigned" in - match underflow, overflow with - | true, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190; CWE 191] "%s integer overflow and underflow" sign - | true, false -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 191] "%s integer underflow" sign - | false, true -> - M.warn ~category:M.Category.Integer.overflow ~tags:[CWE 190] "%s integer overflow" sign - | false, false -> assert false - -let reset_lazy () = - ResettableLazy.reset widening_thresholds; - ResettableLazy.reset widening_thresholds_desc; - ana_int_config.interval_threshold_widening <- None; - ana_int_config.interval_narrow_by_meet <- None; - ana_int_config.def_exc_widen_by_join <- None; - ana_int_config.interval_threshold_widening_constants <- None; - ana_int_config.refinement <- None - -module type Arith = -sig - type t - val neg: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div: t -> t -> t - val rem: t -> t -> t - - val lt: t -> t -> t - val gt: t -> t -> t - val le: t -> t -> t - val ge: t -> t -> t - val eq: t -> t -> t - val ne: t -> t -> t - - val lognot: t -> t - val logand: t -> t -> t - val logor : t -> t -> t - val logxor: t -> t -> t - - val shift_left : t -> t -> t - val shift_right: t -> t -> t - - val c_lognot: t -> t - val c_logand: t -> t -> t - val c_logor : t -> t -> t - -end - -module type ArithIkind = -sig - type t - val neg: Cil.ikind -> t -> t - val add: Cil.ikind -> t -> t -> t - val sub: Cil.ikind -> t -> t -> t - val mul: Cil.ikind -> t -> t -> t - val div: Cil.ikind -> t -> t -> t - val rem: Cil.ikind -> t -> t -> t - - val lt: Cil.ikind -> t -> t -> t - val gt: Cil.ikind -> t -> t -> t - val le: Cil.ikind -> t -> t -> t - val ge: Cil.ikind -> t -> t -> t - val eq: Cil.ikind -> t -> t -> t - val ne: Cil.ikind -> t -> t -> t - - val lognot: Cil.ikind -> t -> t - val logand: Cil.ikind -> t -> t -> t - val logor : Cil.ikind -> t -> t -> t - val logxor: Cil.ikind -> t -> t -> t - - val shift_left : Cil.ikind -> t -> t -> t - val shift_right: Cil.ikind -> t -> t -> t - - val c_lognot: Cil.ikind -> t -> t - val c_logand: Cil.ikind -> t -> t -> t - val c_logor : Cil.ikind -> t -> t -> t - -end - -(* Shared functions between S and Z *) -module type B = -sig - include Lattice.S - type int_t - val bot_of: Cil.ikind -> t - val top_of: Cil.ikind -> t - val to_int: t -> int_t option - val equal_to: int_t -> t -> [`Eq | `Neq | `Top] - - val to_bool: t -> bool option - val to_excl_list: t -> (int_t list * (int64 * int64)) option - val of_excl_list: Cil.ikind -> int_t list -> t - val is_excl_list: t -> bool - - val to_incl_list: t -> int_t list option - - val maximal : t -> int_t option - val minimal : t -> int_t option - - val cast_to: ?suppress_ovwarn:bool -> ?torg:Cil.typ -> Cil.ikind -> t -> t -end - -(** Interface of IntDomain implementations that do not take ikinds for arithmetic operations yet. TODO: Should be ported to S in the future. *) -module type IkindUnawareS = -sig - include B - include Arith with type t := t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: int_t -> t - val of_bool: bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val arbitrary: unit -> t QCheck.arbitrary - val invariant: Cil.exp -> t -> Invariant.t -end - -(** Interface of IntDomain implementations taking an ikind for arithmetic operations *) -module type S = -sig - include B - include ArithIkind with type t:= t - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t - val neg : ?no_ov:bool -> Cil.ikind -> t -> t - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t - - val join: Cil.ikind -> t -> t -> t - val meet: Cil.ikind -> t -> t -> t - val narrow: Cil.ikind -> t -> t -> t - val widen: Cil.ikind -> t -> t -> t - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - val is_top_of: Cil.ikind -> t -> bool - val invariant_ikind : Cil.exp -> Cil.ikind -> t -> Invariant.t - - val refine_with_congruence: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_interval: Cil.ikind -> t -> (int_t * int_t) option -> t - val refine_with_excl_list: Cil.ikind -> t -> (int_t list * (int64 * int64)) option -> t - val refine_with_incl_list: Cil.ikind -> t -> int_t list option -> t - - val project: Cil.ikind -> int_precision -> t -> t - val arbitrary: Cil.ikind -> t QCheck.arbitrary -end - -module type SOverflow = -sig - - include S - - val add : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val sub : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val mul : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val div : ?no_ov:bool -> Cil.ikind -> t -> t -> t * overflow_info - - val neg : ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val cast_to : ?suppress_ovwarn:bool -> ?torg:Cil.typ -> ?no_ov:bool -> Cil.ikind -> t -> t * overflow_info - - val of_int : Cil.ikind -> int_t -> t * overflow_info - - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t * overflow_info - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t * overflow_info - - val shift_left : Cil.ikind -> t -> t -> t * overflow_info - - val shift_right : Cil.ikind -> t -> t -> t * overflow_info -end - -module type Y = -sig - (* include B *) - include B - include Arith with type t:= t - val of_int: Cil.ikind -> int_t -> t - val of_bool: Cil.ikind -> bool -> t - val of_interval: ?suppress_ovwarn:bool -> Cil.ikind -> int_t * int_t -> t - val of_congruence: Cil.ikind -> int_t * int_t -> t - - val starting : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val ending : ?suppress_ovwarn:bool -> Cil.ikind -> int_t -> t - val is_top_of: Cil.ikind -> t -> bool - - val project: int_precision -> t -> t - val invariant: Cil.exp -> t -> Invariant.t -end - -module type Z = Y with type int_t = Z.t - - -module IntDomLifter (I : S) = -struct - open Cil - type int_t = I.int_t - type t = { v : I.t; ikind : CilType.Ikind.t } [@@deriving eq, ord, hash] - - let ikind {ikind; _} = ikind - - (* Helper functions *) - let check_ikinds x y = if x.ikind <> y.ikind then raise (IncompatibleIKinds (GobPretty.sprintf "ikinds %a and %a are incompatible. Values: %a and %a" CilType.Ikind.pretty x.ikind CilType.Ikind.pretty y.ikind I.pretty x.v I.pretty y.v)) - let lift op x = {x with v = op x.ikind x.v } - (* For logical operations the result is of type int *) - let lift_logical op x = {v = op x.ikind x.v; ikind = Cil.IInt} - let lift2 op x y = check_ikinds x y; {x with v = op x.ikind x.v y.v } - let lift2_cmp op x y = check_ikinds x y; {v = op x.ikind x.v y.v; ikind = Cil.IInt} - - let bot_of ikind = { v = I.bot_of ikind; ikind} - let bot () = failwith "bot () is not implemented for IntDomLifter." - let is_bot x = I.is_bot x.v - let top_of ikind = { v = I.top_of ikind; ikind} - let top () = failwith "top () is not implemented for IntDomLifter." - let is_top x = I.is_top x.v - - (* Leq does not check for ikind, because it is used in invariant with arguments of different type. - TODO: check ikinds here and fix invariant to work with right ikinds *) - let leq x y = I.leq x.v y.v - let join = lift2 I.join - let meet = lift2 I.meet - let widen = lift2 I.widen - let narrow = lift2 I.narrow - - let show x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - "⊤" - else - I.show x.v (* TODO add ikind to output *) - let pretty () x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - Pretty.text "⊤" - else - I.pretty () x.v (* TODO add ikind to output *) - let pretty_diff () (x, y) = I.pretty_diff () (x.v, y.v) (* TODO check ikinds, add them to output *) - let printXml o x = - if not (GobConfig.get_bool "dbg.full-output") && I.is_top_of x.ikind x.v then - BatPrintf.fprintf o "\n\n⊤\n\n\n" - else - I.printXml o x.v (* TODO add ikind to output *) - (* This is for debugging *) - let name () = "IntDomLifter(" ^ (I.name ()) ^ ")" - let to_yojson x = I.to_yojson x.v - let invariant e x = - let e' = Cilfacade.mkCast ~e ~newt:(TInt (x.ikind, [])) in - I.invariant_ikind e' x.ikind x.v - let tag x = I.tag x.v - let arbitrary ik = failwith @@ "Arbitrary not implement for " ^ (name ()) ^ "." - let to_int x = I.to_int x.v - let of_int ikind x = { v = I.of_int ikind x; ikind} - let equal_to i x = I.equal_to i x.v - let to_bool x = I.to_bool x.v - let of_bool ikind b = { v = I.of_bool ikind b; ikind} - let to_excl_list x = I.to_excl_list x.v - let of_excl_list ikind is = {v = I.of_excl_list ikind is; ikind} - let is_excl_list x = I.is_excl_list x.v - let to_incl_list x = I.to_incl_list x.v - let of_interval ?(suppress_ovwarn=false) ikind (lb,ub) = {v = I.of_interval ~suppress_ovwarn ikind (lb,ub); ikind} - let of_congruence ikind (c,m) = {v = I.of_congruence ikind (c,m); ikind} - let starting ?(suppress_ovwarn=false) ikind i = {v = I.starting ~suppress_ovwarn ikind i; ikind} - let ending ?(suppress_ovwarn=false) ikind i = {v = I.ending ~suppress_ovwarn ikind i; ikind} - let maximal x = I.maximal x.v - let minimal x = I.minimal x.v - - let neg = lift I.neg - let add = lift2 I.add - let sub = lift2 I.sub - let mul = lift2 I.mul - let div = lift2 I.div - let rem = lift2 I.rem - let lt = lift2_cmp I.lt - let gt = lift2_cmp I.gt - let le = lift2_cmp I.le - let ge = lift2_cmp I.ge - let eq = lift2_cmp I.eq - let ne = lift2_cmp I.ne - let lognot = lift I.lognot - let logand = lift2 I.logand - let logor = lift2 I.logor - let logxor = lift2 I.logxor - let shift_left x y = {x with v = I.shift_left x.ikind x.v y.v } (* TODO check ikinds*) - let shift_right x y = {x with v = I.shift_right x.ikind x.v y.v } (* TODO check ikinds*) - let c_lognot = lift_logical I.c_lognot - let c_logand = lift2 I.c_logand - let c_logor = lift2 I.c_logor - - let cast_to ?(suppress_ovwarn=false) ?torg ikind x = {v = I.cast_to ~suppress_ovwarn ~torg:(TInt(x.ikind,[])) ikind x.v; ikind} - - let is_top_of ik x = ik = x.ikind && I.is_top_of ik x.v - - let relift x = { v = I.relift x.v; ikind = x.ikind } - - let project p v = { v = I.project v.ikind p v.v; ikind = v.ikind } -end - -module type Ikind = -sig - val ikind: unit -> Cil.ikind -end - -module PtrDiffIkind : Ikind = -struct - let ikind = Cilfacade.ptrdiff_ikind -end - -module IntDomWithDefaultIkind (I: Y) (Ik: Ikind) : Y with type t = I.t and type int_t = I.int_t = -struct - include I - let top () = I.top_of (Ik.ikind ()) - let bot () = I.bot_of (Ik.ikind ()) -end - -module Size = struct (* size in bits as int, range as int64 *) - open Cil - let sign x = if Z.compare x Z.zero < 0 then `Signed else `Unsigned - - let top_typ = TInt (ILongLong, []) - let min_for x = intKindForValue x (sign x = `Unsigned) - let bit = function (* bits needed for representation *) - | IBool -> 1 - | ik -> bytesSizeOfInt ik * 8 - let is_int64_big_int x = Z.fits_int64 x - let card ik = (* cardinality *) - let b = bit ik in - Z.shift_left Z.one b - let bits ik = (* highest bits for neg/pos values *) - let s = bit ik in - if isSigned ik then s-1, s-1 else 0, s - let bits_i64 ik = BatTuple.Tuple2.mapn Int64.of_int (bits ik) - let range ik = - let a,b = bits ik in - let x = if isSigned ik then Z.neg (Z.shift_left Z.one a) (* -2^a *) else Z.zero in - let y = Z.pred (Z.shift_left Z.one b) in (* 2^b - 1 *) - x,y - - let is_cast_injective ~from_type ~to_type = - let (from_min, from_max) = range (Cilfacade.get_ikind from_type) in - let (to_min, to_max) = range (Cilfacade.get_ikind to_type) in - if M.tracing then M.trace "int" "is_cast_injective %a (%a, %a) -> %a (%a, %a)" CilType.Typ.pretty from_type GobZ.pretty from_min GobZ.pretty from_max CilType.Typ.pretty to_type GobZ.pretty to_min GobZ.pretty to_max; - Z.compare to_min from_min <= 0 && Z.compare from_max to_max <= 0 - - let cast t x = (* TODO: overflow is implementation-dependent! *) - if t = IBool then - (* C11 6.3.1.2 Boolean type *) - if Z.equal x Z.zero then Z.zero else Z.one - else - let a,b = range t in - let c = card t in - let y = Z.erem x c in - let y = if Z.gt y b then Z.sub y c - else if Z.lt y a then Z.add y c - else y - in - if M.tracing then M.tracel "cast" "Cast %a to range [%a, %a] (%a) = %a (%s in int64)" GobZ.pretty x GobZ.pretty a GobZ.pretty b GobZ.pretty c GobZ.pretty y (if is_int64_big_int y then "fits" else "does not fit"); - y - - let min_range_sign_agnostic x = - let size ik = - let a,b = bits_i64 ik in - Int64.neg a,b - in - if sign x = `Signed then - size (min_for x) - else - let a, b = size (min_for x) in - if b <= 64L then - let upper_bound_less = Int64.sub b 1L in - let max_one_less = Z.(pred @@ shift_left Z.one (Int64.to_int upper_bound_less)) in - if x <= max_one_less then - a, upper_bound_less - else - a,b - else - a, b - - (* From the number of bits used to represent a positive value, determines the maximal representable value *) - let max_from_bit_range pos_bits = Z.(pred @@ shift_left Z.one (to_int (Z.of_int64 pos_bits))) - - (* From the number of bits used to represent a non-positive value, determines the minimal representable value *) - let min_from_bit_range neg_bits = Z.(if neg_bits = 0L then Z.zero else neg @@ shift_left Z.one (to_int (neg (Z.of_int64 neg_bits)))) - -end - - -module StdTop (B: sig type t val top_of: Cil.ikind -> t end) = struct - open B - (* these should be overwritten for better precision if possible: *) - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ik x = top_of ik - let ending ?(suppress_ovwarn=false) ik x = top_of ik - let maximal x = None - let minimal x = None -end - -module Std (B: sig - type t - val name: unit -> string - val top_of: Cil.ikind -> t - val bot_of: Cil.ikind -> t - val show: t -> string - val equal: t -> t -> bool - end) = struct - include Printable.StdLeaf - let name = B.name (* overwrite the one from Printable.Std *) - open B - let is_top x = failwith "is_top not implemented for IntDomain.Std" - let is_bot x = B.equal x (bot_of Cil.IInt) (* Here we assume that the representation of bottom is independent of the ikind - This may be true for intdomain implementations, but not e.g. for IntDomLifter. *) - let is_top_of ik x = B.equal x (top_of ik) - - (* all output is based on B.show *) - include Printable.SimpleShow ( - struct - type nonrec t = t - let show = show - end - ) - let pretty_diff () (x,y) = dprintf "%s: %a instead of %a" (name ()) pretty x pretty y - - include StdTop (B) -end - -(* Textbook interval arithmetic, without any overflow handling etc. *) -module IntervalArith (Ints_t : IntOps.IntOps) = struct - let min4 a b c d = Ints_t.min (Ints_t.min a b) (Ints_t.min c d) - let max4 a b c d = Ints_t.max (Ints_t.max a b) (Ints_t.max c d) - - let mul (x1, x2) (y1, y2) = - let x1y1 = (Ints_t.mul x1 y1) in - let x1y2 = (Ints_t.mul x1 y2) in - let x2y1 = (Ints_t.mul x2 y1) in - let x2y2 = (Ints_t.mul x2 y2) in - (min4 x1y1 x1y2 x2y1 x2y2, max4 x1y1 x1y2 x2y1 x2y2) - - let shift_left (x1,x2) (y1,y2) = - let y1p = Ints_t.shift_left Ints_t.one y1 in - let y2p = Ints_t.shift_left Ints_t.one y2 in - mul (x1, x2) (y1p, y2p) - - let div (x1, x2) (y1, y2) = - let x1y1n = (Ints_t.div x1 y1) in - let x1y2n = (Ints_t.div x1 y2) in - let x2y1n = (Ints_t.div x2 y1) in - let x2y2n = (Ints_t.div x2 y2) in - let x1y1p = (Ints_t.div x1 y1) in - let x1y2p = (Ints_t.div x1 y2) in - let x2y1p = (Ints_t.div x2 y1) in - let x2y2p = (Ints_t.div x2 y2) in - (min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p) - - let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2) - let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1) - - let neg (x1, x2) = (Ints_t.neg x2, Ints_t.neg x1) - - let one = (Ints_t.one, Ints_t.one) - let zero = (Ints_t.zero, Ints_t.zero) - let top_bool = (Ints_t.zero, Ints_t.one) - - let to_int (x1, x2) = - if Ints_t.equal x1 x2 then Some x1 else None - - let upper_threshold u max_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - let max_ik' = Ints_t.to_bigint max_ik in - let t = List.find_opt (fun x -> Z.compare u x <= 0 && Z.compare x max_ik' <= 0) ts in - BatOption.map_default Ints_t.of_bigint max_ik t - let lower_threshold l min_ik = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - let min_ik' = Ints_t.to_bigint min_ik in - let t = List.find_opt (fun x -> Z.compare l x >= 0 && Z.compare x min_ik' >= 0) ts in - BatOption.map_default Ints_t.of_bigint min_ik t - let is_upper_threshold u = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.upper_thresholds () else ResettableLazy.force widening_thresholds in - let u = Ints_t.to_bigint u in - List.exists (Z.equal u) ts - let is_lower_threshold l = - let ts = if get_interval_threshold_widening_constants () = "comparisons" then WideningThresholds.lower_thresholds () else ResettableLazy.force widening_thresholds_desc in - let l = Ints_t.to_bigint l in - List.exists (Z.equal l) ts -end - -module IntInvariant = -struct - let of_int e ik x = - if get_bool "witness.invariant.exact" then - Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) - else - Invariant.none - - let of_incl_list e ik ps = - match ps with - | [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") -> - assert (List.mem Z.zero ps); - assert (List.mem Z.one ps); - Invariant.none - | [_] when get_bool "witness.invariant.exact" -> - Invariant.none - | _ :: _ :: _ - | [_] | [] -> - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in - Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) (Invariant.bot ()) ps - - let of_interval_opt e ik = function - | (Some x1, Some x2) when Z.equal x1 x2 -> - of_int e ik x1 - | x1_opt, x2_opt -> - let (min_ik, max_ik) = Size.range ik in - let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in - let i1 = - match x1_opt, inexact_type_bounds with - | Some x1, false when Z.equal min_ik x1 -> Invariant.none - | Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType)) - | None, _ -> Invariant.none - in - let i2 = - match x2_opt, inexact_type_bounds with - | Some x2, false when Z.equal x2 max_ik -> Invariant.none - | Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType)) - | None, _ -> Invariant.none - in - Invariant.(i1 && i2) - - let of_interval e ik (x1, x2) = - of_interval_opt e ik (Some x1, Some x2) - - let of_excl_list e ik ns = - List.fold_left (fun a x -> - let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in - Invariant.(a && i) - ) (Invariant.top ()) ns -end module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = struct @@ -1046,350 +412,3 @@ struct let project ik p t = t end - -module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct - include D - - let add ?no_ov ik x y = fst @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = fst @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = fst @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = fst @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = fst @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = fst @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = fst @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = fst @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = fst @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = fst @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = fst @@ D.shift_left ik x y - - let shift_right ik x y = fst @@ D.shift_right ik x y -end - -module IntIkind = struct let ikind () = Cil.IInt end -module Interval = IntervalFunctor (IntOps.BigIntOps) -module Interval32 = IntDomWithDefaultIkind (IntDomLifter (SOverflowUnlifter (IntervalFunctor (IntOps.Int64Ops)))) (IntIkind) - -module Integers (Ints_t : IntOps.IntOps): IkindUnawareS with type t = Ints_t.t and type int_t = Ints_t.t = (* no top/bot, order is <= *) -struct - include Printable.Std - let name () = "integers" - type t = Ints_t.t [@@deriving eq, ord, hash] - type int_t = Ints_t.t - let top () = raise Unknown - let bot () = raise Error - let top_of ik = top () - let bot_of ik = bot () - let show (x: Ints_t.t) = Ints_t.to_string x - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - (* is_top and is_bot are never called, but if they were, the Std impl would raise their exception, so we overwrite them: *) - let is_top _ = false - let is_bot _ = false - - let equal_to i x = if i > x then `Neq else `Top - let leq x y = x <= y - let join x y = if Ints_t.compare x y > 0 then x else y - let widen = join - let meet x y = if Ints_t.compare x y > 0 then y else x - let narrow = meet - - let of_bool x = if x then Ints_t.one else Ints_t.zero - let to_bool' x = x <> Ints_t.zero - let to_bool x = Some (to_bool' x) - let of_int x = x - let to_int x = Some x - - let neg = Ints_t.neg - let add = Ints_t.add (* TODO: signed overflow is undefined behavior! *) - let sub = Ints_t.sub - let mul = Ints_t.mul - let div = Ints_t.div - let rem = Ints_t.rem - let lt n1 n2 = of_bool (n1 < n2) - let gt n1 n2 = of_bool (n1 > n2) - let le n1 n2 = of_bool (n1 <= n2) - let ge n1 n2 = of_bool (n1 >= n2) - let eq n1 n2 = of_bool (n1 = n2) - let ne n1 n2 = of_bool (n1 <> n2) - let lognot = Ints_t.lognot - let logand = Ints_t.logand - let logor = Ints_t.logor - let logxor = Ints_t.logxor - let shift_left n1 n2 = Ints_t.shift_left n1 (Ints_t.to_int n2) - let shift_right n1 n2 = Ints_t.shift_right n1 (Ints_t.to_int n2) - let c_lognot n1 = of_bool (not (to_bool' n1)) - let c_logand n1 n2 = of_bool ((to_bool' n1) && (to_bool' n2)) - let c_logor n1 n2 = of_bool ((to_bool' n1) || (to_bool' n2)) - let cast_to ?(suppress_ovwarn=false) ?torg t x = failwith @@ "Cast_to not implemented for " ^ (name ()) ^ "." - let arbitrary ik = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 (* TODO: use ikind *) - let invariant _ _ = Invariant.none (* TODO *) -end - -module FlatPureIntegers: IkindUnawareS with type t = int64 and type int_t = int64 = (* Integers, but raises Unknown/Error on join/meet *) -struct - include Integers(IntOps.Int64Ops) - let top () = raise Unknown - let bot () = raise Error - let leq = equal - let pretty_diff () (x,y) = Pretty.dprintf "Integer %a instead of %a" pretty x pretty y - let join x y = if equal x y then x else top () - let meet x y = if equal x y then x else bot () -end - -module Flat (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Lift, but goes to `Top/`Bot if Base raises Unknown/Error *) -struct - type int_t = Base.int_t - include Lattice.FlatConf (struct - include Printable.DefaultConf - let top_name = "Unknown int" - let bot_name = "Error int" - end) (Base) - - let top_of ik = top () - let bot_of ik = bot () - - - let name () = "flat integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let to_excl_list x = None - let of_excl_list ik x = top_of ik - let is_excl_list x = false - let to_incl_list x = None - let of_interval ?(suppress_ovwarn=false) ik x = top_of ik - let of_congruence ik x = top_of ik - let starting ?(suppress_ovwarn=false) ikind x = top_of ikind - let ending ?(suppress_ovwarn=false) ikind x = top_of ikind - let maximal x = None - let minimal x = None - - let lift1 f x = match x with - | `Lifted x -> - (try `Lifted (f x) with Unknown -> `Top | Error -> `Bot) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> - (try `Lifted (f x y) with Unknown -> `Top | Error -> `Bot) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Lift (Base: IkindUnawareS): IkindUnawareS with type t = [ `Bot | `Lifted of Base.t | `Top ] and type int_t = Base.int_t = (* identical to Flat, but does not go to `Top/Bot` if Base raises Unknown/Error *) -struct - include Lattice.LiftPO (struct - include Printable.DefaultConf - let top_name = "MaxInt" - let bot_name = "MinInt" - end) (Base) - type int_t = Base.int_t - let top_of ik = top () - let bot_of ik = bot () - include StdTop (struct type nonrec t = t let top_of = top_of end) - - let name () = "lifted integers" - let cast_to ?(suppress_ovwarn=false) ?torg t = function - | `Lifted x -> `Lifted (Base.cast_to t x) - | x -> x - - let equal_to i = function - | `Bot -> failwith "unsupported: equal_to with bottom" - | `Top -> `Top - | `Lifted x -> Base.equal_to i x - - let of_int x = `Lifted (Base.of_int x) - let to_int x = match x with - | `Lifted x -> Base.to_int x - | _ -> None - - let of_bool x = `Lifted (Base.of_bool x) - let to_bool x = match x with - | `Lifted x -> Base.to_bool x - | _ -> None - - let lift1 f x = match x with - | `Lifted x -> `Lifted (f x) - | x -> x - let lift2 f x y = match x,y with - | `Lifted x, `Lifted y -> `Lifted (f x y) - | `Bot, `Bot -> `Bot - | _ -> `Top - - let neg = lift1 Base.neg - let add = lift2 Base.add - let sub = lift2 Base.sub - let mul = lift2 Base.mul - let div = lift2 Base.div - let rem = lift2 Base.rem - let lt = lift2 Base.lt - let gt = lift2 Base.gt - let le = lift2 Base.le - let ge = lift2 Base.ge - let eq = lift2 Base.eq - let ne = lift2 Base.ne - let lognot = lift1 Base.lognot - let logand = lift2 Base.logand - let logor = lift2 Base.logor - let logxor = lift2 Base.logxor - let shift_left = lift2 Base.shift_left - let shift_right = lift2 Base.shift_right - let c_lognot = lift1 Base.c_lognot - let c_logand = lift2 Base.c_logand - let c_logor = lift2 Base.c_logor - - let invariant e = function - | `Lifted x -> Base.invariant e x - | `Top | `Bot -> Invariant.none -end - -module Flattened = Flat (Integers (IntOps.Int64Ops)) -module Lifted = Lift (Integers (IntOps.Int64Ops)) - -module Reverse (Base: IkindUnawareS) = -struct - include Base - include (Lattice.Reverse (Base) : Lattice.S with type t := Base.t) -end - -module BISet = struct - include SetDomain.Make (IntOps.BigIntOps) - let is_singleton s = cardinal s = 1 -end - -(* The module [Exclusion] constains common functionality about handling of exclusion sets between [DefExc] and [Enums] *) -module Exclusion = -struct - module R = Interval32 - (* We use these types for the functions in this module to make the intended meaning more explicit *) - type t = Exc of BISet.t * Interval32.t - type inc = Inc of BISet.t [@@unboxed] - let max_of_range r = Size.max_from_bit_range (Option.get (R.maximal r)) - let min_of_range r = Size.min_from_bit_range (Option.get (R.minimal r)) - let cardinality_of_range r = Z.succ (Z.add (Z.neg (min_of_range r)) (max_of_range r)) - - let cardinality_BISet s = - Z.of_int (BISet.cardinal s) - - let leq_excl_incl (Exc (xs, r)) (Inc ys) = - (* For a <= b to hold, the cardinalities must fit, i.e. |a| <= |b|, which implies |min_r, max_r| - |xs| <= |ys|. We check this first. *) - let lower_bound_cardinality_a = Z.sub (cardinality_of_range r) (cardinality_BISet xs) in - let card_b = cardinality_BISet ys in - if Z.compare lower_bound_cardinality_a card_b > 0 then - false - else (* The cardinality did fit, so we check for all elements that are represented by range r, whether they are in (xs union ys) *) - let min_a = min_of_range r in - let max_a = max_of_range r in - GobZ.for_all_range (fun el -> BISet.mem el xs || BISet.mem el ys) (min_a, max_a) - - let leq (Exc (xs, r)) (Exc (ys, s)) = - let min_a, max_a = min_of_range r, max_of_range r in - let excluded_check = BISet.for_all (fun y -> BISet.mem y xs || Z.compare y min_a < 0 || Z.compare y max_a > 0) ys in (* if true, then the values ys, that are not in b, also do not occur in a *) - if not excluded_check - then false - else begin (* Check whether all elements that are in the range r, but not in s, are in xs, i.e. excluded. *) - if R.leq r s then true - else begin if Z.compare (cardinality_BISet xs) (Z.sub (cardinality_of_range r) (cardinality_of_range s)) >= 0 (* Check whether the number of excluded elements in a is as least as big as |min_r, max_r| - |min_s, max_s| *) - then - let min_b, max_b = min_of_range s, max_of_range s in - let leq1 = (* check whether the elements in [r_l; s_l-1] are all in xs, i.e. excluded *) - if Z.compare min_a min_b < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (min_a, Z.pred min_b) - else - true - in - let leq2 () = (* check whether the elements in [s_u+1; r_u] are all in xs, i.e. excluded *) - if Z.compare max_b max_a < 0 then - GobZ.for_all_range (fun x -> BISet.mem x xs) (Z.succ max_b, max_a) - else - true - in - leq1 && (leq2 ()) - else - false - end - end -end - -module SOverflowLifter (D : S) : SOverflow with type int_t = D.int_t and type t = D.t = struct - - include D - - let lift v = (v, {overflow=false; underflow=false}) - - let add ?no_ov ik x y = lift @@ D.add ?no_ov ik x y - - let sub ?no_ov ik x y = lift @@ D.sub ?no_ov ik x y - - let mul ?no_ov ik x y = lift @@ D.mul ?no_ov ik x y - - let div ?no_ov ik x y = lift @@ D.div ?no_ov ik x y - - let neg ?no_ov ik x = lift @@ D.neg ?no_ov ik x - - let cast_to ?suppress_ovwarn ?torg ?no_ov ik x = lift @@ D.cast_to ?suppress_ovwarn ?torg ?no_ov ik x - - let of_int ik x = lift @@ D.of_int ik x - - let of_interval ?suppress_ovwarn ik x = lift @@ D.of_interval ?suppress_ovwarn ik x - - let starting ?suppress_ovwarn ik x = lift @@ D.starting ?suppress_ovwarn ik x - - let ending ?suppress_ovwarn ik x = lift @@ D.ending ?suppress_ovwarn ik x - - let shift_left ik x y = lift @@ D.shift_left ik x y - - let shift_right ik x y = lift @@ D.shift_right ik x y - -end From 127603f4cf2c71bbc833df3932ee69d24b6bb914 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:11:08 +0300 Subject: [PATCH 608/689] Remove IntervalFunctor from IntDomain0 --- src/cdomain/value/cdomains/intDomain0.ml | 412 ----------------------- 1 file changed, 412 deletions(-) diff --git a/src/cdomain/value/cdomains/intDomain0.ml b/src/cdomain/value/cdomains/intDomain0.ml index 67d7da2125..377ef1576d 100644 --- a/src/cdomain/value/cdomains/intDomain0.ml +++ b/src/cdomain/value/cdomains/intDomain0.ml @@ -635,418 +635,6 @@ struct ) (Invariant.top ()) ns end -module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option = -struct - let name () = "intervals" - type int_t = Ints_t.t - type t = (Ints_t.t * Ints_t.t) option [@@deriving eq, ord, hash] - module IArith = IntervalArith (Ints_t) - - let range ik = BatTuple.Tuple2.mapn Ints_t.of_bigint (Size.range ik) - - let top () = failwith @@ "top () not implemented for " ^ (name ()) - let top_of ik = Some (range ik) - let bot () = None - let bot_of ik = bot () (* TODO: improve *) - - let show = function None -> "bottom" | Some (x,y) -> "["^Ints_t.to_string x^","^Ints_t.to_string y^"]" - - include Std (struct type nonrec t = t let name = name let top_of = top_of let bot_of = bot_of let show = show let equal = equal end) - - let equal_to i = function - | None -> failwith "unsupported: equal_to with bottom" - | Some (a, b) -> - if a = b && b = i then `Eq else if Ints_t.compare a i <= 0 && Ints_t.compare i b <=0 then `Top else `Neq - - let norm ?(suppress_ovwarn=false) ?(cast=false) ik : (t -> t * overflow_info) = function None -> (None, {underflow=false; overflow=false}) | Some (x,y) -> - if Ints_t.compare x y > 0 then - (None,{underflow=false; overflow=false}) - else ( - let (min_ik, max_ik) = range ik in - let underflow = Ints_t.compare min_ik x > 0 in - let overflow = Ints_t.compare max_ik y < 0 in - let ov_info = { underflow = underflow && not suppress_ovwarn; overflow = overflow && not suppress_ovwarn } in - let v = - if underflow || overflow then - if should_wrap ik then (* could add [|| cast], but that's GCC implementation-defined behavior: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation *) - (* We can only soundly wrap if at most one overflow occurred, otherwise the minimal and maximal values of the interval *) - (* on Z will not safely contain the minimal and maximal elements after the cast *) - let diff = Ints_t.abs (Ints_t.sub max_ik min_ik) in - let resdiff = Ints_t.abs (Ints_t.sub y x) in - if Ints_t.compare resdiff diff > 0 then - top_of ik - else - let l = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint x) in - let u = Ints_t.of_bigint @@ Size.cast ik (Ints_t.to_bigint y) in - if Ints_t.compare l u <= 0 then - Some (l, u) - else - (* Interval that wraps around (begins to the right of its end). We can not represent such intervals *) - top_of ik - else if not cast && should_ignore_overflow ik then - let tl, tu = BatOption.get @@ top_of ik in - Some (Ints_t.max tl x, Ints_t.min tu y) - else - top_of ik - else - Some (x,y) - in - (v, ov_info) - ) - - let leq (x:t) (y:t) = - match x, y with - | None, _ -> true - | Some _, None -> false - | Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0 - - let join ik (x:t) y = - match x, y with - | None, z | z, None -> z - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst - - let meet ik (x:t) y = - match x, y with - | None, z | z, None -> None - | Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.max x1 y1, Ints_t.min x2 y2) |> fst - - (* TODO: change to_int signature so it returns a big_int *) - let to_int x = Option.bind x (IArith.to_int) - let of_interval ?(suppress_ovwarn=false) ik (x,y) = norm ~suppress_ovwarn ik @@ Some (x,y) - let of_int ik (x: int_t) = of_interval ik (x,x) - let zero = Some IArith.zero - let one = Some IArith.one - let top_bool = Some IArith.top_bool - - let of_bool _ik = function true -> one | false -> zero - let to_bool (a: t) = match a with - | None -> None - | Some (l, u) when Ints_t.compare l Ints_t.zero = 0 && Ints_t.compare u Ints_t.zero = 0 -> Some false - | x -> if leq zero x then None else Some true - - let starting ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (n, snd (range ik)) - - let ending ?(suppress_ovwarn=false) ik n = - norm ~suppress_ovwarn ik @@ Some (fst (range ik), n) - - (* TODO: change signature of maximal, minimal to return big_int*) - let maximal = function None -> None | Some (x,y) -> Some y - let minimal = function None -> None | Some (x,y) -> Some x - - let cast_to ?(suppress_ovwarn=false) ?torg ?no_ov t = norm ~cast:true t (* norm does all overflow handling *) - - let widen ik x y = - match x, y with - | None, z | z, None -> z - | Some (l0,u0), Some (l1,u1) -> - let (min_ik, max_ik) = range ik in - let threshold = get_interval_threshold_widening () in - let l2 = - if Ints_t.compare l0 l1 = 0 then l0 - else if threshold then IArith.lower_threshold l1 min_ik - else min_ik - in - let u2 = - if Ints_t.compare u0 u1 = 0 then u0 - else if threshold then IArith.upper_threshold u1 max_ik - else max_ik - in - norm ik @@ Some (l2,u2) |> fst - let widen ik x y = - let r = widen ik x y in - if M.tracing && not (equal x y) then M.tracel "int" "interval widen %a %a -> %a" pretty x pretty y pretty r; - assert (leq x y); (* TODO: remove for performance reasons? *) - r - - let narrow ik x y = - match x, y with - | _,None | None, _ -> None - | Some (x1,x2), Some (y1,y2) -> - let threshold = get_interval_threshold_widening () in - let (min_ik, max_ik) = range ik in - let lr = if Ints_t.compare min_ik x1 = 0 || threshold && Ints_t.compare y1 x1 > 0 && IArith.is_lower_threshold x1 then y1 else x1 in - let ur = if Ints_t.compare max_ik x2 = 0 || threshold && Ints_t.compare y2 x2 < 0 && IArith.is_upper_threshold x2 then y2 else x2 in - norm ik @@ Some (lr,ur) |> fst - - - let narrow ik x y = - if get_interval_narrow_by_meet () then - meet ik x y - else - narrow ik x y - - let log f ~annihilator ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_bool i1, to_bool i2 with - | Some x, _ when x = annihilator -> of_bool ik annihilator - | _, Some y when y = annihilator -> of_bool ik annihilator - | Some x, Some y -> of_bool ik (f x y) - | _ -> top_of ik - - let c_logor = log (||) ~annihilator:true - let c_logand = log (&&) ~annihilator:false - - let log1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_bool i1 with - | Some x -> of_bool ik (f ik x) - | _ -> top_of ik - - let c_lognot = log1 (fun _ik -> not) - - let bit f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) |> fst with Division_by_zero -> top_of ik) - | _ -> top_of ik - - let bitcomp f ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (f ik x y) with Division_by_zero | Invalid_argument _ -> (top_of ik,{underflow=false; overflow=false})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let logxor = bit (fun _ik -> Ints_t.logxor) - - let logand ik i1 i2 = - match is_bot i1, is_bot i2 with - | true, true -> bot_of ik - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2))) - | _ -> - match to_int i1, to_int i2 with - | Some x, Some y -> (try of_int ik (Ints_t.logand x y) |> fst with Division_by_zero -> top_of ik) - | _, Some y when Ints_t.equal y Ints_t.zero -> of_int ik Ints_t.zero |> fst - | _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst - | _ -> top_of ik - - let logor = bit (fun _ik -> Ints_t.logor) - - let bit1 f ik i1 = - if is_bot i1 then - bot_of ik - else - match to_int i1 with - | Some x -> of_int ik (f ik x) |> fst - | _ -> top_of ik - - let lognot = bit1 (fun _ik -> Ints_t.lognot) - let shift_right = bitcomp (fun _ik x y -> Ints_t.shift_right x (Ints_t.to_int y)) - - let neg ?no_ov ik = function None -> (None,{underflow=false; overflow=false}) | Some x -> norm ik @@ Some (IArith.neg x) - - let binary_op_with_norm ?no_ov op ik x y = match x, y with - | None, None -> (None, {overflow=false; underflow= false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some x, Some y -> norm ik @@ Some (op x y) - - let add ?no_ov = binary_op_with_norm IArith.add - let mul ?no_ov = binary_op_with_norm IArith.mul - let sub ?no_ov = binary_op_with_norm IArith.sub - - let shift_left ik a b = - match is_bot a, is_bot b with - | true, true -> (bot_of ik,{underflow=false; overflow=false}) - | true, _ - | _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show a) (show b))) - | _ -> - match a, minimal b, maximal b with - | Some a, Some bl, Some bu when (Ints_t.compare bl Ints_t.zero >= 0) -> - (try - let r = IArith.shift_left a (Ints_t.to_int bl, Ints_t.to_int bu) in - norm ik @@ Some r - with Z.Overflow -> (top_of ik,{underflow=false; overflow=true})) - | _ -> (top_of ik,{underflow=true; overflow=true}) - - let rem ik x y = match x, y with - | None, None -> None - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (xl, xu), Some (yl, yu) -> - if is_top_of ik x && is_top_of ik y then - (* This is needed to preserve soundness also on things bigger than int32 e.g. *) - (* x: 3803957176L -> T in Interval32 *) - (* y: 4209861404L -> T in Interval32 *) - (* x % y: 3803957176L -> T in Interval32 *) - (* T in Interval32 is [-2147483648,2147483647] *) - (* the code below computes [-2147483647,2147483647] for this though which is unsound *) - top_of ik - else - (* If we have definite values, Ints_t.rem will give a definite result. - * Otherwise we meet with a [range] the result can be in. - * This range is [0, min xu b] if x is positive, and [max xl -b, min xu b] if x can be negative. - * The precise bound b is one smaller than the maximum bound. Negative y give the same result as positive. *) - let pos x = if Ints_t.compare x Ints_t.zero < 0 then Ints_t.neg x else x in - let b = Ints_t.sub (Ints_t.max (pos yl) (pos yu)) Ints_t.one in - let range = if Ints_t.compare xl Ints_t.zero>= 0 then Some (Ints_t.zero, Ints_t.min xu b) else Some (Ints_t.max xl (Ints_t.neg b), Ints_t.min (Ints_t.max (pos xl) (pos xu)) b) in - meet ik (bit (fun _ik -> Ints_t.rem) ik x y) range - - let rec div ?no_ov ik x y = - match x, y with - | None, None -> (bot (),{underflow=false; overflow=false}) - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | (Some (x1,x2) as x), (Some (y1,y2) as y) -> - begin - let is_zero v = Ints_t.compare v Ints_t.zero = 0 in - match y1, y2 with - | l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false}) (* TODO warn about undefined behavior *) - | l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2)) - | _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one))) - | _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false}) - | _ -> binary_op_with_norm IArith.div ik x y - end - - let ne ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik true - else if Ints_t.compare x2 y1 <= 0 && Ints_t.compare y2 x1 <= 0 then - of_bool ik false - else top_bool - - let eq ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 && Ints_t.compare x2 y1 <= 0 then - of_bool ik true - else if Ints_t.compare y2 x1 < 0 || Ints_t.compare x2 y1 < 0 then - of_bool ik false - else top_bool - - let ge ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 <= 0 then of_bool ik true - else if Ints_t.compare x2 y1 < 0 then of_bool ik false - else top_bool - - let le ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 <= 0 then of_bool ik true - else if Ints_t.compare y2 x1 < 0 then of_bool ik false - else top_bool - - let gt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare y2 x1 < 0 then of_bool ik true - else if Ints_t.compare x2 y1 <= 0 then of_bool ik false - else top_bool - - let lt ik x y = - match x, y with - | None, None -> bot_of ik - | None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))) - | Some (x1,x2), Some (y1,y2) -> - if Ints_t.compare x2 y1 < 0 then of_bool ik true - else if Ints_t.compare y2 x1 <= 0 then of_bool ik false - else top_bool - - let invariant_ikind e ik = function - | Some (x1, x2) -> - let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in - IntInvariant.of_interval e ik (x1', x2') - | None -> Invariant.none - - let arbitrary ik = - let open QCheck.Iter in - (* let int_arb = QCheck.map ~rev:Ints_t.to_bigint Ints_t.of_bigint GobQCheck.Arbitrary.big_int in *) - (* TODO: apparently bigints are really slow compared to int64 for domaintest *) - let int_arb = QCheck.map ~rev:Ints_t.to_int64 Ints_t.of_int64 GobQCheck.Arbitrary.int64 in - let pair_arb = QCheck.pair int_arb int_arb in - let shrink = function - | Some (l, u) -> (return None) <+> (GobQCheck.shrink pair_arb (l, u) >|= of_interval ik >|= fst) - | None -> empty - in - QCheck.(set_shrink shrink @@ set_print show @@ map (*~rev:BatOption.get*) (fun x -> of_interval ik x |> fst ) pair_arb) - - let modulo n k = - let result = Ints_t.rem n k in - if Ints_t.compare result Ints_t.zero >= 0 then result - else Ints_t.add result k - - let refine_with_congruence ik (intv : t) (cong : (int_t * int_t ) option) : t = - match intv, cong with - | Some (x, y), Some (c, m) -> - if Ints_t.equal m Ints_t.zero && (Ints_t.compare c x < 0 || Ints_t.compare c y > 0) then None - else if Ints_t.equal m Ints_t.zero then - Some (c, c) - else - let (min_ik, max_ik) = range ik in - let rcx = - if Ints_t.equal x min_ik then x else - Ints_t.add x (modulo (Ints_t.sub c x) (Ints_t.abs m)) in - let lcy = - if Ints_t.equal y max_ik then y else - Ints_t.sub y (modulo (Ints_t.sub y c) (Ints_t.abs m)) in - if Ints_t.compare rcx lcy > 0 then None - else if Ints_t.equal rcx lcy then norm ik @@ Some (rcx, rcx) |> fst - else norm ik @@ Some (rcx, lcy) |> fst - | _ -> None - - let refine_with_congruence ik x y = - let refn = refine_with_congruence ik x y in - if M.tracing then M.trace "refine" "int_refine_with_congruence %a %a -> %a" pretty x pretty y pretty refn; - refn - - let refine_with_interval ik a b = meet ik a b - - let refine_with_excl_list ik (intv : t) (excl : (int_t list * (int64 * int64)) option) : t = - match intv, excl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls, (rl, rh)) -> - let rec shrink op b = - let new_b = (op b (Ints_t.of_int(Bool.to_int(BatList.mem_cmp Ints_t.compare b ls)))) in - if not (Ints_t.equal b new_b) then shrink op new_b else new_b - in - let (min_ik, max_ik) = range ik in - let l' = if Ints_t.equal l min_ik then l else shrink Ints_t.add l in - let u' = if Ints_t.equal u max_ik then u else shrink Ints_t.sub u in - let intv' = norm ik @@ Some (l', u') |> fst in - let range = norm ~suppress_ovwarn:true ik (Some (Ints_t.of_bigint (Size.min_from_bit_range rl), Ints_t.of_bigint (Size.max_from_bit_range rh))) |> fst in - meet ik intv' range - - let refine_with_incl_list ik (intv: t) (incl : (int_t list) option) : t = - match intv, incl with - | None, _ | _, None -> intv - | Some(l, u), Some(ls) -> - let rec min m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> min (Some x) xs | Some m -> if Ints_t.compare m x < 0 then min (Some m) xs else min (Some x) xs in - let rec max m1 ms = match ms with | [] -> m1 | x::xs -> match m1 with - | None -> max (Some x) xs | Some m -> if Ints_t.compare m x > 0 then max (Some m) xs else max (Some x) xs in - match min None ls, max None ls with - | Some m1, Some m2 -> refine_with_interval ik (Some(l, u)) (Some (m1, m2)) - | _, _-> intv - - let project ik p t = t -end - module SOverflowUnlifter (D : SOverflow) : S with type int_t = D.int_t and type t = D.t = struct include D From db37e858017d939c952836e7c0b7f5d3295efe8d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 25 Oct 2024 17:25:13 +0300 Subject: [PATCH 609/689] Add IntDomain exclusions to goblint-lib-modules.py --- scripts/goblint-lib-modules.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/goblint-lib-modules.py b/scripts/goblint-lib-modules.py index ba25a1403c..eee7b218c5 100755 --- a/scripts/goblint-lib-modules.py +++ b/scripts/goblint-lib-modules.py @@ -48,6 +48,12 @@ "MessageCategory", # included in Messages "PreValueDomain", # included in ValueDomain + "IntervalDomain", # included in IntDomain + "IntervalSetDomain", # included in IntDomain + "DefExcDomain", # included in IntDomain + "EnumsDomain", # included in IntDomain + "CongruenceDomain", # included in IntDomain + "IntDomTuple", # included in IntDomain "ConfigVersion", "ConfigProfile", From 3970a2fde041afba272b4a93e3a7c4a73f05cdca Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 28 Oct 2024 13:48:12 +0200 Subject: [PATCH 610/689] Add regression test for joining main thread --- .../regression/51-threadjoins/09-join-main.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/regression/51-threadjoins/09-join-main.c diff --git a/tests/regression/51-threadjoins/09-join-main.c b/tests/regression/51-threadjoins/09-join-main.c new file mode 100644 index 0000000000..249de594bf --- /dev/null +++ b/tests/regression/51-threadjoins/09-join-main.c @@ -0,0 +1,23 @@ +//PARAM: --set ana.activated[+] threadJoins +#include + +pthread_t mainid; + +int g = 10; + +void *t_fun(void *arg) { + pthread_join(mainid, NULL); + g++; // TODO NORACE + return NULL; +} + + +int main(void) { + mainid = pthread_self(); + + pthread_t id2; + pthread_create(&id2, NULL, t_fun, NULL); + + g++; // TODO NORACE + return 0; +} From 3d048eb1035479f26854a23402bb2aad0e53fd31 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 28 Oct 2024 13:48:37 +0200 Subject: [PATCH 611/689] Add pthread_self support --- src/analyses/base.ml | 9 +++++++++ src/util/library/libraryDesc.ml | 1 + src/util/library/libraryFunctions.ml | 2 +- tests/regression/51-threadjoins/09-join-main.c | 4 ++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index cea2c8bcee..e5bcbfede5 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -2651,6 +2651,15 @@ struct | Unknown, "__goblint_assume_join" -> let id = List.hd args in Priv.thread_join ~force:true (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) id st + | ThreadSelf, _ -> + begin match lv, ThreadId.get_current (Analyses.ask_of_ctx ctx) with + | Some lv, `Lifted tid -> + set ~ctx st (eval_lv ~ctx st lv) (Cilfacade.typeOfLval lv) (Thread (ValueDomain.Threads.singleton tid)) + | Some lv, _ -> + invalidate_ret_lv st + | None, _ -> + st + end | Alloca size, _ -> begin match lv with | Some lv -> diff --git a/src/util/library/libraryDesc.ml b/src/util/library/libraryDesc.ml index 80cf86b1e2..6f34de1864 100644 --- a/src/util/library/libraryDesc.ml +++ b/src/util/library/libraryDesc.ml @@ -56,6 +56,7 @@ type special = | ThreadCreate of { thread: Cil.exp; start_routine: Cil.exp; arg: Cil.exp; multiple: bool } | ThreadJoin of { thread: Cil.exp; ret_var: Cil.exp; } | ThreadExit of { ret_val: Cil.exp; } + | ThreadSelf | Globalize of Cil.exp | Signal of Cil.exp | Broadcast of Cil.exp diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 31fcf0510e..fbcaa4fe60 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -504,7 +504,7 @@ let pthread_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("pthread_attr_setstacksize", unknown [drop "attr" [w]; drop "stacksize" []]); ("pthread_attr_getscope", unknown [drop "attr" [r]; drop "scope" [w]]); ("pthread_attr_setscope", unknown [drop "attr" [w]; drop "scope" []]); - ("pthread_self", unknown []); + ("pthread_self", special [] ThreadSelf); ("pthread_sigmask", unknown [drop "how" []; drop "set" [r]; drop "oldset" [w]]); ("pthread_setspecific", unknown ~attrs:[InvalidateGlobals] [drop "key" []; drop "value" [w_deep]]); ("pthread_getspecific", unknown ~attrs:[InvalidateGlobals] [drop "key" []]); diff --git a/tests/regression/51-threadjoins/09-join-main.c b/tests/regression/51-threadjoins/09-join-main.c index 249de594bf..1d61eedf89 100644 --- a/tests/regression/51-threadjoins/09-join-main.c +++ b/tests/regression/51-threadjoins/09-join-main.c @@ -7,7 +7,7 @@ int g = 10; void *t_fun(void *arg) { pthread_join(mainid, NULL); - g++; // TODO NORACE + g++; // NORACE return NULL; } @@ -18,6 +18,6 @@ int main(void) { pthread_t id2; pthread_create(&id2, NULL, t_fun, NULL); - g++; // TODO NORACE + g++; // NORACE return 0; } From 01bff20b3fea1bb077c12ba9b0b7d7eba6d27c72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 28 Oct 2024 14:00:52 +0200 Subject: [PATCH 612/689] Make 51-threadjoins/09-join-main runnable --- tests/regression/51-threadjoins/09-join-main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/regression/51-threadjoins/09-join-main.c b/tests/regression/51-threadjoins/09-join-main.c index 1d61eedf89..196ef8bc00 100644 --- a/tests/regression/51-threadjoins/09-join-main.c +++ b/tests/regression/51-threadjoins/09-join-main.c @@ -1,13 +1,16 @@ //PARAM: --set ana.activated[+] threadJoins #include +#include pthread_t mainid; int g = 10; void *t_fun(void *arg) { - pthread_join(mainid, NULL); + int r = pthread_join(mainid, NULL); // TSan doesn't like this... + printf("j: %d\n", r); g++; // NORACE + printf("t_fun: %d\n", g); return NULL; } @@ -19,5 +22,8 @@ int main(void) { pthread_create(&id2, NULL, t_fun, NULL); g++; // NORACE + printf("main: %d\n", g); + + pthread_exit(NULL); // exit main thread but keep id2 alive, otherwise main returning kills id2 return 0; } From bdc288e9706d3bfd0ae09785b891bc545ac3225e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 28 Oct 2024 15:27:55 +0200 Subject: [PATCH 613/689] Copy 51-threadjoins/09-join-main for plain thread IDs --- .../51-threadjoins/10-join-main-plain.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/regression/51-threadjoins/10-join-main-plain.c diff --git a/tests/regression/51-threadjoins/10-join-main-plain.c b/tests/regression/51-threadjoins/10-join-main-plain.c new file mode 100644 index 0000000000..8bcb2b3a79 --- /dev/null +++ b/tests/regression/51-threadjoins/10-join-main-plain.c @@ -0,0 +1,29 @@ +//PARAM: --set ana.activated[+] threadJoins --set ana.thread.domain plain +#include +#include + +pthread_t mainid; + +int g = 10; + +void *t_fun(void *arg) { + int r = pthread_join(mainid, NULL); // TSan doesn't like this... + printf("j: %d\n", r); + g++; // RACE (imprecise by plain thread IDs) + printf("t_fun: %d\n", g); + return NULL; +} + + +int main(void) { + mainid = pthread_self(); + + pthread_t id2; + pthread_create(&id2, NULL, t_fun, NULL); + + g++; // TODO NORACE + printf("main: %d\n", g); + + pthread_exit(NULL); // exit main thread but keep id2 alive, otherwise main returning kills id2 + return 0; +} From 568e97cf331e7b0cd0b7b035dadaa198435867a6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 28 Oct 2024 15:29:04 +0200 Subject: [PATCH 614/689] Improve plain thread ID is_unique --- src/cdomain/value/cdomains/threadIdDomain.ml | 2 +- tests/regression/51-threadjoins/10-join-main-plain.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdomain/value/cdomains/threadIdDomain.ml b/src/cdomain/value/cdomains/threadIdDomain.ml index fff6734f27..290a6b316b 100644 --- a/src/cdomain/value/cdomains/threadIdDomain.ml +++ b/src/cdomain/value/cdomains/threadIdDomain.ml @@ -86,7 +86,7 @@ struct | ({vname; _}, None) -> List.mem vname @@ GobConfig.get_string_list "mainfun" | _ -> false - let is_unique _ = false (* TODO: should this consider main unique? *) + let is_unique = is_main let may_create _ _ = true let is_must_parent _ _ = false end diff --git a/tests/regression/51-threadjoins/10-join-main-plain.c b/tests/regression/51-threadjoins/10-join-main-plain.c index 8bcb2b3a79..5b2c188bf5 100644 --- a/tests/regression/51-threadjoins/10-join-main-plain.c +++ b/tests/regression/51-threadjoins/10-join-main-plain.c @@ -21,7 +21,7 @@ int main(void) { pthread_t id2; pthread_create(&id2, NULL, t_fun, NULL); - g++; // TODO NORACE + g++; // NORACE printf("main: %d\n", g); pthread_exit(NULL); // exit main thread but keep id2 alive, otherwise main returning kills id2 From 1bb8db120146e371451cd3b1c34bfcf2d44e798b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 30 Oct 2024 15:36:48 +0200 Subject: [PATCH 615/689] Fix plain thread ID is_main unsoundness when ana.thread.include-node is disabled --- src/cdomain/value/cdomains/threadIdDomain.ml | 2 +- .../11-join-main-plain-no-node.c | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/regression/51-threadjoins/11-join-main-plain-no-node.c diff --git a/src/cdomain/value/cdomains/threadIdDomain.ml b/src/cdomain/value/cdomains/threadIdDomain.ml index 290a6b316b..226905ed6f 100644 --- a/src/cdomain/value/cdomains/threadIdDomain.ml +++ b/src/cdomain/value/cdomains/threadIdDomain.ml @@ -83,7 +83,7 @@ struct (v, None) let is_main = function - | ({vname; _}, None) -> List.mem vname @@ GobConfig.get_string_list "mainfun" + | ({vname; _}, None) -> GobConfig.get_bool "ana.thread.include-node" && List.mem vname @@ GobConfig.get_string_list "mainfun" | _ -> false let is_unique = is_main diff --git a/tests/regression/51-threadjoins/11-join-main-plain-no-node.c b/tests/regression/51-threadjoins/11-join-main-plain-no-node.c new file mode 100644 index 0000000000..7f235fd1d8 --- /dev/null +++ b/tests/regression/51-threadjoins/11-join-main-plain-no-node.c @@ -0,0 +1,29 @@ +//PARAM: --set ana.activated[+] threadJoins --set ana.thread.domain plain --disable ana.thread.include-node +#include +#include + +pthread_t mainid; + +int g = 10; + +void *t_fun(void *arg) { + int r = pthread_join(mainid, NULL); // TSan doesn't like this... + printf("j: %d\n", r); + g++; // RACE (imprecise by plain thread IDs) + printf("t_fun: %d\n", g); + return NULL; +} + + +int main(void) { + mainid = pthread_self(); + + pthread_t id2; + pthread_create(&id2, NULL, t_fun, NULL); + + g++; // RACE (imprecise by plain thread IDs not knowing if main is actual main or spawned by program) + printf("main: %d\n", g); + + pthread_exit(NULL); // exit main thread but keep id2 alive, otherwise main returning kills id2 + return 0; +} From 7adeb5a8ac8b45cb01f9649c106606696bb29993 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 31 Oct 2024 18:34:39 +0200 Subject: [PATCH 616/689] Add visitor for finding mallocs/allocs that are not in loops --- src/autoTune.ml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index f59a10ee8a..7194d1ece7 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -44,6 +44,26 @@ class functionVisitor(calling, calledBy, argLists, dynamicallyCalled) = object DoChildren end +exception Found +class findAllocsNotInLoops = object + inherit nopCilVisitor + + method! vstmt stmt = + match stmt.skind with + | Loop _ -> SkipChildren + | _ -> DoChildren + + method! vinst = function + | Call (_, Lval (Var f, NoOffset), args,_,_) -> + let desc = LibraryFunctions.find f in + begin match desc.special args with + | Malloc _ + | Alloca _ -> raise Found + | _ -> DoChildren + end + | _ -> DoChildren +end + type functionCallMaps = { calling: FunctionSet.t FunctionCallMap.t; calledBy: (FunctionSet.t * int) FunctionCallMap.t; From cb16bae9fc8ee6da2f2e07a703ce93eba62e85c1 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 31 Oct 2024 19:47:38 +0200 Subject: [PATCH 617/689] Set ana.malloc.unique_address_count to 1 when alloc is found in program for noOverflow tasks --- src/autoTune.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 7194d1ece7..1eb9aba5fc 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -257,7 +257,11 @@ let focusOnSpecification (spec: Svcomp.Specification.t) = Logs.info "Specification: NoDataRace -> enabling thread analyses \"%s\"" (String.concat ", " notNeccessaryThreadAnalyses); enableAnalyses notNeccessaryThreadAnalyses; | NoOverflow -> (*We focus on integer analysis*) - set_bool "ana.int.def_exc" true + set_bool "ana.int.def_exc" true; + begin + try ignore @@ visitCilFileSameGlobals (new findAllocsNotInLoops) (!Cilfacade.current_file) + with Found -> set_int "ana.malloc.unique_address_count" 1; + end | _ -> () let focusOnSpecification () = From c6a6ee0be729198fd594acf025ffa5b337217c3b Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 31 Oct 2024 19:47:59 +0200 Subject: [PATCH 618/689] Enable autotune.specification --- conf/svcomp.json | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/svcomp.json b/conf/svcomp.json index 50136def50..1e05da580c 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -60,6 +60,7 @@ "singleThreaded", "mallocWrappers", "noRecursiveIntervals", + "specification", "enums", "congruence", "octagon", From 5ceb7205dd2e14ed9bf8135c554dda17e090a92d Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 31 Oct 2024 20:11:28 +0200 Subject: [PATCH 619/689] Separate autotune for each category as options --- conf/svcomp.json | 2 +- src/autoTune.ml | 42 ++++++++++++++++++++++++++-------- src/config/options.schema.json | 8 +++++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/conf/svcomp.json b/conf/svcomp.json index 1e05da580c..c1ccaa4ab3 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -60,13 +60,13 @@ "singleThreaded", "mallocWrappers", "noRecursiveIntervals", - "specification", "enums", "congruence", "octagon", "wideningThresholds", "loopUnrollHeuristic", "memsafetySpecification", + "noOverflows", "termination", "tmpSpecialAnalysis" ] diff --git a/src/autoTune.ml b/src/autoTune.ml index 1eb9aba5fc..c54b84d0e9 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -250,13 +250,25 @@ let focusOnTermination (spec: Svcomp.Specification.t) = let focusOnTermination () = List.iter focusOnTermination (Svcomp.Specification.of_option ()) -let focusOnSpecification (spec: Svcomp.Specification.t) = +let focusOnReachSafety (spec: Svcomp.Specification.t) = () + +let focusOnReachSafety () = + List.iter focusOnReachSafety (Svcomp.Specification.of_option ()) + +let focusOnConcurrencySafety (spec: Svcomp.Specification.t) = match spec with - | UnreachCall s -> () | NoDataRace -> (*enable all thread analyses*) Logs.info "Specification: NoDataRace -> enabling thread analyses \"%s\"" (String.concat ", " notNeccessaryThreadAnalyses); enableAnalyses notNeccessaryThreadAnalyses; - | NoOverflow -> (*We focus on integer analysis*) + | _ -> () + +let focusOnConcurrencySafety () = + List.iter focusOnConcurrencySafety (Svcomp.Specification.of_option ()) + +let focusOnNoOverflows (spec: Svcomp.Specification.t) = + match spec with + | NoOverflow -> + (*We focus on integer analysis*) set_bool "ana.int.def_exc" true; begin try ignore @@ visitCilFileSameGlobals (new findAllocsNotInLoops) (!Cilfacade.current_file) @@ -264,8 +276,8 @@ let focusOnSpecification (spec: Svcomp.Specification.t) = end | _ -> () -let focusOnSpecification () = - List.iter focusOnSpecification (Svcomp.Specification.of_option ()) +let focusOnNoOverflows () = + List.iter focusOnNoOverflows (Svcomp.Specification.of_option ()) (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound @@ -513,8 +525,14 @@ let isActivated a = get_bool "ana.autotune.enabled" && List.mem a @@ get_string_ let isTerminationTask () = List.mem Svcomp.Specification.Termination (Svcomp.Specification.of_option ()) -let specificationIsActivated () = - isActivated "specification" && get_string "ana.specification" <> "" +let specificationReachSafetyIsActivated () = + isActivated "reachSafetySpecification" + +let specificationConcurrencySafetyIsActivated () = + isActivated "concurrencySafetySpecification" + +let specificationNoOverflowsIsActivated () = + isActivated "noOverflows" let specificationTerminationIsActivated () = isActivated "termination" @@ -541,8 +559,14 @@ let chooseConfig file = if isActivated "mallocWrappers" then findMallocWrappers (); - if specificationIsActivated () then - focusOnSpecification (); + if specificationReachSafetyIsActivated () then + focusOnReachSafety (); + + if specificationConcurrencySafetyIsActivated () then + focusOnConcurrencySafety (); + + if specificationNoOverflowsIsActivated () then + focusOnNoOverflows (); if isActivated "enums" && hasEnums file then set_bool "ana.int.enums" true; diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 5d87eb51f6..d8a7d3adc7 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -535,7 +535,6 @@ "enum": [ "congruence", "singleThreaded", - "specification", "mallocWrappers", "noRecursiveIntervals", "enums", @@ -545,6 +544,9 @@ "octagon", "wideningThresholds", "memsafetySpecification", + "reachSafetySpecification", + "concurrencySafetySpecification", + "noOverflows", "termination", "tmpSpecialAnalysis" ] @@ -552,7 +554,6 @@ "default": [ "congruence", "singleThreaded", - "specification", "mallocWrappers", "noRecursiveIntervals", "enums", @@ -561,6 +562,9 @@ "octagon", "wideningThresholds", "memsafetySpecification", + "reachSafetySpecification", + "concurrencySafetySpecification", + "noOverflows", "termination", "tmpSpecialAnalysis" ] From 506fb21001924edb008760da682a4e59bc5283dc Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 31 Oct 2024 20:16:09 +0200 Subject: [PATCH 620/689] Refactor: inline functions --- src/autoTune.ml | 21 +++------------------ src/goblint.ml | 2 +- src/maingoblint.ml | 2 +- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index c54b84d0e9..af7b9ab478 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -525,21 +525,6 @@ let isActivated a = get_bool "ana.autotune.enabled" && List.mem a @@ get_string_ let isTerminationTask () = List.mem Svcomp.Specification.Termination (Svcomp.Specification.of_option ()) -let specificationReachSafetyIsActivated () = - isActivated "reachSafetySpecification" - -let specificationConcurrencySafetyIsActivated () = - isActivated "concurrencySafetySpecification" - -let specificationNoOverflowsIsActivated () = - isActivated "noOverflows" - -let specificationTerminationIsActivated () = - isActivated "termination" - -let specificationMemSafetyIsActivated () = - isActivated "memsafetySpecification" - let chooseConfig file = let factors = collectFactors visitCilFileSameGlobals file in let fileCompplexity = estimateComplexity factors file in @@ -559,13 +544,13 @@ let chooseConfig file = if isActivated "mallocWrappers" then findMallocWrappers (); - if specificationReachSafetyIsActivated () then + if isActivated "reachSafetySpecification" then focusOnReachSafety (); - if specificationConcurrencySafetyIsActivated () then + if isActivated "concurrencySafetySpecification" then focusOnConcurrencySafety (); - if specificationNoOverflowsIsActivated () then + if isActivated "noOverflows" then focusOnNoOverflows (); if isActivated "enums" && hasEnums file then diff --git a/src/goblint.ml b/src/goblint.ml index 6f8f8c20e5..2a0ab3ce0f 100644 --- a/src/goblint.ml +++ b/src/goblint.ml @@ -37,7 +37,7 @@ let main () = Logs.debug "%s" GobSys.command_line; (* When analyzing a termination specification, activate the termination analysis before pre-processing. *) if get_string "ana.specification" <> "" then AutoSoundConfig.enableAnalysesForTerminationSpecification (); - if AutoTune.specificationTerminationIsActivated () then AutoTune.focusOnTermination (); + if AutoTune.isActivated "termination" then AutoTune.focusOnTermination (); let file = lazy (Fun.protect ~finally:GoblintDir.finalize preprocess_parse_merge) in if get_bool "server.enabled" then ( let file = diff --git a/src/maingoblint.ml b/src/maingoblint.ml index 95849bce36..cb81ea0b86 100644 --- a/src/maingoblint.ml +++ b/src/maingoblint.ml @@ -203,7 +203,7 @@ let handle_options () = 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 get_string "ana.specification" <> "" then AutoSoundConfig.enableAnalysesForMemSafetySpecification (); - if AutoTune.specificationMemSafetyIsActivated () then + if AutoTune.isActivated "memsafetySpecification" then AutoTune.focusOnMemSafetySpecification (); AfterConfig.run (); Cilfacade.init_options (); From 2508f1ac655401a13c4831ddfc008be72dacd977 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Thu, 31 Oct 2024 20:20:28 +0200 Subject: [PATCH 621/689] Refactor: generalize repetitive function definition --- src/autoTune.ml | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index af7b9ab478..8dfcc6480e 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -250,22 +250,16 @@ let focusOnTermination (spec: Svcomp.Specification.t) = let focusOnTermination () = List.iter focusOnTermination (Svcomp.Specification.of_option ()) -let focusOnReachSafety (spec: Svcomp.Specification.t) = () +let reachSafety (spec: Svcomp.Specification.t) = () -let focusOnReachSafety () = - List.iter focusOnReachSafety (Svcomp.Specification.of_option ()) - -let focusOnConcurrencySafety (spec: Svcomp.Specification.t) = +let concurrencySafety (spec: Svcomp.Specification.t) = match spec with | NoDataRace -> (*enable all thread analyses*) Logs.info "Specification: NoDataRace -> enabling thread analyses \"%s\"" (String.concat ", " notNeccessaryThreadAnalyses); enableAnalyses notNeccessaryThreadAnalyses; | _ -> () -let focusOnConcurrencySafety () = - List.iter focusOnConcurrencySafety (Svcomp.Specification.of_option ()) - -let focusOnNoOverflows (spec: Svcomp.Specification.t) = +let noOverflows (spec: Svcomp.Specification.t) = match spec with | NoOverflow -> (*We focus on integer analysis*) @@ -276,8 +270,8 @@ let focusOnNoOverflows (spec: Svcomp.Specification.t) = end | _ -> () -let focusOnNoOverflows () = - List.iter focusOnNoOverflows (Svcomp.Specification.of_option ()) +let focusOn (f : SvcompSpec.t -> unit) = + List.iter f (Svcomp.Specification.of_option ()) (*Detect enumerations and enable the "ana.int.enums" option*) exception EnumFound @@ -544,14 +538,11 @@ let chooseConfig file = if isActivated "mallocWrappers" then findMallocWrappers (); - if isActivated "reachSafetySpecification" then - focusOnReachSafety (); + if isActivated "reachSafetySpecification" then focusOn reachSafety; - if isActivated "concurrencySafetySpecification" then - focusOnConcurrencySafety (); + if isActivated "concurrencySafetySpecification" then focusOn concurrencySafety; - if isActivated "noOverflows" then - focusOnNoOverflows (); + if isActivated "noOverflows" then focusOn noOverflows; if isActivated "enums" && hasEnums file then set_bool "ana.int.enums" true; From 0b6f98174c544631c4a1cc80f47c19ac75e992dd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 1 Nov 2024 12:45:19 +0200 Subject: [PATCH 622/689] Add semgrep rules for finding exists/forall-like folds --- .semgrep/fold.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .semgrep/fold.yml diff --git a/.semgrep/fold.yml b/.semgrep/fold.yml new file mode 100644 index 0000000000..8e4739791f --- /dev/null +++ b/.semgrep/fold.yml @@ -0,0 +1,26 @@ +rules: + - id: fold-exists + patterns: + - pattern-either: + - pattern: $D.fold ... false + - pattern: $D.fold_left ... false + - pattern: $D.fold_right ... false + - pattern: fold ... false + - pattern: fold_left ... false + - pattern: fold_right ... false + message: consider replacing fold with exists + languages: [ocaml] + severity: WARNING + + - id: fold-for_all + patterns: + - pattern-either: + - pattern: $D.fold ... true + - pattern: $D.fold_left ... true + - pattern: $D.fold_right ... true + - pattern: fold ... true + - pattern: fold_left ... true + - pattern: fold_right ... true + message: consider replacing fold with for_all + languages: [ocaml] + severity: WARNING From 513662ce92e14b6a8fe25a92c6b47622de858dfb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 1 Nov 2024 12:55:08 +0200 Subject: [PATCH 623/689] Fix or suppress semgrep fold-exists/for_all warnings --- src/analyses/basePriv.ml | 12 ++++++------ src/domain/partitionDomain.ml | 6 +++--- src/incremental/compareCFG.ml | 2 +- src/solver/td3.ml | 2 +- src/witness/witness.ml | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 946b8f8cc5..e69757c7a8 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -1040,11 +1040,11 @@ struct let s = MustLockset.remove m (current_lockset ask) in let t = current_thread ask in let side_cpa = CPA.filter (fun x _ -> - GWeak.fold (fun s' tm acc -> + GWeak.exists (fun s' tm -> (* TODO: swap 2^M and T partitioning for lookup by t here first? *) let v = ThreadMap.find t tm in - (MustLockset.mem m s' && not (VD.is_bot v)) || acc - ) (G.weak (getg (V.global x))) false + (MustLockset.mem m s' && not (VD.is_bot v)) + ) (G.weak (getg (V.global x))) ) st.cpa in sideg (V.mutex m) (G.create_sync (GSync.singleton s side_cpa)); @@ -1098,9 +1098,9 @@ struct let unlock ask getg sideg (st: BaseComponents (D).t) m = let s = MustLockset.remove m (current_lockset ask) in let side_cpa = CPA.filter (fun x _ -> - GWeak.fold (fun s' v acc -> - (MustLockset.mem m s' && not (VD.is_bot v)) || acc - ) (G.weak (getg (V.global x))) false + GWeak.exists (fun s' v -> + (MustLockset.mem m s' && not (VD.is_bot v)) + ) (G.weak (getg (V.global x))) ) st.cpa in sideg (V.mutex m) (G.create_sync (GSync.singleton s side_cpa)); diff --git a/src/domain/partitionDomain.ml b/src/domain/partitionDomain.ml index 9675e9bfce..316f4fb705 100644 --- a/src/domain/partitionDomain.ml +++ b/src/domain/partitionDomain.ml @@ -31,10 +31,10 @@ struct let meet _ _ = failwith "PartitonDomain.Set.meet: unsound" let collapse (s1:t) (s2:t): bool = - let f vf2 res = - res || exists (fun vf1 -> S.collapse vf1 vf2) s1 + let f vf2 = + exists (fun vf1 -> S.collapse vf1 vf2) s1 in - fold f s2 false + exists f s2 let add e s = join s (singleton e) diff --git a/src/incremental/compareCFG.ml b/src/incremental/compareCFG.ml index 6c314ef7c9..a663b80833 100644 --- a/src/incremental/compareCFG.ml +++ b/src/incremental/compareCFG.ml @@ -131,7 +131,7 @@ let reexamine f1 f2 (same : biDirectionNodeMap) (diffNodes1 : unit NH.t) (module false end in let cond n2 = Node.equal n2 (FunctionEntry f2) || check_all_nodes_in_same (List.map snd (CfgNew.prev n2)) n2 in - let forall = NH.fold (fun n2 n1 acc -> acc && cond n2) same.node2to1 true in + let forall = NH.fold (fun n2 n1 acc -> acc && cond n2) same.node2to1 true in (* nosemgrep: fold-for_all *) (* cond does side effects *) if not forall then repeat () in repeat (); NH.to_seq same.node1to2, NH.to_seq_keys diffNodes1 diff --git a/src/solver/td3.ml b/src/solver/td3.ml index c7bec621e3..049dce2a0d 100644 --- a/src/solver/td3.ml +++ b/src/solver/td3.ml @@ -289,7 +289,7 @@ module Base = destabilize_vs y || b || was_stable && List.mem_cmp S.Var.compare y vs else true - ) w false + ) w false (* nosemgrep: fold-exists *) (* does side effects *) and solve ?reuse_eq x phase = if tracing then trace "sol2" "solve %a, phase: %s, called: %b, stable: %b, wpoint: %b" S.Var.pretty_trace x (show_phase phase) (HM.mem called x) (HM.mem stable x) (HM.mem wpoint x); init x; diff --git a/src/witness/witness.ml b/src/witness/witness.ml index 5da46a1011..bb70c3319f 100644 --- a/src/witness/witness.ml +++ b/src/witness/witness.ml @@ -342,14 +342,14 @@ struct | UnreachCall _ -> (* error function name is globally known through Svcomp.task *) let is_unreach_call = - LHT.fold (fun (n, c) v acc -> + LHT.for_all (fun (n, c) v -> match n with (* FunctionEntry isn't used for extern __VERIFIER_error... *) | FunctionEntry f when Svcomp.is_error_function f.svar -> let is_dead = Spec.D.is_bot v in - acc && is_dead - | _ -> acc - ) lh true + is_dead + | _ -> true + ) lh in if is_unreach_call then ( From 62cb655ab97c9fe2bf2967ba68af5d6247bb3f8d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 1 Nov 2024 12:56:32 +0200 Subject: [PATCH 624/689] Extend semgrep tracing rule for abbreviated module name --- .semgrep/tracing.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.semgrep/tracing.yml b/.semgrep/tracing.yml index 061b3efa0d..9c7813a7e8 100644 --- a/.semgrep/tracing.yml +++ b/.semgrep/tracing.yml @@ -8,8 +8,16 @@ rules: - pattern: Messages.tracec - pattern: Messages.traceu - pattern: Messages.traceli + - pattern: M.trace + - pattern: M.tracel + - pattern: M.tracei + - pattern: M.tracec + - pattern: M.traceu + - pattern: M.traceli - pattern-not-inside: if Messages.tracing then ... - pattern-not-inside: if Messages.tracing && ... then ... + - pattern-not-inside: if M.tracing then ... + - pattern-not-inside: if M.tracing && ... then ... message: trace functions should only be called if tracing is enabled at compile time languages: [ocaml] severity: WARNING From c0d51c321042153900101d7cf92b489cf119e425 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 3 Nov 2024 17:24:42 +0100 Subject: [PATCH 625/689] Fix `thread` for non-unique spawns --- src/analyses/threadAnalysis.ml | 10 +++--- .../40-threadid/12-multiple-created-only.c | 26 ++++++++++++++++ tests/regression/40-threadid/13-no-crash.c | 31 +++++++++++++++++++ 3 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 tests/regression/40-threadid/12-multiple-created-only.c create mode 100644 tests/regression/40-threadid/13-no-crash.c diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index 07f46e915d..a67c26092c 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -95,9 +95,7 @@ struct let startstate v = D.bot () 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)); + (* ctx is of creator, side-effects to denote non-uniqueness are performed in threadspawn *) [D.bot ()] let threadspawn ctx ~multiple lval f args fctx = @@ -106,9 +104,9 @@ struct let repeated = D.mem tid ctx.local in let eff = match creator with - | `Lifted ctid -> (repeated, TS.singleton ctid, false) - | `Top -> (true, TS.bot (), false) - | `Bot -> (false, TS.bot (), false) + | `Lifted ctid -> (repeated || multiple, TS.singleton ctid, false) + | `Top -> (true, TS.bot (), false) + | `Bot -> (false || multiple, TS.bot (), false) in ctx.sideg tid eff; D.join ctx.local (D.singleton tid) diff --git a/tests/regression/40-threadid/12-multiple-created-only.c b/tests/regression/40-threadid/12-multiple-created-only.c new file mode 100644 index 0000000000..e65021caaf --- /dev/null +++ b/tests/regression/40-threadid/12-multiple-created-only.c @@ -0,0 +1,26 @@ +// PARAM: --set ana.activated[+] thread --set ana.activated[+] threadid --set ana.thread.domain plain + +#include +#include + +int myglobal; +int myglobal2; + +void* bla(void *arg) { + // This is created multiple times, it should race with itself + myglobal = 10; //RACE + return NULL; +} + +void* other(void) { + // This is created only once, it should not be marked as non-unique + unknown(bla); + myglobal2 = 30; //NORACE +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, other, NULL); + + return 0; +} diff --git a/tests/regression/40-threadid/13-no-crash.c b/tests/regression/40-threadid/13-no-crash.c new file mode 100644 index 0000000000..c9a6c7d88b --- /dev/null +++ b/tests/regression/40-threadid/13-no-crash.c @@ -0,0 +1,31 @@ +// PARAM: --set ana.context.gas_value 0 --set ana.activated[+] thread --set ana.activated[+] threadid + +#include +#include + +int myglobal; +int myglobal2; + +void *t_flurb(void *arg) { + myglobal=40; //RACE + return NULL; +} + +void* bla(void *arg) { + return NULL; +} + +void *t_fun(void *arg) { + unknown(t_flurb); // NOCRASH + return NULL; +} + +int main(void) { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_create(&id, NULL, t_fun, NULL); + + unknown(bla); + + return 0; +} From 39d0a8aa8664b9296645a4b69f639179a7224efd Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 4 Nov 2024 10:29:14 +0200 Subject: [PATCH 626/689] Use HM.exists instead of HM.fold in td3 (closes #1618) --- src/solver/td3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/td3.ml b/src/solver/td3.ml index 049dce2a0d..3cab3cf7f7 100644 --- a/src/solver/td3.ml +++ b/src/solver/td3.ml @@ -49,7 +49,7 @@ module Base = open SolverBox.Warrow (S.Dom) include Generic.SolverStats (S) (HM) module VS = Set.Make (S.Var) - let exists_key f hm = HM.fold (fun k _ a -> a || f k) hm false + let exists_key f hm = HM.exists (fun k _ -> f k) hm type solver_data = { st: (S.Var.t * S.Dom.t) list; (* needed to destabilize start functions if their start state changed because of some changed global initializer *) From f7184c06244e8919638a3870a7922fd37a1e817b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 4 Nov 2024 11:08:17 +0200 Subject: [PATCH 627/689] Print innermost backtrace mark for uncaught exception even with backtrace printing off --- src/util/backtrace/goblint_backtrace.ml | 9 ++++++++- src/util/backtrace/goblint_backtrace.mli | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/util/backtrace/goblint_backtrace.ml b/src/util/backtrace/goblint_backtrace.ml index 513753bddb..21d150a470 100644 --- a/src/util/backtrace/goblint_backtrace.ml +++ b/src/util/backtrace/goblint_backtrace.ml @@ -76,12 +76,19 @@ let print_marktrace oc e = Printf.fprintf oc "Marked with %s\n" (mark_to_string m) ) ms +let print_innermost_mark oc e = + match find_marks e with + | m :: _ -> Printf.fprintf oc "Marked with %s\n" (mark_to_string m) + | [] -> () + let () = Printexc.set_uncaught_exception_handler (fun e bt -> (* Copied & modified from Printexc.default_uncaught_exception_handler. *) Printf.eprintf "Fatal error: exception %s\n" (Printexc.to_string e); (* nosemgrep: print-not-logging *) if Printexc.backtrace_status () then - print_marktrace stderr e; + print_marktrace stderr e + else + print_innermost_mark stderr e; Printexc.print_raw_backtrace stderr bt; flush stderr ) diff --git a/src/util/backtrace/goblint_backtrace.mli b/src/util/backtrace/goblint_backtrace.mli index e53bfd826a..ee7052122e 100644 --- a/src/util/backtrace/goblint_backtrace.mli +++ b/src/util/backtrace/goblint_backtrace.mli @@ -32,5 +32,10 @@ val print_marktrace: out_channel -> exn -> unit Used by default for uncaught exceptions. *) +val print_innermost_mark: out_channel -> exn -> unit +(** Print innermost mark of an exception. + + Used by default for uncaught exceptions. *) + val find_marks: exn -> mark list (** Find all marks of an exception. *) From 1bb50df301ddfd63b9a15677c3bf6f9cf5d026ff Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 4 Nov 2024 10:38:13 +0100 Subject: [PATCH 628/689] Use multiple also in bot case Co-authored-by: Simmo Saan --- src/analyses/threadAnalysis.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/threadAnalysis.ml b/src/analyses/threadAnalysis.ml index a67c26092c..435e1a6afe 100644 --- a/src/analyses/threadAnalysis.ml +++ b/src/analyses/threadAnalysis.ml @@ -106,7 +106,7 @@ struct match creator with | `Lifted ctid -> (repeated || multiple, TS.singleton ctid, false) | `Top -> (true, TS.bot (), false) - | `Bot -> (false || multiple, TS.bot (), false) + | `Bot -> (multiple, TS.bot (), false) in ctx.sideg tid eff; D.join ctx.local (D.singleton tid) From eb149f9520a05664bb1d7addd90d6a23f44f5832 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 4 Nov 2024 10:39:24 +0100 Subject: [PATCH 629/689] Move tests --- .../29-multiple-created-only.c} | 0 .../{40-threadid/13-no-crash.c => 10-synch/30-no-crash.c} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression/{40-threadid/12-multiple-created-only.c => 10-synch/29-multiple-created-only.c} (100%) rename tests/regression/{40-threadid/13-no-crash.c => 10-synch/30-no-crash.c} (100%) diff --git a/tests/regression/40-threadid/12-multiple-created-only.c b/tests/regression/10-synch/29-multiple-created-only.c similarity index 100% rename from tests/regression/40-threadid/12-multiple-created-only.c rename to tests/regression/10-synch/29-multiple-created-only.c diff --git a/tests/regression/40-threadid/13-no-crash.c b/tests/regression/10-synch/30-no-crash.c similarity index 100% rename from tests/regression/40-threadid/13-no-crash.c rename to tests/regression/10-synch/30-no-crash.c From 7c4581b400f242bb005e9d329e7594231e156708 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 5 Nov 2024 12:35:34 +0200 Subject: [PATCH 630/689] Remove empty focusOn reachSafety and its (yet) pointless option reachSafetySpecification --- src/autoTune.ml | 4 ---- src/config/options.schema.json | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 8dfcc6480e..3db3729d0d 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -250,8 +250,6 @@ let focusOnTermination (spec: Svcomp.Specification.t) = let focusOnTermination () = List.iter focusOnTermination (Svcomp.Specification.of_option ()) -let reachSafety (spec: Svcomp.Specification.t) = () - let concurrencySafety (spec: Svcomp.Specification.t) = match spec with | NoDataRace -> (*enable all thread analyses*) @@ -538,8 +536,6 @@ let chooseConfig file = if isActivated "mallocWrappers" then findMallocWrappers (); - if isActivated "reachSafetySpecification" then focusOn reachSafety; - if isActivated "concurrencySafetySpecification" then focusOn concurrencySafety; if isActivated "noOverflows" then focusOn noOverflows; diff --git a/src/config/options.schema.json b/src/config/options.schema.json index d8a7d3adc7..746b950547 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -544,7 +544,6 @@ "octagon", "wideningThresholds", "memsafetySpecification", - "reachSafetySpecification", "concurrencySafetySpecification", "noOverflows", "termination", @@ -562,7 +561,6 @@ "octagon", "wideningThresholds", "memsafetySpecification", - "reachSafetySpecification", "concurrencySafetySpecification", "noOverflows", "termination", From 53f540da9d9d1814622255d08c5342234ffe1861 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 5 Nov 2024 12:36:45 +0200 Subject: [PATCH 631/689] Add autotune 'noOverflows' option --- conf/svcomp-validate.json | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/svcomp-validate.json b/conf/svcomp-validate.json index 8e11fee7f5..64564f480f 100644 --- a/conf/svcomp-validate.json +++ b/conf/svcomp-validate.json @@ -67,6 +67,7 @@ "wideningThresholds", "loopUnrollHeuristic", "memsafetySpecification", + "noOverflows", "termination", "tmpSpecialAnalysis" ] From 4e7bfaeb472c4e60c4d84bb8ab7258297672f810 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 5 Nov 2024 12:47:45 +0200 Subject: [PATCH 632/689] Detect mallocs in loops instead of detecting mallocs outside of loops --- src/autoTune.ml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 3db3729d0d..56fdfcca25 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -45,12 +45,14 @@ class functionVisitor(calling, calledBy, argLists, dynamicallyCalled) = object end exception Found -class findAllocsNotInLoops = object +class findAllocsInLoops = object inherit nopCilVisitor + val mutable inloop = false + method! vstmt stmt = match stmt.skind with - | Loop _ -> SkipChildren + | Loop _ -> inloop <- true; DoChildren | _ -> DoChildren method! vinst = function @@ -58,7 +60,7 @@ class findAllocsNotInLoops = object let desc = LibraryFunctions.find f in begin match desc.special args with | Malloc _ - | Alloca _ -> raise Found + | Alloca _ when inloop -> raise Found | _ -> DoChildren end | _ -> DoChildren @@ -263,8 +265,10 @@ let noOverflows (spec: Svcomp.Specification.t) = (*We focus on integer analysis*) set_bool "ana.int.def_exc" true; begin - try ignore @@ visitCilFileSameGlobals (new findAllocsNotInLoops) (!Cilfacade.current_file) - with Found -> set_int "ana.malloc.unique_address_count" 1; + try + ignore @@ visitCilFileSameGlobals (new findAllocsInLoops) (!Cilfacade.current_file); + set_int "ana.malloc.unique_address_count" 1 + with Found -> set_int "ana.malloc.unique_address_count" 0; end | _ -> () From fa31b55e85b54355b0d61c0c4f46272527ec4ea2 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Tue, 5 Nov 2024 15:44:46 +0200 Subject: [PATCH 633/689] Reset inloop after processing children --- src/autoTune.ml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 56fdfcca25..cae6c62c68 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -51,8 +51,13 @@ class findAllocsInLoops = object val mutable inloop = false method! vstmt stmt = + let outOfLoop stmt = + match stmt.skind with + | Loop _ -> inloop <- false; stmt + | _ -> stmt + in match stmt.skind with - | Loop _ -> inloop <- true; DoChildren + | Loop _ -> inloop <- true; ChangeDoChildrenPost(stmt, outOfLoop) | _ -> DoChildren method! vinst = function From b1095fbd71b7360e1a6d7a7d8b9bcc3b790b3bef Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Nov 2024 11:32:06 +0200 Subject: [PATCH 634/689] Add more precise YAML witness generation summary --- src/witness/yamlWitness.ml | 13 ++++++++++++ .../03-practical/35-base-mutex-macos.t | 3 +++ tests/regression/13-privatized/01-priv_nr.t | 9 ++++++++ .../regression/36-apron/12-traces-min-rpb1.t | 3 +++ tests/regression/36-apron/52-queuesize.t | 6 ++++++ .../11-unrolled-loop-invariant.t | 3 +++ tests/regression/56-witness/05-prec-problem.t | 3 +++ .../56-witness/08-witness-all-locals.t | 6 ++++++ .../56-witness/46-top-bool-invariant.t | 21 +++++++++++++++++++ .../56-witness/47-top-int-invariant.t | 21 +++++++++++++++++++ tests/regression/cfg/foo.t/run.t | 3 +++ tests/regression/cfg/issue-1356.t/run.t | 3 +++ tests/regression/cfg/loops.t/run.t | 3 +++ tests/regression/cfg/pr-758.t/run.t | 3 +++ tests/regression/witness/int.t/run.t | 3 +++ tests/regression/witness/typedef.t/run.t | 6 ++++++ 16 files changed, 109 insertions(+) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 2bdd2ced4c..bc31797688 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -249,6 +249,11 @@ struct let entries = [] in + let cnt_loop_invariant = ref 0 in + let cnt_location_invariant = ref 0 in + let cnt_flow_insensitive_invariant = ref 0 in + (* TODO: precondition invariants? *) + (* Generate location invariants (without precondition) *) let entries = if entry_type_enabled YamlWitnessType.LocationInvariant.entry_type then ( @@ -268,6 +273,7 @@ struct List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.location_invariant ~task ~location ~invariant in + incr cnt_location_invariant; entry :: acc ) acc invs | `Bot | `Top -> (* TODO: 0 for bot (dead code)? *) @@ -297,6 +303,7 @@ struct List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.loop_invariant ~task ~location ~invariant in + incr cnt_loop_invariant; entry :: acc ) acc invs | `Bot | `Top -> (* TODO: 0 for bot (dead code)? *) @@ -322,6 +329,7 @@ struct List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.flow_insensitive_invariant ~task ~invariant in + incr cnt_flow_insensitive_invariant; entry :: acc ) acc invs | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) @@ -459,6 +467,7 @@ struct List.fold_left (fun acc inv -> let invariant = CilType.Exp.show inv in let invariant = Entry.location_invariant' ~location ~invariant in + incr cnt_location_invariant; invariant :: acc ) acc invs | `Bot | `Top -> (* TODO: 0 for bot (dead code)? *) @@ -488,6 +497,7 @@ struct List.fold_left (fun acc inv -> let invariant = CilType.Exp.show inv in let invariant = Entry.loop_invariant' ~location ~invariant in + incr cnt_loop_invariant; invariant :: acc ) acc invs | `Bot | `Top -> (* TODO: 0 for bot (dead code)? *) @@ -512,6 +522,9 @@ struct let yaml_entries = List.rev_map YamlWitnessType.Entry.to_yaml entries in (* reverse to make entries in file in the same order as generation messages *) M.msg_group Info ~category:Witness "witness generation summary" [ + (Pretty.dprintf "location invariants: %d" !cnt_location_invariant, None); + (Pretty.dprintf "loop invariants: %d" !cnt_loop_invariant, None); + (Pretty.dprintf "flow-insensitive invariants: %d" !cnt_flow_insensitive_invariant, None); (Pretty.dprintf "total generation entries: %d" (List.length yaml_entries), None); ]; diff --git a/tests/regression/03-practical/35-base-mutex-macos.t b/tests/regression/03-practical/35-base-mutex-macos.t index 9e5f36d337..1d8a184d4c 100644 --- a/tests/regression/03-practical/35-base-mutex-macos.t +++ b/tests/regression/03-practical/35-base-mutex-macos.t @@ -4,6 +4,9 @@ dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 1 There should be no invariants about __sig. diff --git a/tests/regression/13-privatized/01-priv_nr.t b/tests/regression/13-privatized/01-priv_nr.t index bbc285098a..0186709027 100644 --- a/tests/regression/13-privatized/01-priv_nr.t +++ b/tests/regression/13-privatized/01-priv_nr.t @@ -10,6 +10,9 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: + location invariants: 3 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 @@ -64,6 +67,9 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: + location invariants: 3 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 @@ -118,6 +124,9 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: + location invariants: 3 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 5060f505d9..d0cebd6d1c 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -13,6 +13,9 @@ write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) [Info][Witness] witness generation summary: + location invariants: 3 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 diff --git a/tests/regression/36-apron/52-queuesize.t b/tests/regression/36-apron/52-queuesize.t index 62851f2ec9..f0a977891a 100644 --- a/tests/regression/36-apron/52-queuesize.t +++ b/tests/regression/36-apron/52-queuesize.t @@ -37,6 +37,9 @@ Without diff-box: [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (52-queuesize.c:56:10-56:11) [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (52-queuesize.c:78:12-78:13) [Info][Witness] witness generation summary: + location invariants: 8 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 8 [Info][Race] Memory locations race summary: safe: 3 @@ -173,6 +176,9 @@ With diff-box: [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (52-queuesize.c:56:10-56:11) [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (52-queuesize.c:78:12-78:13) [Info][Witness] witness generation summary: + location invariants: 6 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 6 [Info][Race] Memory locations race summary: safe: 3 diff --git a/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t b/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t index 3a3b7c43cf..860ffae3bd 100644 --- a/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t +++ b/tests/regression/55-loop-unrolling/11-unrolled-loop-invariant.t @@ -211,6 +211,9 @@ [Warning][Deadcode][CWE-571] condition 'k < 100' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:9:12-9:19) [Warning][Deadcode][CWE-571] condition 'j < 10' (possibly inserted by CIL) is always true (11-unrolled-loop-invariant.c:8:10-8:16) [Info][Witness] witness generation summary: + location invariants: 11 + loop invariants: 5 + flow-insensitive invariants: 0 total generation entries: 16 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/56-witness/05-prec-problem.t b/tests/regression/56-witness/05-prec-problem.t index 733f16269e..51f92ca203 100644 --- a/tests/regression/56-witness/05-prec-problem.t +++ b/tests/regression/56-witness/05-prec-problem.t @@ -6,6 +6,9 @@ total lines: 13 [Warning][Deadcode][CWE-570] condition '0' (possibly inserted by CIL) is always false (05-prec-problem.c:13:12-13:13) [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 6 TODO: Don't generate duplicate entries from each context: should have generated just 3. diff --git a/tests/regression/56-witness/08-witness-all-locals.t b/tests/regression/56-witness/08-witness-all-locals.t index fc4462201d..fe6aefefbd 100644 --- a/tests/regression/56-witness/08-witness-all-locals.t +++ b/tests/regression/56-witness/08-witness-all-locals.t @@ -4,6 +4,9 @@ dead: 0 total lines: 4 [Info][Witness] witness generation summary: + location invariants: 3 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 3 $ yamlWitnessStrip < witness.yml @@ -50,6 +53,9 @@ Fewer entries are emitted if locals from nested block scopes are excluded: dead: 0 total lines: 4 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/56-witness/46-top-bool-invariant.t b/tests/regression/56-witness/46-top-bool-invariant.t index 741b00966f..be41ef58f2 100644 --- a/tests/regression/56-witness/46-top-bool-invariant.t +++ b/tests/regression/56-witness/46-top-bool-invariant.t @@ -6,6 +6,9 @@ def_exc only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -40,6 +43,9 @@ interval only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -74,6 +80,9 @@ enums only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 1 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 1 $ yamlWitnessStrip < witness.yml @@ -97,6 +106,9 @@ congruence only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 0 $ yamlWitnessStrip < witness.yml @@ -110,6 +122,9 @@ interval_set only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -144,6 +159,9 @@ all: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 1 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 1 $ yamlWitnessStrip < witness.yml @@ -167,6 +185,9 @@ all without inexact-type-bounds: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 0 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/56-witness/47-top-int-invariant.t b/tests/regression/56-witness/47-top-int-invariant.t index cdfe65673f..35d5978c00 100644 --- a/tests/regression/56-witness/47-top-int-invariant.t +++ b/tests/regression/56-witness/47-top-int-invariant.t @@ -6,6 +6,9 @@ def_exc only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -40,6 +43,9 @@ interval only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -74,6 +80,9 @@ enums only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -108,6 +117,9 @@ congruence only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 0 $ yamlWitnessStrip < witness.yml @@ -121,6 +133,9 @@ interval_set only: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -155,6 +170,9 @@ all: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 2 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 2 $ yamlWitnessStrip < witness.yml @@ -189,6 +207,9 @@ all without inexact-type-bounds: dead: 0 total lines: 2 [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 0 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/cfg/foo.t/run.t b/tests/regression/cfg/foo.t/run.t index cd890b7a19..19873d7540 100644 --- a/tests/regression/cfg/foo.t/run.t +++ b/tests/regression/cfg/foo.t/run.t @@ -67,6 +67,9 @@ total lines: 6 [Warning][Deadcode][CWE-571] condition 'a > 0' (possibly inserted by CIL) is always true (foo.c:3:10-3:20) [Info][Witness] witness generation summary: + location invariants: 8 + loop invariants: 2 + flow-insensitive invariants: 0 total generation entries: 10 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/cfg/issue-1356.t/run.t b/tests/regression/cfg/issue-1356.t/run.t index aee9456b61..d1fcb3c7ef 100644 --- a/tests/regression/cfg/issue-1356.t/run.t +++ b/tests/regression/cfg/issue-1356.t/run.t @@ -99,6 +99,9 @@ dead: 0 total lines: 13 [Info][Witness] witness generation summary: + location invariants: 0 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 0 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/cfg/loops.t/run.t b/tests/regression/cfg/loops.t/run.t index 6596e7b4a4..1fd19b41fe 100644 --- a/tests/regression/cfg/loops.t/run.t +++ b/tests/regression/cfg/loops.t/run.t @@ -219,6 +219,9 @@ dead: 0 total lines: 20 [Info][Witness] witness generation summary: + location invariants: 32 + loop invariants: 21 + flow-insensitive invariants: 0 total generation entries: 53 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/cfg/pr-758.t/run.t b/tests/regression/cfg/pr-758.t/run.t index 58bbb88ce4..082c63e860 100644 --- a/tests/regression/cfg/pr-758.t/run.t +++ b/tests/regression/cfg/pr-758.t/run.t @@ -93,6 +93,9 @@ dead: 0 total lines: 6 [Info][Witness] witness generation summary: + location invariants: 10 + loop invariants: 2 + flow-insensitive invariants: 0 total generation entries: 12 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/witness/int.t/run.t b/tests/regression/witness/int.t/run.t index 6b4784ce32..9448ac7855 100644 --- a/tests/regression/witness/int.t/run.t +++ b/tests/regression/witness/int.t/run.t @@ -7,6 +7,9 @@ dead: 0 total lines: 10 [Info][Witness] witness generation summary: + location invariants: 3 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 3 $ yamlWitnessStrip < witness.yml diff --git a/tests/regression/witness/typedef.t/run.t b/tests/regression/witness/typedef.t/run.t index 55dcc1f911..f9fac0c743 100644 --- a/tests/regression/witness/typedef.t/run.t +++ b/tests/regression/witness/typedef.t/run.t @@ -4,6 +4,9 @@ dead: 0 total lines: 6 [Info][Witness] witness generation summary: + location invariants: 13 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 13 $ yamlWitnessStrip < witness.yml @@ -157,6 +160,9 @@ dead: 0 total lines: 6 [Info][Witness] witness generation summary: + location invariants: 14 + loop invariants: 0 + flow-insensitive invariants: 0 total generation entries: 14 $ yamlWitnessStrip < witness.yml From 77190828a810819b5b607c59d1553fc713b1be9d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Nov 2024 11:45:13 +0200 Subject: [PATCH 635/689] Add witness.yaml.strict option description --- src/config/options.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 447290b44d..9c1f9e1e76 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2659,7 +2659,7 @@ }, "strict": { "title": "witness.yaml.strict", - "description": "", + "description": "Fail YAML witness validation if there's an error/unsupported/disabled entry.", "type": "boolean", "default": false }, From 546a8d04ede0d6646e1d5b20095c0ae5e2f0a78b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Nov 2024 11:49:17 +0200 Subject: [PATCH 636/689] Update YAML witness validation result for refutation under new scoring schema --- src/witness/yamlWitness.ml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index bc31797688..1a8c536da5 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -892,7 +892,9 @@ struct | true when !cnt_disabled > 0 -> Error "witness disabled" | _ when !cnt_refuted > 0 -> - Ok (Svcomp.Result.False None) + (* Refuted only when assuming the invariant is reachable. *) + (* Ok (Svcomp.Result.False None) *) (* Wasn't a problem because valid*->correctness->false gave 0 points under old validator track scoring schema: https://doi.org/10.1007/978-3-031-22308-2_8. *) + Ok Svcomp.Result.Unknown (* Now valid*->correctness->false gives 1p (negative) points under new validator track scoring schema: https://doi.org/10.1007/978-3-031-57256-2_15. *) | _ when !cnt_unconfirmed > 0 -> Ok Unknown | _ -> From 2048122f114dd24acaa0ff8b4fbd431d92c291f8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 6 Nov 2024 11:57:42 +0200 Subject: [PATCH 637/689] Fix YAML witness validate/unassume error with empty (unparsable) path Raised an obscure Invalid_argument exception instead. --- src/analyses/unassumeAnalysis.ml | 2 +- src/witness/yamlWitness.ml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 615dbd3266..707e0f4820 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -71,7 +71,7 @@ struct | _ -> () ); - let yaml = match Yaml_unix.of_file (Fpath.v (GobConfig.get_string "witness.yaml.unassume")) with + let yaml = match GobResult.Syntax.(Fpath.of_string (GobConfig.get_string "witness.yaml.unassume") >>= Yaml_unix.of_file) with | Ok yaml -> yaml | Error (`Msg m) -> Logs.error "Yaml_unix.of_file: %s" m; diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 1a8c536da5..06e355068e 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -608,7 +608,7 @@ struct let inv_parser = InvariantParser.create FileCfg.file in - let yaml = match Yaml_unix.of_file (Fpath.v (GobConfig.get_string "witness.yaml.validate")) with + let yaml = match GobResult.Syntax.(Fpath.of_string (GobConfig.get_string "witness.yaml.validate") >>= Yaml_unix.of_file) with | Ok yaml -> yaml | Error (`Msg m) -> Logs.error "Yaml_unix.of_file: %s" m; From 9f7ef77000ef2a86e24c060c767f19ea2840e121 Mon Sep 17 00:00:00 2001 From: Karoliine Holter Date: Wed, 6 Nov 2024 20:13:37 +0200 Subject: [PATCH 638/689] Add backtrace marker around LibraryFunctions special call --- src/autoTune.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autoTune.ml b/src/autoTune.ml index cae6c62c68..3277291823 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -62,6 +62,7 @@ class findAllocsInLoops = object method! vinst = function | Call (_, Lval (Var f, NoOffset), args,_,_) -> + Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo f) ~finally:Fun.id @@ fun () -> let desc = LibraryFunctions.find f in begin match desc.special args with | Malloc _ From 72bf7d6e7815c27acee1d8b7feedadd8109baff6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 7 Nov 2024 10:14:18 +0200 Subject: [PATCH 639/689] Add is_special check to AutoTune.findAllocsInLoops --- src/autoTune.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoTune.ml b/src/autoTune.ml index 3277291823..05f651ee62 100644 --- a/src/autoTune.ml +++ b/src/autoTune.ml @@ -61,7 +61,7 @@ class findAllocsInLoops = object | _ -> DoChildren method! vinst = function - | Call (_, Lval (Var f, NoOffset), args,_,_) -> + | Call (_, Lval (Var f, NoOffset), args,_,_) when LibraryFunctions.is_special f -> Goblint_backtrace.protect ~mark:(fun () -> Cilfacade.FunVarinfo f) ~finally:Fun.id @@ fun () -> let desc = LibraryFunctions.find f in begin match desc.special args with From 065f990a3b35269d36d8b6384deef29d4edb76fa Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 8 Nov 2024 15:39:43 +0200 Subject: [PATCH 640/689] Add 27-inv_invariants/22-mine-tutorial-ex4.4 as test --- .../22-mine-tutorial-ex4.4.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/regression/27-inv_invariants/22-mine-tutorial-ex4.4.c diff --git a/tests/regression/27-inv_invariants/22-mine-tutorial-ex4.4.c b/tests/regression/27-inv_invariants/22-mine-tutorial-ex4.4.c new file mode 100644 index 0000000000..9770d03de7 --- /dev/null +++ b/tests/regression/27-inv_invariants/22-mine-tutorial-ex4.4.c @@ -0,0 +1,38 @@ +// PARAM: --enable ana.int.interval +#include +int main() { + int x, y, z; + __goblint_assume(0 <= x); + __goblint_assume(x <= 10); + __goblint_assume(5 <= y); + __goblint_assume(y <= 15); + __goblint_assume(-10 <= z); + __goblint_assume(z <= 10); + + if (x >= y) { + __goblint_check(5 <= x); + __goblint_check(y <= 10); // why doesn't Miné refine this? + } + + if (z >= x) { + __goblint_check(0 <= z); + } + + if (x >= y && z >= x) { // CIL transform does branches sequentially (good order) + __goblint_check(5 <= x); + __goblint_check(y <= 10); // why doesn't Miné refine this? + __goblint_check(0 <= z); + + __goblint_check(5 <= z); + } + + if (z >= x && x >= y) { // CIL transform does branches sequentially (bad order) + __goblint_check(5 <= x); + __goblint_check(y <= 10); // why doesn't Miné refine this? + __goblint_check(0 <= z); + + __goblint_check(5 <= z); // TODO + } + + return 0; +} From f2f0c12d0a3ba6946430c467f812b72acc8ad4e0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Nov 2024 10:48:10 +0200 Subject: [PATCH 641/689] Error on must-relocking of non-recursive mutex mayLocks analysis can warn on it, but mutex analysis can be definite about it. --- src/analyses/mutexAnalysis.ml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 9b6aa4f4ca..a608b3b6e3 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -121,14 +121,17 @@ struct let add ctx ((addr, rw): AddrRW.t): D.t = match addr with - | Addr mv -> + | Addr ((v, o) as mv) -> let (s, m) = ctx.local in let s' = MustLocksetRW.add_mval_rw (mv, rw) s in let m' = - if MutexTypeAnalysis.must_be_recursive ctx mv then - MustMultiplicity.increment mv m - else + match ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) with + | `Lifted Recursive -> MustMultiplicity.increment mv m + | `Lifted NonRec -> + if MustLocksetRW.mem_mval mv s then + M.error ~category:M.Category.Behavior.Undefined.double_locking "Acquiring a non-recursive mutex that is already held"; m + | `Bot | `Top -> m in (s', m') | NullPtr -> From 8d8b6752af3d23260a9c5ab080eb26bdf740006d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Nov 2024 17:40:49 +0200 Subject: [PATCH 642/689] Remove outdated comments about new __VERIFIER_nondet functions --- lib/sv-comp/stub/src/sv-comp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/sv-comp/stub/src/sv-comp.c b/lib/sv-comp/stub/src/sv-comp.c index 12c04125d6..469a641e73 100644 --- a/lib/sv-comp/stub/src/sv-comp.c +++ b/lib/sv-comp/stub/src/sv-comp.c @@ -35,10 +35,10 @@ __VERIFIER_nondet2(unsigned int, u32) __VERIFIER_nondet2(unsigned short int, u16) // not in rules __VERIFIER_nondet2(unsigned char, u8) // not in rules __VERIFIER_nondet2(unsigned char, unsigned_char) // not in rules -__VERIFIER_nondet2(long long, longlong) // not in rules yet (https://gitlab.com/sosy-lab/benchmarking/sv-benchmarks/-/issues/1341) -__VERIFIER_nondet2(unsigned long long, ulonglong) // not in rules yet (https://gitlab.com/sosy-lab/benchmarking/sv-benchmarks/-/issues/1341) -__VERIFIER_nondet2(__uint128_t, uint128) // not in rules yet (https://gitlab.com/sosy-lab/benchmarking/sv-benchmarks/-/issues/1341) -__VERIFIER_nondet2(__int128_t, int128) // not in rules yet (https://gitlab.com/sosy-lab/benchmarking/sv-benchmarks/-/issues/1341) +__VERIFIER_nondet2(long long, longlong) +__VERIFIER_nondet2(unsigned long long, ulonglong) +__VERIFIER_nondet2(__uint128_t, uint128) +__VERIFIER_nondet2(__int128_t, int128) __VERIFIER_nondet2(unsigned char, uchar) __VERIFIER_nondet2(unsigned int, uint) __VERIFIER_nondet2(unsigned long, ulong) From 6a05022657c9da91e90cea46c0c420650a77fb16 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Nov 2024 13:37:44 +0200 Subject: [PATCH 643/689] Add initial CHANGELOG for SV-COMP 2025 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 420cc7145e..6e9fe29306 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## v2.5.0 (unreleased) +Functionally equivalent to Goblint in SV-COMP 2025. + +### SV-COMP 2025 +* Improve invariants (#1361, #1362, #1375, #1328, #1493, #1356). +* Simplify invariants (#1436, #1517). +* Improve YAML witness locations (#1355, #1372, #1400, #1403). +* Improve autotuner (#1469, #1450, #1612, #1604, #1181). +* Loop unrolling (#1582, #1583, #1584, #1516, #1590, #1595, #1599). +* Add abortUnless to svcomp (#1464). +* Fix spurious overflow warnings (#1511). +* Add primitive YAML violation witness rejection (#1301, #1512). +* Machdep support (#54, #1574). + ## v2.4.0 * Remove unmaintained analyses: spec, file (#1281). * Add linear two-variable equalities analysis (#1297, #1412, #1466). From 152ebb633d32275d8cb9924fd54541c2ac64917b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Nov 2024 13:51:22 +0200 Subject: [PATCH 644/689] Add initial CHANGELOG for v2.5.0 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e9fe29306..aec84573cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ## v2.5.0 (unreleased) Functionally equivalent to Goblint in SV-COMP 2025. +* Cleanup (#1095, #1523, #1554, #1575, #1588, #1597, #1614). +* Reduce hash collisions (#1594, #1602). +* Context gas per function (#1569, #1570, #1598). + ### SV-COMP 2025 * Improve invariants (#1361, #1362, #1375, #1328, #1493, #1356). * Simplify invariants (#1436, #1517). From 64981452f455f42cef61de0ab044f3131497db6d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 18 Nov 2024 14:08:10 +0200 Subject: [PATCH 645/689] Add CHANGELOG for v2.5.0 --- CHANGELOG.md | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aec84573cf..cf6a8aa781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,13 @@ ## v2.5.0 (unreleased) Functionally equivalent to Goblint in SV-COMP 2025. -* Cleanup (#1095, #1523, #1554, #1575, #1588, #1597, #1614). -* Reduce hash collisions (#1594, #1602). -* Context gas per function (#1569, #1570, #1598). - -### SV-COMP 2025 -* Improve invariants (#1361, #1362, #1375, #1328, #1493, #1356). -* Simplify invariants (#1436, #1517). -* Improve YAML witness locations (#1355, #1372, #1400, #1403). -* Improve autotuner (#1469, #1450, #1612, #1604, #1181). -* Loop unrolling (#1582, #1583, #1584, #1516, #1590, #1595, #1599). -* Add abortUnless to svcomp (#1464). -* Fix spurious overflow warnings (#1511). -* Add primitive YAML violation witness rejection (#1301, #1512). -* Machdep support (#54, #1574). +* Add 32bit vs 64bit architecture support (#54, #1574). +* Add per-function context gas analysis (#1569, #1570, #1598). +* Adapt automatic static loop unrolling (#1516, #1582, #1583, #1584, #1590, #1595, #1599). +* Adapt automatic configuration tuning (#1450, #1612, #1181, #1604). +* Simplify non-relational integer invariants in witnesses (#1517). +* Fix excessive hash collisions (#1594, #1602). +* Clean up various code (#1095, #1523, #1554, #1575, #1588, #1597, #1614). ## v2.4.0 * Remove unmaintained analyses: spec, file (#1281). @@ -28,7 +21,7 @@ Functionally equivalent to Goblint in SV-COMP 2025. * Fix mutex type analysis unsoundness and enable it by default (#1414, #1416, #1510). * Add points-to set refinement on mutex path splitting (#1287, #1343, #1374, #1396, #1407). * Improve narrowing operators (#1502, #1540, #1543). -* Extract automatic configuration tuning for soundness (#1369). +* Extract automatic configuration tuning for soundness (#1469). * Fix many locations in witnesses (#1355, #1372, #1400, #1403). * Improve output readability (#1294, #1312, #1405, #1497). * Refactor logging (#1117). From ced56ca4882ae5c461d1a7aefd435e814283c02a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:06:41 +0200 Subject: [PATCH 646/689] Document YamlEntryGlobal and InvariantGlobalNodes queries --- src/domains/queries.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 5436e5f7e0..e3a0a3e776 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -131,9 +131,9 @@ type _ t = | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t | GasExhausted: MustBool.t t - | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t + | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t (** YAML witness entries for a global unknown ([Obj.t] represents [Spec.V.t]) and YAML witness task. *) | GhostVarAvailable: WitnessGhostVar.t -> MayBool.t t - | InvariantGlobalNodes: NS.t t (* TODO: V.t argument? *) + | InvariantGlobalNodes: NS.t t (** Nodes where YAML witness flow-insensitive invariants should be emitted as location invariants (if [witness.invariant.flow_insensitive-as] is configured to do so). *) (* [Spec.V.t] argument (as [Obj.t]) could be added, if this should be different for different flow-insensitive invariants. *) type 'a result = 'a From 969b87a02e7e956beb8911dc753c42918510a48d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:10:38 +0200 Subject: [PATCH 647/689] Replace privatization invariant_global mutex_inits TODO with comment --- src/analyses/apron/relationPriv.apron.ml | 2 +- src/analyses/basePriv.ml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 9b25abb371..abaaa0d9b8 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -722,7 +722,7 @@ struct let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in let exact = GobConfig.get_bool "witness.invariant.exact" in - let rel = keep_only_protected_globals ask m' (get_m_with_mutex_inits ask getg m') in (* TODO: disjunct with mutex_inits instead of join? *) + let rel = keep_only_protected_globals ask m' (get_m_with_mutex_inits ask getg m') in (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) let inv = RD.invariant rel |> List.enum diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 347a365778..7a67d0e0fc 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -250,7 +250,7 @@ struct let invariant_global ask getg = function | `Right g' -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g' (* TODO: disjunct with mutex_inits instead of join? *) + ValueDomain.invariant_global (read_unprotected_global getg) g' (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) | _ -> (* mutex *) Invariant.none @@ -343,7 +343,7 @@ struct | `Left m' -> (* mutex *) let atomic = LockDomain.MustLock.equal m' (LockDomain.MustLock.of_var LibraryFunctions.verifier_atomic_var) in if atomic || ask.f (GhostVarAvailable (Locked m')) then ( - let cpa = get_m_with_mutex_inits ask getg m' in (* TODO: disjunct with mutex_inits instead of join? *) + let cpa = get_m_with_mutex_inits ask getg m' in (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) let inv = CPA.fold (fun v _ acc -> if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in @@ -704,7 +704,7 @@ struct let invariant_global ask getg = function | `Middle g -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g (* TODO: disjunct with mutex_inits instead of join? *) + ValueDomain.invariant_global (read_unprotected_global getg) g (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) | `Left _ | `Right _ -> (* mutex or thread *) Invariant.none From 4940658a23799a16f78731570ca9921ff8f2b0f2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:15:27 +0200 Subject: [PATCH 648/689] Apply suggestions from code review Co-authored-by: Julian Erhard --- src/analyses/mutexGhosts.ml | 1 - src/witness/witnessGhostVar.ml | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 09afc41baa..87e7281028 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -10,7 +10,6 @@ struct include UnitAnalysis.Spec let name () = "mutexGhosts" - (* module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) *) module V = struct include Printable.Either3 (Node) (LockDomain.MustLock) (BoolDomain.Bool) diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index 82813b4a65..0d71909ba0 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -35,9 +35,9 @@ include Printable.SimpleShow (struct let describe_varinfo _ _ = "" let typ = function - | Locked _ -> GoblintCil.intType + | Locked _ | Multithreaded -> GoblintCil.intType let initial = function - | Locked _ -> GoblintCil.zero + | Locked _ | Multithreaded -> GoblintCil.zero From 09045bc232f7cf0e36389534eb3fc5e56e1d81d7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:32:17 +0200 Subject: [PATCH 649/689] Add nontrivial condition for querying YamlEntryGlobal at all --- src/witness/yamlWitness.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index f8890d8eaa..ec83fa04fb 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -397,7 +397,7 @@ struct (* Generate flow-insensitive entries (ghost variables and ghost updates) *) let entries = - if true then ( + if (entry_type_enabled YamlWitnessType.GhostVariable.entry_type && entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) From 3a07c1615d9a4888a0e972fc6da69719d91e9fb6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:47:07 +0200 Subject: [PATCH 650/689] Remove old unnecessary branching from ghost_update YAML witness entries --- src/witness/yamlWitnessType.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 7834951892..fa2d55d2c2 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -464,7 +464,6 @@ struct variable: string; expression: string; location: Location.t; - (* TODO: branching? *) } [@@deriving eq, ord, hash] From 9a3a338287664b9697bf2eaa0eca378bd5be247b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:53:46 +0200 Subject: [PATCH 651/689] Implement YamlWitnessType.Entry pretty-printing --- src/witness/yamlWitnessType.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index fa2d55d2c2..6ec133c7d6 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -693,12 +693,6 @@ struct let name () = "YAML entry" - let show _ = "TODO" - include Printable.SimpleShow (struct - type nonrec t = t - let show = show - end) - let to_yaml {entry_type; metadata} = `O ([ ("entry_type", `String (EntryType.entry_type entry_type)); @@ -710,4 +704,10 @@ struct let+ metadata = y |> find "metadata" >>= Metadata.of_yaml and+ entry_type = y |> EntryType.of_yaml in {entry_type; metadata} + + let pp ppf x = Yaml.pp ppf (to_yaml x) + include Printable.SimpleFormat (struct + type nonrec t = t + let pp = pp + end) end From 34277e041b43c093d2d635a586e10686c35a3f8e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 11:24:42 +0200 Subject: [PATCH 652/689] Use sets instead of BatList.mem_cmp for deduplicating ghost witness variables --- src/analyses/mutexGhosts.ml | 19 ++++++------------- src/witness/yamlWitness.ml | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 87e7281028..6542ab3607 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -114,6 +114,8 @@ struct let ghost_var_available ctx v = WitnessGhost.enabled () && ghost_var_available ctx v + module VariableSet = Set.Make (YamlWitnessType.GhostInstrumentation.Variable) + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | GhostVarAvailable v -> ghost_var_available ctx v @@ -173,15 +175,11 @@ struct let (variables, location_updates) = NodeSet.fold (fun node (variables, location_updates) -> let (locked, unlocked, multithread) = G.node (ctx.global (V.node node)) in let variables' = - (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> match mustlock_of_addr l with | Some l when ghost_var_available ctx (Locked l) -> let variable = WitnessGhost.variable' (Locked l) in - if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable acc then (* TODO: be efficient *) - acc - else - variable :: acc + VariableSet.add variable acc | _ -> acc ) (Locked.union locked unlocked) variables @@ -211,12 +209,7 @@ struct if ghost_var_available ctx Multithreaded then ( let variable = WitnessGhost.variable' Multithreaded in let update = WitnessGhost.update' Multithreaded GoblintCil.one in - let variables' = - if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable variables' then (* TODO: be efficient *) - variables' - else - variable :: variables' - in + let variables' = VariableSet.add variable variables' in (variables', update :: updates) ) else @@ -227,9 +220,9 @@ struct in let location_update = WitnessGhost.location_update' ~node ~updates in (variables', location_update :: location_updates) - ) nodes ([], []) + ) nodes (VariableSet.empty, []) in - let entry = WitnessGhost.instrumentation_entry ~task ~variables ~location_updates in + let entry = WitnessGhost.instrumentation_entry ~task ~variables:(VariableSet.elements variables) ~location_updates in Queries.YS.singleton entry | `Left _ -> Queries.Result.top q | `Middle _ -> Queries.Result.top q diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index ec83fa04fb..a044750a79 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -398,23 +398,24 @@ struct (* Generate flow-insensitive entries (ghost variables and ghost updates) *) let entries = if (entry_type_enabled YamlWitnessType.GhostVariable.entry_type && entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( - GHT.fold (fun g v acc -> + let module EntrySet = Queries.YS in + fst @@ GHT.fold (fun g v accs -> match g with | `Left g -> (* Spec global *) begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with | `Lifted _ as inv -> - Queries.YS.fold (fun entry acc -> - if BatList.mem_cmp YamlWitnessType.Entry.compare entry acc then (* TODO: be efficient *) - acc + Queries.YS.fold (fun entry (acc, acc') -> + if EntrySet.mem entry acc' then (* deduplicate only with other global entries because local ones have different locations anyway *) + accs else - entry :: acc - ) inv acc + (entry :: acc, EntrySet.add entry acc') + ) inv accs | `Top -> - acc + accs end | `Right _ -> (* contexts global *) - acc - ) gh entries + accs + ) gh (entries, EntrySet.empty ()) ) else entries From 7929d633ee5dc3e30c3607596850bcb64995352f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 11:48:58 +0200 Subject: [PATCH 653/689] Extract fold_flow_insensitive_as_location in YamlWitness to deduplicate code --- src/witness/yamlWitness.ml | 56 ++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index a044750a79..b0ffac5852 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -353,6 +353,22 @@ struct let invariant_global_nodes = lazy (R.ask_global InvariantGlobalNodes) in + let fold_flow_insensitive_as_location ~inv f acc = + (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + let invs = WitnessUtil.InvariantExp.process_exp inv in + Queries.NS.fold (fun n acc -> + let fundec = Node.find_fundec n in + match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + | Some loc -> + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + f ~location ~inv acc + ) acc invs + | None -> acc + ) (Lazy.force invariant_global_nodes) acc + in + (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( @@ -368,21 +384,11 @@ struct entry :: acc ) acc invs | `Lifted inv, "location_invariant" -> - (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) - let invs = WitnessUtil.InvariantExp.process_exp inv in - Queries.NS.fold (fun n acc -> - let fundec = Node.find_fundec n in - match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) - | Some loc -> - let location_function = fundec.svar.vname in - let location = Entry.location ~location:loc ~location_function in - List.fold_left (fun acc inv -> - let invariant = Entry.invariant (CilType.Exp.show inv) in - let entry = Entry.location_invariant ~task ~location ~invariant in - entry :: acc - ) acc invs - | None -> acc - ) (Lazy.force invariant_global_nodes) acc + fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> + let invariant = Entry.invariant (CilType.Exp.show inv) in + let entry = Entry.location_invariant ~task ~location ~invariant in + entry :: acc + ) acc | `Lifted _, _ | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc @@ -595,21 +601,11 @@ struct | `Left g -> (* Spec global *) begin match R.ask_global (InvariantGlobal (Obj.repr g)) with | `Lifted inv -> - (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) - let invs = WitnessUtil.InvariantExp.process_exp inv in - Queries.NS.fold (fun n acc -> - let fundec = Node.find_fundec n in - match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) - | Some loc -> - let location_function = fundec.svar.vname in - let location = Entry.location ~location:loc ~location_function in - List.fold_left (fun acc inv -> - let invariant = CilType.Exp.show inv in - let invariant = Entry.location_invariant' ~location ~invariant in - invariant :: acc - ) acc invs - | None -> acc - ) (Lazy.force invariant_global_nodes) acc + fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> + let invariant = CilType.Exp.show inv in + let invariant = Entry.location_invariant' ~location ~invariant in + invariant :: acc + ) acc | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end From 8a0240ddb8753ab6e40691c301550c602fe821cb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 12:08:02 +0200 Subject: [PATCH 654/689] Update ghost witness related TODOs and comments --- src/analyses/apron/relationPriv.apron.ml | 2 +- src/analyses/basePriv.ml | 2 +- src/witness/yamlWitness.ml | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index abaaa0d9b8..02ebe4d0e6 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -747,7 +747,7 @@ struct else Invariant.none | g -> (* global *) - Invariant.none (* TODO: ? *) + Invariant.none (* Could output unprotected one-variable (so non-relational) invariants, but probably not very useful. [BasePriv] does those anyway. *) end (** May written variables. *) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7a67d0e0fc..c46492b7c7 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -891,7 +891,7 @@ struct else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( - let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) + let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: This takes protected values of every [g], not just [g'], which might be unsound with pointers. See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698136411. *) (* Very conservative about multiple (write-)protecting mutexes: invariant is not claimed when any of them is held. It should be possible to be more precise because writes only happen with all of them held, but conjunction is unsound when one of the mutexes is temporarily unlocked. diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index b0ffac5852..159892fd20 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -354,11 +354,13 @@ struct let invariant_global_nodes = lazy (R.ask_global InvariantGlobalNodes) in let fold_flow_insensitive_as_location ~inv f acc = - (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + (* Currently same invariants (from InvariantGlobal query) for all nodes (from InvariantGlobalNodes query). + The alternative would be querying InvariantGlobal per local unknown when looping over them to generate location invariants. + See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698149514. *) let invs = WitnessUtil.InvariantExp.process_exp inv in Queries.NS.fold (fun n acc -> let fundec = Node.find_fundec n in - match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + match WitnessInvariant.location_location n with (* Not just using Node.location because it returns expression location which may be invalid for location invariant (e.g. inside conditional). *) | Some loc -> let location_function = fundec.svar.vname in let location = Entry.location ~location:loc ~location_function in @@ -374,7 +376,7 @@ struct if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( GHT.fold (fun g v acc -> match g with - | `Left g -> (* Spec global *) + | `Left g -> (* global unknown from analysis Spec *) begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_string "witness.invariant.flow_insensitive-as" with | `Lifted inv, "flow_insensitive_invariant" -> let invs = WitnessUtil.InvariantExp.process_exp inv in @@ -393,7 +395,7 @@ struct | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end - | `Right _ -> (* contexts global *) + | `Right _ -> (* global unknown for FromSpec contexts *) acc ) gh entries ) @@ -407,7 +409,7 @@ struct let module EntrySet = Queries.YS in fst @@ GHT.fold (fun g v accs -> match g with - | `Left g -> (* Spec global *) + | `Left g -> (* global unknown from analysis Spec *) begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with | `Lifted _ as inv -> Queries.YS.fold (fun entry (acc, acc') -> @@ -419,7 +421,7 @@ struct | `Top -> accs end - | `Right _ -> (* contexts global *) + | `Right _ -> (* global unknown for FromSpec contexts *) accs ) gh (entries, EntrySet.empty ()) ) @@ -598,7 +600,7 @@ struct if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type && GobConfig.get_string "witness.invariant.flow_insensitive-as" = "invariant_set-location_invariant" then ( GHT.fold (fun g v acc -> match g with - | `Left g -> (* Spec global *) + | `Left g -> (* global unknown from analysis Spec *) begin match R.ask_global (InvariantGlobal (Obj.repr g)) with | `Lifted inv -> fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> @@ -609,7 +611,7 @@ struct | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end - | `Right _ -> (* contexts global *) + | `Right _ -> (* global unknown for FromSpec contexts *) acc ) gh invariants ) From aeb2376811f30d6d9b7f814b685d04643ede5190 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 15:31:39 +0200 Subject: [PATCH 655/689] Clean up Z_mlgmpidl usages --- src/cdomains/apron/apronDomain.apron.ml | 2 +- src/cdomains/apron/gobApron.apron.ml | 2 ++ src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml | 2 +- src/cdomains/apron/sharedFunctions.apron.ml | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cdomains/apron/apronDomain.apron.ml b/src/cdomains/apron/apronDomain.apron.ml index 03ac3ed3f0..043b728799 100644 --- a/src/cdomains/apron/apronDomain.apron.ml +++ b/src/cdomains/apron/apronDomain.apron.ml @@ -19,7 +19,7 @@ module M = Messages let widening_thresholds_apron = ResettableLazy.from_fun (fun () -> let t = if GobConfig.get_string "ana.apron.threshold_widening_constants" = "comparisons" then WideningThresholds.octagon_thresholds () else WideningThresholds.thresholds_incl_mul2 () in - let r = List.map (fun x -> Apron.Scalar.of_mpqf @@ Mpqf.of_mpz @@ Z_mlgmpidl.mpz_of_z x) t in + let r = List.map Scalar.of_z t in Array.of_list r ) diff --git a/src/cdomains/apron/gobApron.apron.ml b/src/cdomains/apron/gobApron.apron.ml index fbb1fe9ec5..327e43e321 100644 --- a/src/cdomains/apron/gobApron.apron.ml +++ b/src/cdomains/apron/gobApron.apron.ml @@ -12,6 +12,8 @@ struct let pp = pp end ) + + let of_z z = of_mpqf (Mpqf.of_mpz (Z_mlgmpidl.mpz_of_z z)) end module Coeff = diff --git a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml index c1ca3661a5..6af7030a51 100644 --- a/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml +++ b/src/cdomains/apron/linearTwoVarEqualityDomain.apron.ml @@ -790,7 +790,7 @@ struct let of_coeff xi coeffs o = let typ = (Option.get @@ V.to_cil_varinfo xi).vtype in let ikind = Cilfacade.get_ikind typ in - let cst = Coeff.s_of_mpqf @@ Mpqf.of_mpz (Z_mlgmpidl.mpz_of_z @@ IntDomain.Size.cast ikind o) in + let cst = Coeff.s_of_z (IntDomain.Size.cast ikind o) in let lincons = Lincons1.make (Linexpr1.make t.env) Lincons1.EQ in Lincons1.set_list lincons coeffs (Some cst); lincons diff --git a/src/cdomains/apron/sharedFunctions.apron.ml b/src/cdomains/apron/sharedFunctions.apron.ml index 86b5f2770f..b9d93bfd99 100644 --- a/src/cdomains/apron/sharedFunctions.apron.ml +++ b/src/cdomains/apron/sharedFunctions.apron.ml @@ -133,7 +133,7 @@ struct else failwith "texpr1_expr_of_cil_exp: globals must be replaced with temporary locals" | Const (CInt (i, _, _)) -> - Cst (Coeff.s_of_mpqf (Mpqf.of_mpz (Z_mlgmpidl.mpz_of_z i))) + Cst (Coeff.s_of_z i) | exp -> match Cilfacade.get_ikind_exp exp with | ik -> @@ -175,7 +175,7 @@ struct (* convert response to a constant *) let const = IntDomain.IntDomTuple.to_int @@ IntDomain.IntDomTuple.cast_to t_ik res in match const with - | Some c -> Cst (Coeff.s_of_mpqf (Mpqf.of_mpz (Z_mlgmpidl.mpz_of_z c))) (* Got a constant value -> use it straight away *) + | Some c -> Cst (Coeff.s_of_z c) (* Got a constant value -> use it straight away *) (* I gotten top, we can not guarantee injectivity *) | None -> if IntDomain.IntDomTuple.is_top_of t_ik res then raise (Unsupported_CilExp (Cast_not_injective t)) else ( (* Got a ranged value different from top, so let's check bounds manually *) From 64c11c2748d2981346d909392423fde938c8ca8c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 16:10:36 +0200 Subject: [PATCH 656/689] Add test 56-witness/69-ghost-ptr-protection for unsound protection flow-sensitive invariant --- .../56-witness/69-ghost-ptr-protection.c | 30 ++++++ .../56-witness/69-ghost-ptr-protection.t | 101 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 tests/regression/56-witness/69-ghost-ptr-protection.c create mode 100644 tests/regression/56-witness/69-ghost-ptr-protection.t diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.c b/tests/regression/56-witness/69-ghost-ptr-protection.c new file mode 100644 index 0000000000..f5557f3fc8 --- /dev/null +++ b/tests/regression/56-witness/69-ghost-ptr-protection.c @@ -0,0 +1,30 @@ +// PARAM: --set ana.activated[+] mutexGhosts +// CRAM +#include +#include + +int g = 0; +int *p = &g; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + int x = 10; + pthread_mutex_lock(&m2); + p = &x; + p = &g; + pthread_mutex_unlock(&m2); + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&m1); + g = 1; + // m2_locked || (p == & g && *p == 0) would be violated here + __goblint_check(*p != 0); // 1 from g or 10 from x in t_fun + g = 0; + pthread_mutex_unlock(&m1); + return 0; +} diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t new file mode 100644 index 0000000000..03481a7ce1 --- /dev/null +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -0,0 +1,101 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 69-ghost-ptr-protection.c + [Success][Assert] Assertion "*p != 0" will succeed (69-ghost-ptr-protection.c:26:3-26:27) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 15 + dead: 0 + total lines: 15 + [Warning][Race] Memory location p (race with conf. 110): (69-ghost-ptr-protection.c:7:5-7:12) + write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:14:3-14:9) + write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) + read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) + [Info][Witness] witness generation summary: + total generation entries: 12 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 1 + total memory locations: 3 + +TODO: Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (p == & g && *p == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || g == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g && g <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (*p == 10 || ((0 <= *p && *p <= 1) && p == & g))' + type: assertion + format: C From b4734c31753b328b74283f9f82351fd6e09979c9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 16:22:33 +0200 Subject: [PATCH 657/689] Fix unsound ghost witness invariant in 56-witness/69-ghost-ptr-protection --- src/analyses/basePriv.ml | 5 ++++- tests/regression/56-witness/69-ghost-ptr-protection.t | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index b7e32ceb94..3afd758daa 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -891,7 +891,10 @@ struct else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( - let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: This takes protected values of every [g], not just [g'], which might be unsound with pointers. See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698136411. *) + (* Only read g' as protected, everything else (e.g. pointed to variables) may be unprotected. + See 56-witness/69-ghost-ptr-protection and https://github.com/goblint/analyzer/pull/1394#discussion_r1698136411. *) + let read_global g = getg (if CilType.Varinfo.equal g g' then V.protected g else V.unprotected g) in + let inv = ValueDomain.invariant_global read_global g' in (* Very conservative about multiple (write-)protecting mutexes: invariant is not claimed when any of them is held. It should be possible to be more precise because writes only happen with all of them held, but conjunction is unsound when one of the mutexes is temporarily unlocked. diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t index 03481a7ce1..698f643385 100644 --- a/tests/regression/56-witness/69-ghost-ptr-protection.t +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -16,7 +16,7 @@ unsafe: 1 total memory locations: 3 -TODO: Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): +Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): $ yamlWitnessStrip < witness.yml - entry_type: ghost_update @@ -81,7 +81,7 @@ TODO: Should not contain unsound flow-insensitive invariant m2_locked || (p == & initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (m2_locked || (p == & g && *p == 0))' + string: '! multithreaded || (m2_locked || ((0 <= *p && *p <= 1) && p == & g))' type: assertion format: C - entry_type: flow_insensitive_invariant From d2e71cbbf773205abb600fc15cf07ba712a2e6eb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 16:58:43 +0200 Subject: [PATCH 658/689] Change ghost witness tests to use ghost_instrumentation --- .../regression/13-privatized/04-priv_multi.t | 298 +++---- tests/regression/13-privatized/25-struct_nr.t | 125 +-- tests/regression/13-privatized/74-mutex.t | 258 +++--- tests/regression/13-privatized/92-idx_priv.t | 66 +- tests/regression/29-svcomp/16-atomic_priv.t | 76 +- .../regression/36-apron/12-traces-min-rpb1.t | 163 ++-- .../56-witness/64-ghost-multiple-protecting.t | 750 ++++++++++-------- .../56-witness/65-ghost-ambiguous-lock.t | 94 ++- .../56-witness/66-ghost-alloc-lock.t | 212 ++--- .../56-witness/67-ghost-no-unlock.t | 106 +-- .../56-witness/68-ghost-ambiguous-idx.t | 66 +- .../56-witness/69-ghost-ptr-protection.t | 136 ++-- 12 files changed, 1325 insertions(+), 1025 deletions(-) diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index fd0dad6a39..3ea9b385fc 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -16,7 +16,7 @@ [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) [Info][Witness] witness generation summary: - total generation entries: 19 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -24,138 +24,158 @@ total memory locations: 2 $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml - - entry_type: ghost_update - variable: mutex_B_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 69 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_B_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 46 - column: 5 - function: dispose - - entry_type: ghost_update - variable: mutex_B_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 29 - column: 7 - function: process - - entry_type: ghost_update - variable: mutex_B_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 73 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_B_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 49 - column: 7 - function: dispose - - entry_type: ghost_update - variable: mutex_B_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 32 - column: 7 - function: process - - entry_type: ghost_update - variable: mutex_A_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 68 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_A_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 26 - column: 5 - function: process - - entry_type: ghost_update - variable: mutex_A_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 15 - column: 5 - function: generate - - entry_type: ghost_update - variable: mutex_A_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 74 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_A_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 34 - column: 7 - function: process - - entry_type: ghost_update - variable: mutex_A_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 18 - column: 5 - function: generate - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 63 - column: 3 - function: main - - entry_type: ghost_variable - variable: mutex_B_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: mutex_A_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: mutex_A_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: mutex_B_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 15 + column: 5 + function: generate + updates: + - variable: mutex_A_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 18 + column: 5 + function: generate + updates: + - variable: mutex_A_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 26 + column: 5 + function: process + updates: + - variable: mutex_A_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 29 + column: 7 + function: process + updates: + - variable: mutex_B_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 32 + column: 7 + function: process + updates: + - variable: mutex_B_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 34 + column: 7 + function: process + updates: + - variable: mutex_A_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 46 + column: 5 + function: dispose + updates: + - variable: mutex_B_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 49 + column: 7 + function: dispose + updates: + - variable: mutex_B_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 63 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 68 + column: 5 + function: main + updates: + - variable: mutex_A_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 69 + column: 5 + function: main + updates: + - variable: mutex_B_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 73 + column: 5 + function: main + updates: + - variable: mutex_B_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 74 + column: 5 + function: main + updates: + - variable: mutex_A_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' @@ -174,7 +194,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' --set witness.invariant.flow_insensitive-as location_invariant 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -192,7 +212,7 @@ Flow-insensitive invariants as location invariants. [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) [Info][Witness] witness generation summary: - total generation entries: 25 + total generation entries: 10 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -204,7 +224,7 @@ Flow-insensitive invariants as location invariants. Location invariant at `for` loop in `main` should be on column 3, not 7. $ diff witness.flow_insensitive.yml witness.location.yml - 133,134c133,140 + 153,154c153,160 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -216,7 +236,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > column: 3 > function: main > location_invariant: - 138,139c144,151 + 158,159c164,171 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -228,7 +248,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > column: 3 > function: main > location_invariant: - 143,144c155,228 + 163,164c175,248 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t index 88f205a431..59ed9960f2 100644 --- a/tests/regression/13-privatized/25-struct_nr.t +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 25-struct_nr.c [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) @@ -8,7 +8,7 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -16,61 +16,72 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 27 - column: 3 - function: main - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "1" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "1" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "0" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 32 - column: 3 - function: main - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "0" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: lock1_mutex_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: lock1_mutex_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: lock1_mutex_locked + value: "1" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: lock1_mutex_locked + value: "0" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: lock1_mutex_locked + value: "1" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 32 + column: 3 + function: main + updates: + - variable: lock1_mutex_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (lock1_mutex_locked || glob1 == 5)' diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 8a1a7fee5f..1c1f0c12be 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -8,7 +8,7 @@ total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -16,61 +16,72 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 34 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 36 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 38 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - variable: m_locked + value: "0" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - variable: m_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m_locked || used == 0)' @@ -84,7 +95,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' --set witness.invariant.flow_insensitive-as location_invariant 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -94,7 +105,7 @@ Flow-insensitive invariants as location invariants. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -104,7 +115,7 @@ Flow-insensitive invariants as location invariants. $ yamlWitnessStrip < witness.yml > witness.location.yml $ diff witness.flow_insensitive.yml witness.location.yml - 56,57c56,63 + 67,68c67,74 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -116,7 +127,7 @@ Flow-insensitive invariants as location invariants. > column: 3 > function: main > location_invariant: - 61,62c67,74 + 72,73c78,85 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -259,7 +270,7 @@ Same with ghost_instrumentation and invariant_set entries. Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -269,7 +280,7 @@ Same with mutex-meet. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -277,61 +288,72 @@ Same with mutex-meet. total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 34 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 36 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 38 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - variable: m_locked + value: "0" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - variable: m_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m_locked || used == 0)' diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index b157dfed4b..4783f65092 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -1,11 +1,11 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 92-idx_priv.c [Success][Assert] Assertion "data == 0" will succeed (92-idx_priv.c:22:3-22:29) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 total lines: 14 [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -13,20 +13,54 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + updates: [] + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index eea47295d5..92afedcd27 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -13,7 +13,7 @@ write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -21,20 +21,26 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || myglobal == 5' @@ -43,7 +49,7 @@ Non-atomic privatization: - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -58,7 +64,7 @@ Non-atomic privatization: write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 4 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -66,20 +72,26 @@ Non-atomic privatization: total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || myglobal == 5' diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 8201b2f8f9..c0ae5c118e 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -56,7 +56,7 @@ format: C - $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) @@ -76,82 +76,95 @@ dead: 0 total lines: 18 [Info][Witness] witness generation summary: - total generation entries: 10 + total generation entries: 2 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: A_locked - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_update - variable: A_locked - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 18 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: A_locked - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: A_locked - expression: "0" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 30 - column: 3 - function: main - - entry_type: ghost_update - variable: A_locked - expression: "0" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: A_locked - expression: "0" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: A_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: A_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "0" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 18 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "0" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: A_locked + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + updates: + - variable: A_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (A_locked || ((0LL - (long long )g) + (long long )h diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index e78d0d75aa..73863eecac 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,10 +1,10 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 17 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -14,120 +14,138 @@ protection doesn't have precise protected invariant for g2. $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' @@ -144,13 +162,13 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 18 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -160,120 +178,138 @@ protection doesn't have precise protected invariant for g2. protection-read has precise protected invariant for g2. $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || (m1_locked || g2 == 0))' @@ -295,13 +331,13 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 18 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -309,120 +345,138 @@ protection-read has precise protected invariant for g2. total memory locations: 2 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || ((0 <= g2 && g2 <= 1) && g1 == 0))' diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index a6e0c12b74..8115bb2921 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -1,10 +1,10 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 65-ghost-ambiguous-lock.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 23 dead: 0 total lines: 23 [Info][Witness] witness generation summary: - total generation entries: 4 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -12,20 +12,82 @@ total memory locations: 2 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 24 + column: 3 + function: fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 37 + column: 3 + function: main + updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index 8e45272538..844c1e6c15 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 66-ghost-alloc-lock.c [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -6,7 +6,7 @@ dead: 0 total lines: 23 [Info][Witness] witness generation summary: - total generation entries: 16 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 4 vulnerable: 0 @@ -14,102 +14,118 @@ total memory locations: 4 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 33 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 30 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 32 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: alloc_m861095507_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: alloc_m559918035_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: alloc_m559918035_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: alloc_m861095507_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: alloc_m559918035_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: alloc_m559918035_locked + value: "0" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: alloc_m861095507_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: alloc_m861095507_locked + value: "0" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + updates: + - variable: alloc_m559918035_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 32 + column: 3 + function: main + updates: + - variable: alloc_m559918035_locked + value: "0" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 33 + column: 3 + function: main + updates: + - variable: alloc_m861095507_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + updates: + - variable: alloc_m861095507_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t index 85b7a0b897..264d592366 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.t +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -1,11 +1,11 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 67-ghost-no-unlock.c [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 total lines: 11 [Info][Witness] witness generation summary: - total generation entries: 8 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -13,52 +13,62 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 21 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 12 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 12 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: m1_locked + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m1_locked || g1 == 0)' diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 02cecfd8f6..a8f2a0226a 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 68-ghost-ambiguous-idx.c [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -10,7 +10,7 @@ write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -18,20 +18,54 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: [] + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t index 698f643385..0b28f22b0f 100644 --- a/tests/regression/56-witness/69-ghost-ptr-protection.t +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 69-ghost-ptr-protection.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 69-ghost-ptr-protection.c [Success][Assert] Assertion "*p != 0" will succeed (69-ghost-ptr-protection.c:26:3-26:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 15 @@ -9,7 +9,7 @@ write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) [Info][Witness] witness generation summary: - total generation entries: 12 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -19,66 +19,78 @@ Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: m1_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || ((0 <= *p && *p <= 1) && p == & g))' From 554bd7f72e8cac3cc226976ad6f26bc434fd38d5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 17:01:40 +0200 Subject: [PATCH 659/689] Avoid empty ghost_instrumentation location updates --- src/analyses/mutexGhosts.ml | 7 ++- tests/regression/13-privatized/92-idx_priv.t | 28 ---------- .../56-witness/65-ghost-ambiguous-lock.t | 56 ------------------- .../56-witness/68-ghost-ambiguous-idx.t | 28 ---------- 4 files changed, 5 insertions(+), 114 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 6542ab3607..6ed0da4d4c 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -218,8 +218,11 @@ struct else (variables', updates) in - let location_update = WitnessGhost.location_update' ~node ~updates in - (variables', location_update :: location_updates) + match updates with + | [] -> (variables', location_updates) (* don't add location_update with no updates *) + | _ -> + let location_update = WitnessGhost.location_update' ~node ~updates in + (variables', location_update :: location_updates) ) nodes (VariableSet.empty, []) in let entry = WitnessGhost.instrumentation_entry ~task ~variables:(VariableSet.elements variables) ~location_updates in diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index 4783f65092..261108cf2f 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -23,20 +23,6 @@ value: "0" format: c_expression ghost_updates: - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - updates: [] - location: file_name: 92-idx_priv.c file_hash: $FILE_HASH @@ -47,20 +33,6 @@ - variable: multithreaded value: "1" format: c_expression - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 21 - column: 3 - function: main - updates: [] - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index 8115bb2921..2771ec5c50 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -22,48 +22,6 @@ value: "0" format: c_expression ghost_updates: - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 24 - column: 3 - function: fun - updates: [] - location: file_name: 65-ghost-ambiguous-lock.c file_hash: $FILE_HASH @@ -74,20 +32,6 @@ - variable: multithreaded value: "1" format: c_expression - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 37 - column: 3 - function: main - updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index a8f2a0226a..e45399e005 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -28,20 +28,6 @@ value: "0" format: c_expression ghost_updates: - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - updates: [] - location: file_name: 68-ghost-ambiguous-idx.c file_hash: $FILE_HASH @@ -52,20 +38,6 @@ - variable: multithreaded value: "1" format: c_expression - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - updates: [] - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' From 2c25848a23e3b74859cd4b8a7be549d572a748bc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 17:04:25 +0200 Subject: [PATCH 660/689] Remove support for old ghost_variable and ghost_update entry types --- src/analyses/mutexGhosts.ml | 48 -------------------- src/config/options.schema.json | 2 - src/witness/witnessGhost.ml | 16 +------ src/witness/yamlWitness.ml | 24 ++-------- src/witness/yamlWitnessType.ml | 67 ---------------------------- tests/util/yamlWitnessStripCommon.ml | 4 -- 6 files changed, 4 insertions(+), 157 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 6ed0da4d4c..3deec3ef59 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -122,54 +122,6 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with - | `Left g' when YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type -> - let (locked, unlocked, multithread) = G.node (ctx.global g) in - let g = g' in - let entries = - (* TODO: do variable_entry-s only once *) - Locked.fold (fun l acc -> - match mustlock_of_addr l with - | Some l when ghost_var_available ctx (Locked l) -> - let entry = WitnessGhost.variable_entry ~task (Locked l) in - Queries.YS.add entry acc - | _ -> - acc - ) (Locked.union locked unlocked) (Queries.YS.empty ()) - in - let entries = - Locked.fold (fun l acc -> - match mustlock_of_addr l with - | Some l when ghost_var_available ctx (Locked l) -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in - Queries.YS.add entry acc - | _ -> - acc - ) locked entries - in - let entries = - Unlocked.fold (fun l acc -> - match mustlock_of_addr l with - | Some l when ghost_var_available ctx (Locked l) -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in - Queries.YS.add entry acc - | _ -> - acc - ) unlocked entries - in - let entries = - if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - if ghost_var_available ctx Multithreaded then ( - let entry = WitnessGhost.variable_entry ~task Multithreaded in - let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in - Queries.YS.add entry (Queries.YS.add entry' entries) - ) - else - entries - ) - else - entries - in - entries | `Right true when YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type -> let nodes = G.update (ctx.global g) in let (variables, location_updates) = NodeSet.fold (fun node (variables, location_updates) -> diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 8534620d02..362e028ee3 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2673,8 +2673,6 @@ "precondition_loop_invariant_certificate", "invariant_set", "violation_sequence", - "ghost_variable", - "ghost_update", "ghost_instrumentation" ] }, diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 3535e8a347..3eaa8ef69b 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,7 +1,7 @@ (** Ghost variables for YAML witnesses. *) let enabled () = - (YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type + YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type module Var = WitnessGhostVar @@ -11,20 +11,6 @@ module Map = RichVarinfo.BiVarinfoMap.Make (Var) include Map -let variable_entry ~task x = - let variable = name_varinfo x in - let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) - let initial = CilType.Exp.show (initial x) in - YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial - -let update_entry ~task ~node x e = - let loc = Node.location node in - let location_function = (Node.find_fundec node).svar.vname in - let location = YamlWitness.Entry.location ~location:loc ~location_function in - let variable = name_varinfo x in - let expression = CilType.Exp.show e in - YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression - let variable' x = let variable = name_varinfo x in let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 81072ff82d..ec9a542919 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -149,25 +149,6 @@ struct metadata = metadata (); } - let ghost_variable ~task ~variable ~type_ ~(initial): Entry.t = { - entry_type = GhostVariable { - variable; - scope = "global"; - type_; - initial; - }; - metadata = metadata ~task (); - } - - let ghost_update ~task ~location ~variable ~(expression): Entry.t = { - entry_type = GhostUpdate { - variable; - expression; - location; - }; - metadata = metadata ~task (); - } - let ghost_variable' ~variable ~type_ ~(initial): GhostInstrumentation.Variable.t = { name = variable; scope = "global"; @@ -410,9 +391,10 @@ struct entries in - (* Generate flow-insensitive entries (ghost variables and ghost updates) *) + (* Generate flow-insensitive entries (ghost instrumentation) *) let entries = - if (entry_type_enabled YamlWitnessType.GhostVariable.entry_type && entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( + if entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( + (* TODO: only at most one ghost_instrumentation entry can ever be produced, so this fold and deduplication is overkill *) let module EntrySet = Queries.YS in fst @@ GHT.fold (fun g v accs -> match g with diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 9b5d580849..bcd8e9435f 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -644,61 +644,6 @@ struct {content} end -module GhostVariable = -struct - type t = { - variable: string; - scope: string; - type_: string; - initial: string; - } - [@@deriving eq, ord, hash] - - let entry_type = "ghost_variable" - - let to_yaml' {variable; scope; type_; initial} = - [ - ("variable", `String variable); - ("scope", `String scope); - ("type", `String type_); - ("initial", `String initial); - ] - - let of_yaml y = - let open GobYaml in - let+ variable = y |> find "variable" >>= to_string - and+ scope = y |> find "scope" >>= to_string - and+ type_ = y |> find "type" >>= to_string - and+ initial = y |> find "initial" >>= to_string in - {variable; scope; type_; initial} -end - -module GhostUpdate = -struct - type t = { - variable: string; - expression: string; - location: Location.t; - } - [@@deriving eq, ord, hash] - - let entry_type = "ghost_update" - - let to_yaml' {variable; expression; location} = - [ - ("variable", `String variable); - ("expression", `String expression); - ("location", Location.to_yaml location); - ] - - let of_yaml y = - let open GobYaml in - let+ variable = y |> find "variable" >>= to_string - and+ expression = y |> find "expression" >>= to_string - and+ location = y |> find "location" >>= Location.of_yaml in - {variable; expression; location} -end - module GhostInstrumentation = struct @@ -831,8 +776,6 @@ struct | PreconditionLoopInvariantCertificate of PreconditionLoopInvariantCertificate.t | InvariantSet of InvariantSet.t | ViolationSequence of ViolationSequence.t - | GhostVariable of GhostVariable.t - | GhostUpdate of GhostUpdate.t | GhostInstrumentation of GhostInstrumentation.t [@@deriving eq, ord, hash] @@ -845,8 +788,6 @@ struct | PreconditionLoopInvariantCertificate _ -> PreconditionLoopInvariantCertificate.entry_type | InvariantSet _ -> InvariantSet.entry_type | ViolationSequence _ -> ViolationSequence.entry_type - | GhostVariable _ -> GhostVariable.entry_type - | GhostUpdate _ -> GhostUpdate.entry_type | GhostInstrumentation _ -> GhostInstrumentation.entry_type let to_yaml' = function @@ -858,8 +799,6 @@ struct | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate.to_yaml' x | InvariantSet x -> InvariantSet.to_yaml' x | ViolationSequence x -> ViolationSequence.to_yaml' x - | GhostVariable x -> GhostVariable.to_yaml' x - | GhostUpdate x -> GhostUpdate.to_yaml' x | GhostInstrumentation x -> GhostInstrumentation.to_yaml' x let of_yaml y = @@ -889,12 +828,6 @@ struct else if entry_type = ViolationSequence.entry_type then let+ x = y |> ViolationSequence.of_yaml in ViolationSequence x - else if entry_type = GhostVariable.entry_type then - let+ x = y |> GhostVariable.of_yaml in - GhostVariable x - else if entry_type = GhostUpdate.entry_type then - let+ x = y |> GhostUpdate.of_yaml in - GhostUpdate x else if entry_type = GhostInstrumentation.entry_type then let+ x = y |> GhostInstrumentation.of_yaml in GhostInstrumentation x diff --git a/tests/util/yamlWitnessStripCommon.ml b/tests/util/yamlWitnessStripCommon.ml index d54dd446bf..39bc231d72 100644 --- a/tests/util/yamlWitnessStripCommon.ml +++ b/tests/util/yamlWitnessStripCommon.ml @@ -74,10 +74,6 @@ struct InvariantSet {content = List.sort InvariantSet.Invariant.compare (List.map invariant_strip_file_hash x.content)} (* Sort, so order is deterministic regardless of Goblint. *) | ViolationSequence x -> ViolationSequence {content = List.map segment_strip_file_hash x.content} - | GhostVariable x -> - GhostVariable x (* no location to strip *) - | GhostUpdate x -> - GhostUpdate {x with location = location_strip_file_hash x.location} | GhostInstrumentation x -> GhostInstrumentation { (* Sort, so order is deterministic regardless of Goblint. *) ghost_variables = List.sort GhostInstrumentation.Variable.compare x.ghost_variables; From 0ca1bb30f50d12bec84198ae404994c510e37431 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 22 Nov 2024 11:11:34 +0200 Subject: [PATCH 661/689] Add parsing of integer constraints in YAML violation_sequence-s --- src/util/std/gobYaml.ml | 2 ++ src/witness/yamlWitnessType.ml | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/util/std/gobYaml.ml b/src/util/std/gobYaml.ml index 624cdbf1fa..4c8576ade2 100644 --- a/src/util/std/gobYaml.ml +++ b/src/util/std/gobYaml.ml @@ -44,3 +44,5 @@ let list = function let entries = function | `O assoc -> Ok assoc | _ -> Error (`Msg "Failed to get entries from non-object value") + +let int i = float (float_of_int i) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 4fc2029801..c77fadad4c 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -447,15 +447,35 @@ struct module Constraint = struct + + module Value = + struct + type t = + | String of string + | Int of int (* Why doesn't format consider ints (for switch branches) as strings here, like everywhere else? *) + [@@deriving ord] + + let to_yaml = function + | String s -> GobYaml.string s + | Int i -> GobYaml.int i + + let of_yaml y = + let open GobYaml in + match y with + | `String s -> Ok (String s) + | `Float f -> Ok (Int (int_of_float f)) + | _ -> Error (`Msg "Expected a string or integer value") + end + type t = { - value: string; + value: Value.t; format: string option; } [@@deriving ord] let to_yaml {value; format} = `O ([ - ("value", `String value); + ("value", Value.to_yaml value); ] @ (match format with | Some format -> [ ("format", `String format); @@ -466,7 +486,7 @@ struct let of_yaml y = let open GobYaml in - let+ value = y |> find "value" >>= to_string + let+ value = y |> find "value" >>= Value.of_yaml and+ format = y |> Yaml.Util.find "format" >>= option_map to_string in {value; format} end From d7074f1e9526c0df5f146d267c35038b2bb65770 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 27 Nov 2024 13:44:50 +0200 Subject: [PATCH 662/689] Add Karoliine's email to opam maintainer field opam-repository CI now demands this. Co-authored-by: Karoliine Holter --- dune-project | 2 +- goblint.opam | 2 +- goblint.opam.locked | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dune-project b/dune-project index 54915cf964..f2f87b3c58 100644 --- a/dune-project +++ b/dune-project @@ -16,7 +16,7 @@ (homepage "https://goblint.in.tum.de") (documentation "https://goblint.readthedocs.io/en/latest/") (authors "Simmo Saan" "Michael Schwarz" "Julian Erhard" "Sarah Tilscher" "Karoliine Holter" "Ralf Vogler" "Kalmer Apinis" "Vesal Vojdani" ) ; same authors as in .zenodo.json and CITATION.cff -(maintainers "Simmo Saan " "Michael Schwarz " "Karoliine Holter") +(maintainers "Simmo Saan " "Michael Schwarz " "Karoliine Holter ") (license MIT) (package diff --git a/goblint.opam b/goblint.opam index 44e5ccd2c2..f74ffab8c4 100644 --- a/goblint.opam +++ b/goblint.opam @@ -9,7 +9,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e maintainer: [ "Simmo Saan " "Michael Schwarz " - "Karoliine Holter" + "Karoliine Holter " ] authors: [ "Simmo Saan" diff --git a/goblint.opam.locked b/goblint.opam.locked index 9fbee1e02b..cedb4088b8 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -5,7 +5,7 @@ synopsis: "Static analysis framework for C" maintainer: [ "Simmo Saan " "Michael Schwarz " - "Karoliine Holter" + "Karoliine Holter " ] authors: [ "Simmo Saan" From 65ddbbb7d06236e2a266ef2967f58c59528a48c6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Nov 2024 10:27:35 +0200 Subject: [PATCH 663/689] Finalize CHANGELOG for v2.5.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf6a8aa781..1fb07a7dc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## v2.5.0 (unreleased) +## v2.5.0 Functionally equivalent to Goblint in SV-COMP 2025. * Add 32bit vs 64bit architecture support (#54, #1574). From 629cd493201c133e284f45437816ab82fe305742 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Nov 2024 10:34:13 +0200 Subject: [PATCH 664/689] Replace goblint-cil pin with published 2.0.5 --- dune-project | 2 +- goblint.opam | 5 +++-- goblint.opam.locked | 6 +----- goblint.opam.template | 3 ++- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/dune-project b/dune-project index f2f87b3c58..9a1d958484 100644 --- a/dune-project +++ b/dune-project @@ -37,7 +37,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e "concurrency")) (depends (ocaml (>= 4.14)) - (goblint-cil (>= 2.0.4)) ; TODO no way to define as pin-depends? Used goblint.opam.template to add it for now. https://github.com/ocaml/dune/issues/3231. Alternatively, removing this line and adding cil as a git submodule and `(vendored_dirs cil)` as ./dune also works. This way, no more need to reinstall the pinned cil opam package on changes. However, then cil is cleaned and has to be rebuild together with goblint. + (goblint-cil (>= 2.0.5)) ; TODO no way to define as pin-depends? Used goblint.opam.template to add it for now. https://github.com/ocaml/dune/issues/3231. Alternatively, removing this line and adding cil as a git submodule and `(vendored_dirs cil)` as ./dune also works. This way, no more need to reinstall the pinned cil opam package on changes. However, then cil is cleaned and has to be rebuild together with goblint. (batteries (>= 3.5.1)) (zarith (>= 1.10)) (yojson (>= 2.0.0)) diff --git a/goblint.opam b/goblint.opam index f74ffab8c4..9fa877d54f 100644 --- a/goblint.opam +++ b/goblint.opam @@ -37,7 +37,7 @@ bug-reports: "https://github.com/goblint/analyzer/issues" depends: [ "dune" {>= "3.7"} "ocaml" {>= "4.14"} - "goblint-cil" {>= "2.0.4"} + "goblint-cil" {>= "2.0.5"} "batteries" {>= "3.5.1"} "zarith" {>= "1.10"} "yojson" {>= "2.0.0"} @@ -97,7 +97,8 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] + # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed + # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release diff --git a/goblint.opam.locked b/goblint.opam.locked index cedb4088b8..081731a9a3 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -64,7 +64,7 @@ depends: [ "fileutils" {= "0.6.4"} "fmt" {= "0.9.0"} "fpath" {= "0.7.3"} - "goblint-cil" {= "2.0.4"} + "goblint-cil" {= "2.0.5"} "hex" {= "1.5.0"} "integers" {= "0.7.0"} "json-data-encoding" {= "1.0.1"} @@ -138,10 +138,6 @@ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] pin-depends: [ - [ - "goblint-cil.2.0.4" - "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" - ] [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" diff --git a/goblint.opam.template b/goblint.opam.template index 0a517fbfa0..d05a0af61d 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -2,7 +2,8 @@ # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - [ "goblint-cil.2.0.4" "git+https://github.com/goblint/cil.git#9f4fac450c02bc61a13717784515056b185794cd" ] + # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed + # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release From d066c8dd711317ae969639d45285aa5664767daa Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Nov 2024 10:35:32 +0200 Subject: [PATCH 665/689] Disable pins for v2.5.0 release --- goblint.opam | 8 ++++---- goblint.opam.locked | 10 ---------- goblint.opam.template | 8 ++++---- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/goblint.opam b/goblint.opam index 9fa877d54f..9f2b874ff6 100644 --- a/goblint.opam +++ b/goblint.opam @@ -96,14 +96,14 @@ 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-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") -pin-depends: [ +# pin-depends: [ # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release - [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] + # [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release - [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] -] + # [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] +# ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] diff --git a/goblint.opam.locked b/goblint.opam.locked index 081731a9a3..3a7bb1bfa5 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -137,16 +137,6 @@ conflicts: [ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] -pin-depends: [ - [ - "camlidl.1.12" - "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" - ] - [ - "apron.v0.9.15" - "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" - ] -] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} description: """\ Goblint is a sound static analysis framework for C programs using abstract interpretation. diff --git a/goblint.opam.template b/goblint.opam.template index d05a0af61d..8766a89df2 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,14 +1,14 @@ # 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-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") -pin-depends: [ +# pin-depends: [ # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release - [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] + # [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release - [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] -] + # [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] +# ] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] From 0df4d8647afbfd2d65043c13f89047ecc3a2219b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Nov 2024 13:36:28 +0200 Subject: [PATCH 666/689] Update goblint-cil to 2.0.5 in Gobview lock file --- gobview | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gobview b/gobview index 76e42c34d3..8e1b755ebc 160000 --- a/gobview +++ b/gobview @@ -1 +1 @@ -Subproject commit 76e42c34d36bd2ab6900efd661a972ba4824f065 +Subproject commit 8e1b755ebc5fb479095fb4dcc30305fe02501e47 From eb9ee513ba2cb1811750d58fd10370f31c21dda1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Nov 2024 14:52:54 +0200 Subject: [PATCH 667/689] Make 29-svcomp/36-svcomp-arch multilib detection more precise Also handles missing gcc-multilib on Linux, e.g. in opam docker. There's no conf-* package for gcc-multilib. --- tests/regression/29-svcomp/dune | 2 +- tests/util/dune | 7 ++++++- tests/util/multilibConfigure.ml | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/util/multilibConfigure.ml diff --git a/tests/regression/29-svcomp/dune b/tests/regression/29-svcomp/dune index 95ac66a5ec..9b2396b313 100644 --- a/tests/regression/29-svcomp/dune +++ b/tests/regression/29-svcomp/dune @@ -17,4 +17,4 @@ (cram (applies_to 36-svcomp-arch) - (enabled_if (<> %{system} macosx))) ; https://dune.readthedocs.io/en/stable/reference/boolean-language.html + (enabled_if %{read:../../util/multilibAvailable})) ; https://dune.readthedocs.io/en/stable/reference/boolean-language.html diff --git a/tests/util/dune b/tests/util/dune index 0e32304d4f..e43d21c25d 100644 --- a/tests/util/dune +++ b/tests/util/dune @@ -1,7 +1,8 @@ (executables - (names yamlWitnessStrip yamlWitnessStripDiff) + (names yamlWitnessStrip yamlWitnessStripDiff multilibConfigure) (libraries batteries.unthreaded + goblint-cil goblint_std goblint_lib yaml @@ -9,3 +10,7 @@ goblint.build-info.dune) (flags :standard -open Goblint_std) (preprocess (pps ppx_deriving.std))) + +(rule + (target multilibAvailable) + (action (with-stdout-to %{target} (run ./multilibConfigure.exe)))) diff --git a/tests/util/multilibConfigure.ml b/tests/util/multilibConfigure.ml new file mode 100644 index 0000000000..cf59e04416 --- /dev/null +++ b/tests/util/multilibConfigure.ml @@ -0,0 +1,4 @@ +open GoblintCil + +let () = + Printf.printf "%B" (Option.is_some GoblintCil.Machdep.gcc32 && Option.is_some GoblintCil.Machdep.gcc64) From 7170d9a8944706a1adc0acaeb81a4fc6d914af7b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 28 Nov 2024 15:00:16 +0200 Subject: [PATCH 668/689] Fix unused open in multilibConfigure --- tests/util/multilibConfigure.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/multilibConfigure.ml b/tests/util/multilibConfigure.ml index cf59e04416..96cf9a706a 100644 --- a/tests/util/multilibConfigure.ml +++ b/tests/util/multilibConfigure.ml @@ -1,4 +1,4 @@ open GoblintCil let () = - Printf.printf "%B" (Option.is_some GoblintCil.Machdep.gcc32 && Option.is_some GoblintCil.Machdep.gcc64) + Printf.printf "%B" (Option.is_some Machdep.gcc32 && Option.is_some Machdep.gcc64) From 4f83ce8369977071c5a749ad50cf5ebba7aa4f75 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 10:51:02 +0200 Subject: [PATCH 669/689] Revert "Disable pins for v2.5.0 release" This reverts commit d066c8dd711317ae969639d45285aa5664767daa. --- goblint.opam | 8 ++++---- goblint.opam.locked | 10 ++++++++++ goblint.opam.template | 8 ++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/goblint.opam b/goblint.opam index 9f2b874ff6..9fa877d54f 100644 --- a/goblint.opam +++ b/goblint.opam @@ -96,14 +96,14 @@ 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-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") -# pin-depends: [ +pin-depends: [ # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release - # [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] + [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release - # [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] -# ] + [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] +] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] diff --git a/goblint.opam.locked b/goblint.opam.locked index 3a7bb1bfa5..081731a9a3 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -137,6 +137,16 @@ conflicts: [ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] +pin-depends: [ + [ + "camlidl.1.12" + "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" + ] + [ + "apron.v0.9.15" + "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" + ] +] depexts: ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} description: """\ Goblint is a sound static analysis framework for C programs using abstract interpretation. diff --git a/goblint.opam.template b/goblint.opam.template index 8766a89df2..d05a0af61d 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -1,14 +1,14 @@ # 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-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") -# pin-depends: [ +pin-depends: [ # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release - # [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] + [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release - # [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] -# ] + [ "apron.v0.9.15" "git+https://github.com/antoinemine/apron.git#418a217c7a70dae3f422678f3aaba38ae374d91a" ] +] depexts: [ ["libgraph-easy-perl"] {os-distribution = "ubuntu" & with-test} ] From 77acd917865a4385c160155740d20615c0e87f2a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 10:58:11 +0200 Subject: [PATCH 670/689] Pin released goblint-cil.2.0.5 for reproducibility --- goblint.opam | 4 ++-- goblint.opam.locked | 4 ++++ goblint.opam.template | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/goblint.opam b/goblint.opam index 9fa877d54f..219c67d011 100644 --- a/goblint.opam +++ b/goblint.opam @@ -97,8 +97,8 @@ dev-repo: "git+https://github.com/goblint/analyzer.git" # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed - # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] + # published goblint-cil 2.0.5 is currently up-to-date, but pinned for reproducibility + [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release diff --git a/goblint.opam.locked b/goblint.opam.locked index 081731a9a3..2594aea288 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -138,6 +138,10 @@ post-messages: [ "Do not benchmark Goblint on OCaml 5 (https://goblint.readthedocs.io/en/latest/user-guide/benchmarking/)." {ocaml:version >= "5.0.0"} ] pin-depends: [ + [ + "oblint-cil.2.0.5" + "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" + ] [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" diff --git a/goblint.opam.template b/goblint.opam.template index d05a0af61d..84dcc24d8d 100644 --- a/goblint.opam.template +++ b/goblint.opam.template @@ -2,8 +2,8 @@ # also remember to generate/adjust goblint.opam.locked! available: os-family != "bsd" & os-distribution != "alpine" & (arch != "arm64" | os = "macos") pin-depends: [ - # published goblint-cil 2.0.5 is currently up-to-date, so no pin needed - # [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] + # published goblint-cil 2.0.5 is currently up-to-date, but pinned for reproducibility + [ "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new camlidl release [ "camlidl.1.12" "git+https://github.com/xavierleroy/camlidl.git#1c1e87e3f56c2c6b3226dd0af3510ef414b462d0" ] # pinned for stability (https://github.com/goblint/analyzer/issues/1520), remove after new apron release From dbdefab9825123e08c92b4c36618e7eacb7883d4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 11:21:22 +0200 Subject: [PATCH 671/689] Fix must-double-locking in regression tests --- tests/regression/04-mutex/32-allfuns.c | 4 ++-- tests/regression/09-regions/31-equ_rc.c | 2 +- tests/regression/09-regions/32-equ_nr.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/regression/04-mutex/32-allfuns.c b/tests/regression/04-mutex/32-allfuns.c index b59c487c53..e6b88e47ce 100644 --- a/tests/regression/04-mutex/32-allfuns.c +++ b/tests/regression/04-mutex/32-allfuns.c @@ -8,11 +8,11 @@ pthread_mutex_t B_mutex = PTHREAD_MUTEX_INITIALIZER; void t1() { pthread_mutex_lock(&A_mutex); myglobal++; //RACE! - pthread_mutex_lock(&A_mutex); + pthread_mutex_unlock(&A_mutex); } void t2() { pthread_mutex_lock(&B_mutex); myglobal++; //RACE! - pthread_mutex_lock(&B_mutex); + pthread_mutex_unlock(&B_mutex); } diff --git a/tests/regression/09-regions/31-equ_rc.c b/tests/regression/09-regions/31-equ_rc.c index 7cea370c58..2f3aff7f63 100644 --- a/tests/regression/09-regions/31-equ_rc.c +++ b/tests/regression/09-regions/31-equ_rc.c @@ -15,7 +15,7 @@ struct s { void *t_fun(void *arg) { pthread_mutex_lock(&A.mutex); B.datum = 5; // RACE! - pthread_mutex_lock(&A.mutex); + pthread_mutex_unlock(&A.mutex); return NULL; } diff --git a/tests/regression/09-regions/32-equ_nr.c b/tests/regression/09-regions/32-equ_nr.c index d9b909546e..a242448ba8 100644 --- a/tests/regression/09-regions/32-equ_nr.c +++ b/tests/regression/09-regions/32-equ_nr.c @@ -15,7 +15,7 @@ struct s { void *t_fun(void *arg) { pthread_mutex_lock(&A.mutex); A.datum = 5; // NORACE - pthread_mutex_lock(&A.mutex); + pthread_mutex_unlock(&A.mutex); return NULL; } From 218770b8f3f825338db1e10911668151d3317f14 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 11:21:55 +0200 Subject: [PATCH 672/689] Check must-double-locking in 03-practical/21-pfscan_combine_minimal --- tests/regression/03-practical/21-pfscan_combine_minimal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/03-practical/21-pfscan_combine_minimal.c b/tests/regression/03-practical/21-pfscan_combine_minimal.c index abdef0627b..86cfdabac1 100644 --- a/tests/regression/03-practical/21-pfscan_combine_minimal.c +++ b/tests/regression/03-practical/21-pfscan_combine_minimal.c @@ -18,7 +18,7 @@ int pqueue_init(PQUEUE *qp) void pqueue_close(PQUEUE *qp ) { - pthread_mutex_lock(& qp->mtx); + pthread_mutex_lock(& qp->mtx); // WARN (must double locking) qp->closed = 1; pthread_mutex_unlock(& qp->mtx); return; @@ -26,7 +26,7 @@ void pqueue_close(PQUEUE *qp ) int pqueue_put(PQUEUE *qp) { - pthread_mutex_lock(& qp->mtx); + pthread_mutex_lock(& qp->mtx); // WARN (must double locking) if (qp->closed) { // pfscan actually has a bug and is missing the following unlock at early return // pthread_mutex_unlock(& qp->mtx); From 68cd95237ebbb2023f6c9f7e59dc5f2d33d8ad45 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 11:30:41 +0200 Subject: [PATCH 673/689] Fix goblint-cil typo in opam lock file --- goblint.opam.locked | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goblint.opam.locked b/goblint.opam.locked index 2594aea288..e5176b9007 100644 --- a/goblint.opam.locked +++ b/goblint.opam.locked @@ -139,7 +139,7 @@ post-messages: [ ] pin-depends: [ [ - "oblint-cil.2.0.5" + "goblint-cil.2.0.5" "git+https://github.com/goblint/cil.git#c79208b21ea61d7b72eae29a18c1ddeda4795dfd" ] [ From ffe255b9a60a1c4919b565f6c9a0e07c47ac7218 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 14:11:46 +0200 Subject: [PATCH 674/689] Count witness.invariant.flow_insensitive-as location invariants in summary --- src/witness/yamlWitness.ml | 2 ++ tests/regression/13-privatized/04-priv_multi.t | 2 +- tests/regression/13-privatized/74-mutex.t | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index e3978f9929..9d04b597fa 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -385,6 +385,7 @@ struct fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.location_invariant ~task ~location ~invariant in + incr cnt_location_invariant; entry :: acc ) acc | `Lifted _, _ @@ -605,6 +606,7 @@ struct fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> let invariant = CilType.Exp.show inv in let invariant = Entry.location_invariant' ~location ~invariant in + incr cnt_location_invariant; invariant :: acc ) acc | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index af7c9b2098..1f6dff3fdc 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -215,7 +215,7 @@ Flow-insensitive invariants as location invariants. [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) [Info][Witness] witness generation summary: - location invariants: 0 + location invariants: 9 loop invariants: 0 flow-insensitive invariants: 0 total generation entries: 10 diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 1d750a211c..4b370db387 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -108,7 +108,7 @@ Flow-insensitive invariants as location invariants. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - location invariants: 0 + location invariants: 2 loop invariants: 0 flow-insensitive invariants: 0 total generation entries: 3 @@ -177,7 +177,7 @@ Same with ghost_instrumentation and invariant_set entries. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - location invariants: 0 + location invariants: 2 loop invariants: 0 flow-insensitive invariants: 0 total generation entries: 2 From f3dfca7a9ab28fe16ce77bfeac0d55f65058ff4c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 17:25:15 +0200 Subject: [PATCH 675/689] Change must-double-locking in 03-practical/21-pfscan_combine_minimal to TODO On MacOS the mutex type is top because it's zero-initialized global. On MacOS zero-initialized mutex isn't the same as a default mutex (type 0). --- tests/regression/03-practical/21-pfscan_combine_minimal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/03-practical/21-pfscan_combine_minimal.c b/tests/regression/03-practical/21-pfscan_combine_minimal.c index 86cfdabac1..b8fc7948b2 100644 --- a/tests/regression/03-practical/21-pfscan_combine_minimal.c +++ b/tests/regression/03-practical/21-pfscan_combine_minimal.c @@ -18,7 +18,7 @@ int pqueue_init(PQUEUE *qp) void pqueue_close(PQUEUE *qp ) { - pthread_mutex_lock(& qp->mtx); // WARN (must double locking) + pthread_mutex_lock(& qp->mtx); // TODO (OSX): WARN (must double locking) qp->closed = 1; pthread_mutex_unlock(& qp->mtx); return; @@ -26,7 +26,7 @@ void pqueue_close(PQUEUE *qp ) int pqueue_put(PQUEUE *qp) { - pthread_mutex_lock(& qp->mtx); // WARN (must double locking) + pthread_mutex_lock(& qp->mtx); // TODO (OSX): WARN (must double locking) if (qp->closed) { // pfscan actually has a bug and is missing the following unlock at early return // pthread_mutex_unlock(& qp->mtx); From 0706c136b7897191ea1241d76f7c3dc716d939a1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:14:35 +0200 Subject: [PATCH 676/689] Copy VMCAI 2025 artifact description from concurrency-witnesses repo --- docs/artifact-descriptions/vmcai25.md | 288 ++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 289 insertions(+) create mode 100644 docs/artifact-descriptions/vmcai25.md diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md new file mode 100644 index 0000000000..08b2c468b8 --- /dev/null +++ b/docs/artifact-descriptions/vmcai25.md @@ -0,0 +1,288 @@ +# Artifact for VMCAI'2025 Paper "Correctness Witnesses for Concurrent Programs: Bridging the Semantic Divide with Ghosts" + +------------------------------------------------------------------------------- + +## OVERVIEW + +This artifact contains the following components: + + EVALUATION RESULTS :: The evaluation results, and overview tables (HTML) + generated from the raw data. + SOURCE CODE :: Source code for Goblint and Ultimate GemCutter, + the verification tools used in the experiments + for the paper. + VERIFIER BINARIES :: Binaries for Goblint and Ultimate GemCutter. + BENCHMARK PROGRAMS :: Benchmarks used for evaluation of the verifiers. + BENCHMARK WITNESSES :: The witnesses generated by Goblint, as used in the + experiments. + BENCHEXEC TOOL :: The BenchExec benchmarking tool can be used + to replicate our results on these benchmarks. + +The next section gives instructions on how to setup and quickly get an overview of the artifact. +The subsequent sections then describe each of these components in detail. +The final section gives information on how to reuse this artifact. + +------------------------------------------------------------------------------- + +## GETTING STARTED + +### 1. Setup + +The artifact is a virtual machine (VM). Follow these steps to set it up: + +* If you have not done so already, install VirtualBox. + (https://www.virtualbox.org/wiki/Downloads) +* Download the artifact. +* Import the artifact via the VirtualBox UI (`File > Import Appliance`) + or by running `VBoxManage import ghost-witnesses.ova`. + +You can then start the VM from the VirtualBox UI. +Login with user `vagrant` and password `vagrant`. +(Note: By default, the user `Ubuntu` may be selected on the login screen. Click on the name and switch to user `vagrant`.) + +You may want to install VirtualBox guest additions (). +If the usual installation does not work, try the following steps: + +* Add a disk drive to the VM in its settings (the VM must be off for this). +* After starting the VM and logging in, select `Devices > Insert Guest Additions CD image` from the VirtualBox menu. +* Run the following in a terminal: + `sudo mount /dev/cdrom /mnt && cd /mnt && sudo ./VBoxLinuxAdditions.run` + +### 2. Inspect the evaluation results + +To extract the table data used in the paper from our raw evaluation results, open a terminal in the VM (`Ctrl+Alt+T`) and run the following commands: + + ~/scripts/analyse-witnesses.py "$HOME/witness-generation/paper-evaluation/goblint.2024-09-02_08-21-23.files" + cd ~/witness-validation/paper-evaluation/ + WITNESS_DIR="$HOME/witness-generation/paper-evaluation/goblint.2024-09-02_08-21-23.files" ~/scripts/analyse-validation.py + +The times for the Table 2 are given first in seconds and then pretty-printed as in the paper. + +For a more detailed inspection and visualization of the data, take a look at the generated HTML report. +Just open the file `~/witness-validation/paper-evaluation/results.2024-09-24_22-00-48.table.html` in firefox. +For detailed information, see the "EVALUATION RESULTS" section below. + +### 3. Quick Test of the Benchmark Setup + +To analyse some programs with Goblint and analyse the generated witnesses with GemCutter, run + + ~/scripts/quick-run.sh + +on a console in the VM. +This will analyse a single program with Goblint and generate witnesses using the four analyses described in the paper. +Subsequently, the script will run GemCutter's verification, witness confirmation and witness validation analyses on the example. + +The whole run should should conclude successfully for all configurations in about 2min. +This is indicated by the benchmark results `true` printed on the console, and the fact that the final output looks roughly like this: + + Table 1: Witness Confirmation + ============================= + correct programs + ----------------------------- + protection-ghost : total= 1 , confirmed= 1 , rejected= 0 , confirmation rate= 100.0 % , resource out= 0 + mutex-meet-ghost : total= 1 , confirmed= 1 , rejected= 0 , confirmation rate= 100.0 % , resource out= 0 + protection-local : total= 1 , confirmed= 1 , rejected= 0 , confirmation rate= 100.0 % , resource out= 0 + mutex-meet-local : total= 1 , confirmed= 1 , rejected= 0 , confirmation rate= 100.0 % , resource out= 0 + + confirmation range: 100.0 % - 100.0 % + + incorrect programs + ----------------------------- + No programs with witnesses found for protection-ghost. Skipping benchmark set... + No programs with witnesses found for mutex-meet-ghost. Skipping benchmark set... + No programs with witnesses found for protection-local. Skipping benchmark set... + No programs with witnesses found for mutex-meet-local. Skipping benchmark set... + + confirmation range: 100.0 % - 0.0 % + + + Table 2: Witness Validation + =========================== + protection-ghost + ---------------- + validation : {'number': 1, 'time': 14, 'time_pretty': 0:00:14} + verification : {'number': 1, 'time': 12, 'time_pretty': 0:00:12} + 0 tasks could be validated but not verified + + mutex-meet-ghost + ---------------- + validation : {'number': 1, 'time': 13, 'time_pretty': 0:00:13} + verification : {'number': 1, 'time': 12, 'time_pretty': 0:00:12} + 0 tasks could be validated but not verified + + protection-local + ---------------- + validation : {'number': 1, 'time': 12, 'time_pretty': 0:00:12} + verification : {'number': 1, 'time': 12, 'time_pretty': 0:00:12} + 0 tasks could be validated but not verified + + mutex-meet-local + ---------------- + validation : {'number': 1, 'time': 13, 'time_pretty': 0:00:13} + verification : {'number': 1, 'time': 12, 'time_pretty': 0:00:12} + 0 tasks could be validated but not verified + + ~ + + =============================================================================== + Completed quick benchmark test run. + + Results of witness generation can be found in: /home/vagrant/witness-generation/2024-10-01_08-57-09 + Generated witnesses are located in: /home/vagrant/witness-generation/2024-10-01_08-57-09/goblint.2024-10-01_08-57-09.files + Results of witness validation can be found in: /home/vagrant/witness-validation/2024-10-01_08-57-09 + =============================================================================== + +For a slightly larger set of experiments, run + + ~/scripts/medium-run.sh + +This will run an entire folder of SV-COMP benchmarks through Goblint and subsequently analyse the generated witness with GemCutter. +The whole run should complete in 3-4h. +(Note: This run uses a smaller timeout and memory limit than the full evaluation used in the paper, so the results for individual benchmarks may differ.) + +#### Troubleshooting +On certain old host machines, GemCutter fails with `ERROR(7)`, and the log files (`/home/vagrant/witness-validation/YYYY-MM-DD_hh-mm-ss/concurrency-witness-validation-gemcutter.YYYY-MM-DD_hh-mm-ss.logfiles/*.log`) contain a message as follows: + + [2024-10-01 22:04:14,025 INFO L327 MonitoredProcess]: [MP /home/vagrant/ultimate/releaseScripts/default/UGemCutter-linux/z3 SMTLIB2_COMPLIANT=true -memory:2024 -smt2 -in -t:2000 (1)] Waiting until timeout for monitored process + [2024-10-01 22:04:14,058 FATAL L? ?]: An unrecoverable error occured during an interaction with an SMT solver: + de.uni_freiburg.informatik.ultimate.logic.SMTLIBException: External (MP /home/vagrant/ultimate/releaseScripts/default/UGemCutter-linux/z3 SMTLIB2_COMPLIANT=true -memory:2024 -smt2 -in -t:2000 (1) with exit command (exit)) Received EOF on stdin. No stderr output. + +This is because the version of Z3 shipped with GemCutter uses certain processor instructions that the host does not support or VirtualBox emulates incorrectly. +In this case, download an official build of Z3 () and replace the file `~/ultimate/releaseScripts/default/UGemCutter-linux/z3` with the corresponding binary from the official ZIP: + + wget https://github.com/Z3Prover/z3/releases/download/z3-4.12.5/z3-4.12.5-x64-glibc-2.31.zip + unzip z3-4.12.5-x64-glibc-2.31.zip + cp z3-4.12.5-x64-glibc-2.31/bin/z3 ~/ultimate/releaseScripts/default/UGemCutter-linux/z3 + +### 4. Running the Full Experiments + +To re-run the full experiments, execute + + ~/scripts/full-run.sh + +This script behaves similarly to the smaller variants in the previous sections. +Note however: + +- By default the experiments require 16 GB of memory per benchmark (this configuration was used for the experiments in the paper). + To reproduce this, you will have to modify the VM's settings in VirtualBox and increase the available memory (shutdown the machine while doing so). + + Alternatively, you can run the experiments with a reduced memory limit. + To do so, modify the environment variable `BENCHMARK_PARAMS`. + For instance, the following allows only 4GB of memory per benchmark: + + BENCHMARK_PARAMS="-M 4GB" ~/scripts/full-run.sh + +- The full evaluation for the paper required around 3 days. + In this evaluation, we used the benchexec tool to run 14 validation tasks in parallel (occupying up to 28 cores at a time). + + By default, the provided script only runs one benchmark at a time. + If you have sufficient cores and memory available (adjust the VM settings accordingly), you can run multiple benchmarks in parallel by setting the environment variable `BENCHEXEC_THREADS`. You may also execute the experiments with a reduced timeout. + For instance, the following command runs 4 benchmarks in parallel at a time (occupying up to 8 cores), and gives each benchmark a 300s timeout and 4GB memory limit: + + BENCHEXEC_THREADS=4 BENCHMARK_PARAMS="-T 300s -M 4GB" ~/scripts/full-run.sh + +Naturally, changes to the timeout or memory are expected to affect the evaluation numbers. + +---------------------------------------------------------------------------------- + +## EVALUATION RESULTS + +The evaluation results that form the basis for the experimental data in the paper can be found in the directory `~/witness-validation/paper-evaluation/`. +The witnesses generated by Goblint that formed the basis for this evaluation can be found in `~/witness-generation/paper-evaluation/`. +See below for detailed info to reproduce the tables and figures of the paper. + +The file `~/witness-validation/paper-evaluation/~/witness-validation/paper-evaluation/` contains an HTML overview page generated by the BenchExec benchmarking tool, which displays individual results, quantile and scatter plots. Through the filtering sidebar (top right corner), detailed analyses can be made. + +The table contains the following configurations : + +* `verify` -- GemCutter verification, without any witness +* `verify+validate-goblint-witnesses-{mutex-meet,protection}-{ghost,local}` -- GemCutter witness validation, applied to the 4 different witness sets generated by Goblint. + In this mode, GemCutter checks if the given witness is valid and the corresponding program is correct. +* `validate-goblint-witnesses-{mutex-meet,protection}-{ghost,local}` -- GemCutter witness _confirmation_, applied to the different witness sets. + In this mode, described in the paper, GemCutter only checks if the given witness' invariants are correct, but does not prove the corresponding program correct. + +The summary table shows how many benchmarks were analysed and the results. +- The row `correct true` indicates tasks that were successfully verified (for `verify`), or where the witness was confirmed resp. validated (for the other configurations). +- The row `correct false` indicates that a bug was found (for `verify`), resp. that witness validation failed and a witness was rejected. + The latter only happens for programs that are incorrect, hence there can be no valid correctness witness and rejection is expected. + As witness validation is not possible for incorrect programs, this data is not discussed in the paper and only appears here due to the benchmark setup. +- The row `incorrect false` would indicate that GemCutter finds a supposed bug in a correct program (for `verify`). + For witness confirmation configurations, it indicates that GemCutter confirmed the correctness witness given by Goblint, for an incorrect program. + As witness confirmation ignores the program's correctness, these results are expected and do not indicate a problem in one of the tools. + +The *Table* tab gives access to detailed evaluation results for each file. +Clicking on a status shows the complete GemCutter log for the benchmark run. + +> **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. + +As described above (in section _2. Inspect the evaluation results_), the artifact provides python scripts to directly extract the data shown in the paper from the benchmark results. + + +---------------------------------------------------------------------------------- + +## SOURCE CODE + +### GemCutter + +Ultimate GemCutter is developed as part of the Ultimate program analysis framework () and is implemented in Java. The source code for Ultimate at the time of evaluation can be found in this artifact in the `~/ultimate` directory. + +The directory `trunk/source/CACSL2BoogieTranslator/src/de/uni_freiburg/informatik/ultimate/plugins/generator/cacsl2boogietranslator/witness` is of particular interest for the present paper. +The code in this directory handles instrumentation of the program with various witness entries, as part of Ultimate's translation of the original C code to the intermediate verification language Boogie. + +More recent versions of Ultimate can be found at . + +### Goblint + +The Goblint analyzer () is developed by TU Munich and University of Tartu. The source code for Goblint at the time of evaluation can be found in this artifact in the `~/goblint` directory. + +More recent versions of Goblint can be found at . + +---------------------------------------------------------------------------------- + +## VERIFIER BINARIES + +A pre-built binary of GemCutter can be found in `~/ultimate/releaseScripts/default/UGemCutter-linux/`. +For information on how to execute GemCutter, consult the `README` in `~/ultimate/releaseScripts/default/UGemCutter-linux/`. +To build Ultimate GemCutter from scratch, go to `~/ultimate/releaseScripts/default/` and run `./makeFresh.sh`. + +A pre-built binary of Goblint is available as `~/goblint/goblint`. +See `~/goblint/README.md` for information on how to run Goblint. +To build Goblint from scratch, run `make setup && make release`. + +Both GemCutter and Goblint can be invoked via the BenchExec benchmarking tool () which is installed in the VM. +For examples, see the benchmark definition files `~/witness-generation/goblint.xml` resp. `~/witness-validation/gemcutter.xml` and the scripts `~/scripts/generate-witnesses.sh` resp. `~/scripts/validate-witnesses.sh`. + +---------------------------------------------------------------------------------- + +## BENCHMARK PROGRAMS + +This artifact includes the benchmark programs on which we evaluated the verifiers. +These benchmarks are taken from the publicly available sv-benchmarks set () +and correspond to the _ConcurrencySafety-Main_ category of SV-COMP'24 (). +The benchmarks are written in C and use POSIX threads (`pthreads`) to model concurrency. + +---------------------------------------------------------------------------------- + +## EXTENDING & REUSING THIS ARTIFACT + +* **Building a modified version of the VM:** This VM was created using the `vagrant` tool (). + The `Vagrantfile` used to build the artifact, along with several other files used in the build, is included in the directory `~/artifact`. + This can be used to inspect the setup of the VM, and even build a modified version. + + Note that, to rebuild the VM, some files (e.g. scripts, evaluation results, this README) need to be extracted from the image and placed in a suitable location on your machine. + +* **Adding benchmarks:** You can easily add your own benchmarks programs written in C. + C programs should contain an empty function called `reach_error()`. Goblint and GemCutter then check that this function is never invoked. Certain (gcc) preprocessing steps may be necessary, e.g. to resolve `#include`s. See the SV-COMP benchmarks for examples (the preprocessed files typically have the extension `.i`). + + To run the evaluation on your own programs, you must edit the benchmark definition files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template`. + Replace the `` path specified in the task set `minimal` with your own path. + You can then simply run `~/scripts/quick-run.sh`. + +* **Adding more tools:** As described above, you can reuse the `Vagrantfile` for this artifact and extend it with whatever installation measures are necessary for an additional tool. Also note, that in order to run other tools with BenchExec, you must write a *tool info module* in python (). + + Create a new benchmark definition file for your tool (). + The existing files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template` can serve as an example. + + If you are planning to support generation or validation of correctness witnesses using the proposed format, take a look at the YAML schema definition for the format linked in the paper. + The schema is also available in this artifact as `~/artifact-files/correctness-witness-schema.yml`. + diff --git a/mkdocs.yml b/mkdocs.yml index a4c4238601..b55787f8da 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -41,3 +41,4 @@ nav: - "🇸 SAS '21": artifact-descriptions/sas21.md - "🇪 ESOP '23": artifact-descriptions/esop23.md - "🇻 VMCAI '24": artifact-descriptions/vmcai24.md + - "🇻 VMCAI '25": artifact-descriptions/vmcai25.md From fa3538c576e39166d0d0850772d83273afc95f48 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:21:03 +0200 Subject: [PATCH 677/689] Fix lists in VMACI25 artifact description --- docs/artifact-descriptions/vmcai25.md | 43 ++++++++++++++------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index 08b2c468b8..75374c659b 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -164,22 +164,22 @@ This script behaves similarly to the smaller variants in the previous sections. Note however: - By default the experiments require 16 GB of memory per benchmark (this configuration was used for the experiments in the paper). - To reproduce this, you will have to modify the VM's settings in VirtualBox and increase the available memory (shutdown the machine while doing so). + To reproduce this, you will have to modify the VM's settings in VirtualBox and increase the available memory (shutdown the machine while doing so). - Alternatively, you can run the experiments with a reduced memory limit. - To do so, modify the environment variable `BENCHMARK_PARAMS`. - For instance, the following allows only 4GB of memory per benchmark: + Alternatively, you can run the experiments with a reduced memory limit. + To do so, modify the environment variable `BENCHMARK_PARAMS`. + For instance, the following allows only 4GB of memory per benchmark: - BENCHMARK_PARAMS="-M 4GB" ~/scripts/full-run.sh + BENCHMARK_PARAMS="-M 4GB" ~/scripts/full-run.sh - The full evaluation for the paper required around 3 days. - In this evaluation, we used the benchexec tool to run 14 validation tasks in parallel (occupying up to 28 cores at a time). + In this evaluation, we used the benchexec tool to run 14 validation tasks in parallel (occupying up to 28 cores at a time). - By default, the provided script only runs one benchmark at a time. - If you have sufficient cores and memory available (adjust the VM settings accordingly), you can run multiple benchmarks in parallel by setting the environment variable `BENCHEXEC_THREADS`. You may also execute the experiments with a reduced timeout. - For instance, the following command runs 4 benchmarks in parallel at a time (occupying up to 8 cores), and gives each benchmark a 300s timeout and 4GB memory limit: + By default, the provided script only runs one benchmark at a time. + If you have sufficient cores and memory available (adjust the VM settings accordingly), you can run multiple benchmarks in parallel by setting the environment variable `BENCHEXEC_THREADS`. You may also execute the experiments with a reduced timeout. + For instance, the following command runs 4 benchmarks in parallel at a time (occupying up to 8 cores), and gives each benchmark a 300s timeout and 4GB memory limit: - BENCHEXEC_THREADS=4 BENCHMARK_PARAMS="-T 300s -M 4GB" ~/scripts/full-run.sh + BENCHEXEC_THREADS=4 BENCHMARK_PARAMS="-T 300s -M 4GB" ~/scripts/full-run.sh Naturally, changes to the timeout or memory are expected to affect the evaluation numbers. @@ -202,6 +202,7 @@ The table contains the following configurations : In this mode, described in the paper, GemCutter only checks if the given witness' invariants are correct, but does not prove the corresponding program correct. The summary table shows how many benchmarks were analysed and the results. + - The row `correct true` indicates tasks that were successfully verified (for `verify`), or where the witness was confirmed resp. validated (for the other configurations). - The row `correct false` indicates that a bug was found (for `verify`), resp. that witness validation failed and a witness was rejected. The latter only happens for programs that are incorrect, hence there can be no valid correctness witness and rejection is expected. @@ -266,23 +267,23 @@ The benchmarks are written in C and use POSIX threads (`pthreads`) to model conc ## EXTENDING & REUSING THIS ARTIFACT * **Building a modified version of the VM:** This VM was created using the `vagrant` tool (). - The `Vagrantfile` used to build the artifact, along with several other files used in the build, is included in the directory `~/artifact`. - This can be used to inspect the setup of the VM, and even build a modified version. + The `Vagrantfile` used to build the artifact, along with several other files used in the build, is included in the directory `~/artifact`. + This can be used to inspect the setup of the VM, and even build a modified version. - Note that, to rebuild the VM, some files (e.g. scripts, evaluation results, this README) need to be extracted from the image and placed in a suitable location on your machine. + Note that, to rebuild the VM, some files (e.g. scripts, evaluation results, this README) need to be extracted from the image and placed in a suitable location on your machine. * **Adding benchmarks:** You can easily add your own benchmarks programs written in C. - C programs should contain an empty function called `reach_error()`. Goblint and GemCutter then check that this function is never invoked. Certain (gcc) preprocessing steps may be necessary, e.g. to resolve `#include`s. See the SV-COMP benchmarks for examples (the preprocessed files typically have the extension `.i`). + C programs should contain an empty function called `reach_error()`. Goblint and GemCutter then check that this function is never invoked. Certain (gcc) preprocessing steps may be necessary, e.g. to resolve `#include`s. See the SV-COMP benchmarks for examples (the preprocessed files typically have the extension `.i`). - To run the evaluation on your own programs, you must edit the benchmark definition files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template`. - Replace the `` path specified in the task set `minimal` with your own path. - You can then simply run `~/scripts/quick-run.sh`. + To run the evaluation on your own programs, you must edit the benchmark definition files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template`. + Replace the `` path specified in the task set `minimal` with your own path. + You can then simply run `~/scripts/quick-run.sh`. * **Adding more tools:** As described above, you can reuse the `Vagrantfile` for this artifact and extend it with whatever installation measures are necessary for an additional tool. Also note, that in order to run other tools with BenchExec, you must write a *tool info module* in python (). - Create a new benchmark definition file for your tool (). - The existing files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template` can serve as an example. + Create a new benchmark definition file for your tool (). + The existing files `~/witness-generation/goblint.xml.template` resp. `~/witness-validation/gemcutter.xml.template` can serve as an example. - If you are planning to support generation or validation of correctness witnesses using the proposed format, take a look at the YAML schema definition for the format linked in the paper. - The schema is also available in this artifact as `~/artifact-files/correctness-witness-schema.yml`. + If you are planning to support generation or validation of correctness witnesses using the proposed format, take a look at the YAML schema definition for the format linked in the paper. + The schema is also available in this artifact as `~/artifact-files/correctness-witness-schema.yml`. From 9fecf6ee40761503ee63b1072db0937e23dbdc69 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:23:28 +0200 Subject: [PATCH 678/689] Add Goblint code references to VMCAI25 artifact description --- docs/artifact-descriptions/vmcai25.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index 75374c659b..b4eec295ac 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -236,6 +236,16 @@ More recent versions of Ultimate can be found at ) is developed by TU Munich and University of Tartu. The source code for Goblint at the time of evaluation can be found in this artifact in the `~/goblint` directory. +The code for this paper is the following: + +1. `src/witness/witnessGhostVar.ml` and `src/witness/witnessGhost.ml` define the data types for ghost variables. +2. `src/analyses/mutexGhosts.ml` defines the analysis which determines the ghost variables for a specific program and their updates. +3. `src/analyses/basePriv.ml` lines 342-365 define the invariants with mutex ghost variables from non-relational _mutex-meet_ analysis. +4. `src/analyses/apron/relationPriv.apron.ml` lines 717-750 define the invariants with mutex ghost variables from relational _mutex-meet_ analysis. +5. `src/analyses/base.ml` lines 1269-1289 and `src/analyses/apron/relationAnalysis.apron.ml` lines 637-644 define the wrapping of the invariants with multithreaded mode ghost variables. +6. `src/analyses/basePriv.ml` lines 882-909 define the invariants with mutex ghost variables from (non-relational) _protection_ analysis. +7. `src/witness/yamlWitness.ml` lines 398-421 and 589-621 define the YAML output of ghost variables, their updates and the invariants. + More recent versions of Goblint can be found at . ---------------------------------------------------------------------------------- From 5c9b5fb5e67572f5b8dd4a0424558d469b7bcf2f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:28:46 +0200 Subject: [PATCH 679/689] Rewrite VMCAI25 artifact description intro --- docs/artifact-descriptions/vmcai25.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index b4eec295ac..ac9312caa8 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -1,4 +1,11 @@ -# Artifact for VMCAI'2025 Paper "Correctness Witnesses for Concurrent Programs: Bridging the Semantic Divide with Ghosts" +# VMCAI '25 Artifact Description +## Correctness Witnesses for Concurrent Programs: Bridging the Semantic Divide with Ghosts + +This is the artifact description for our [VMCAI '25 paper "Correctness Witnesses for Concurrent Programs: Bridging the Semantic Divide with Ghosts"](https://doi.org/10.48550/arXiv.2411.16612). +The artifact is available on [Zenodo](https://doi.org/10.5281/zenodo.13863579). + +**The description here is provided for convenience and not maintained.** +The artifact contains [Goblint at `vmcai25` git tag](https://github.com/goblint/analyzer/releases/tag/vmcai25). ------------------------------------------------------------------------------- From 55bfe9631ab58fdf0275b8560eb222eba0e2f361 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:31:55 +0200 Subject: [PATCH 680/689] Remove all-caps headings in VMCAI25 artifact description --- docs/artifact-descriptions/vmcai25.md | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index ac9312caa8..9f2de1c511 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -9,20 +9,20 @@ The artifact contains [Goblint at `vmcai25` git tag](https://github.com/goblint/ ------------------------------------------------------------------------------- -## OVERVIEW +## Overview This artifact contains the following components: - EVALUATION RESULTS :: The evaluation results, and overview tables (HTML) + Evaluation Results :: The evaluation results, and overview tables (HTML) generated from the raw data. - SOURCE CODE :: Source code for Goblint and Ultimate GemCutter, + Source Code :: Source code for Goblint and Ultimate GemCutter, the verification tools used in the experiments for the paper. - VERIFIER BINARIES :: Binaries for Goblint and Ultimate GemCutter. - BENCHMARK PROGRAMS :: Benchmarks used for evaluation of the verifiers. - BENCHMARK WITNESSES :: The witnesses generated by Goblint, as used in the + Verifier Binaries :: Binaries for Goblint and Ultimate GemCutter. + Benchmark Programs :: Benchmarks used for evaluation of the verifiers. + Benchmark Witnesses :: The witnesses generated by Goblint, as used in the experiments. - BENCHEXEC TOOL :: The BenchExec benchmarking tool can be used + BenchExec Tool :: The BenchExec benchmarking tool can be used to replicate our results on these benchmarks. The next section gives instructions on how to setup and quickly get an overview of the artifact. @@ -31,7 +31,7 @@ The final section gives information on how to reuse this artifact. ------------------------------------------------------------------------------- -## GETTING STARTED +## Getting Started ### 1. Setup @@ -67,7 +67,7 @@ The times for the Table 2 are given first in seconds and then pretty-printed as For a more detailed inspection and visualization of the data, take a look at the generated HTML report. Just open the file `~/witness-validation/paper-evaluation/results.2024-09-24_22-00-48.table.html` in firefox. -For detailed information, see the "EVALUATION RESULTS" section below. +For detailed information, see the "Evaluation Results" section below. ### 3. Quick Test of the Benchmark Setup @@ -192,7 +192,7 @@ Naturally, changes to the timeout or memory are expected to affect the evaluatio ---------------------------------------------------------------------------------- -## EVALUATION RESULTS +## Evaluation Results The evaluation results that form the basis for the experimental data in the paper can be found in the directory `~/witness-validation/paper-evaluation/`. The witnesses generated by Goblint that formed the basis for this evaluation can be found in `~/witness-generation/paper-evaluation/`. @@ -228,7 +228,7 @@ As described above (in section _2. Inspect the evaluation results_), the artifac ---------------------------------------------------------------------------------- -## SOURCE CODE +## Source Code ### GemCutter @@ -257,7 +257,7 @@ More recent versions of Goblint can be found at . ---------------------------------------------------------------------------------- -## VERIFIER BINARIES +## Verifier Binaries A pre-built binary of GemCutter can be found in `~/ultimate/releaseScripts/default/UGemCutter-linux/`. For information on how to execute GemCutter, consult the `README` in `~/ultimate/releaseScripts/default/UGemCutter-linux/`. @@ -272,7 +272,7 @@ For examples, see the benchmark definition files `~/witness-generation/goblint.x ---------------------------------------------------------------------------------- -## BENCHMARK PROGRAMS +## Benchmark Programs This artifact includes the benchmark programs on which we evaluated the verifiers. These benchmarks are taken from the publicly available sv-benchmarks set () @@ -281,7 +281,7 @@ The benchmarks are written in C and use POSIX threads (`pthreads`) to model conc ---------------------------------------------------------------------------------- -## EXTENDING & REUSING THIS ARTIFACT +## Extending & Reusing This Artifact * **Building a modified version of the VM:** This VM was created using the `vagrant` tool (). The `Vagrantfile` used to build the artifact, along with several other files used in the build, is included in the directory `~/artifact`. From fcc2d02afcd1bb5c4e8c140cc10f5569cc18f569 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:32:37 +0200 Subject: [PATCH 681/689] Remove horizontal rules in VMCAI25 artifact description --- docs/artifact-descriptions/vmcai25.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index 9f2de1c511..d53faa310a 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -7,7 +7,6 @@ The artifact is available on [Zenodo](https://doi.org/10.5281/zenodo.13863579). **The description here is provided for convenience and not maintained.** The artifact contains [Goblint at `vmcai25` git tag](https://github.com/goblint/analyzer/releases/tag/vmcai25). -------------------------------------------------------------------------------- ## Overview @@ -29,7 +28,6 @@ The next section gives instructions on how to setup and quickly get an overview The subsequent sections then describe each of these components in detail. The final section gives information on how to reuse this artifact. -------------------------------------------------------------------------------- ## Getting Started @@ -190,7 +188,6 @@ Note however: Naturally, changes to the timeout or memory are expected to affect the evaluation numbers. ----------------------------------------------------------------------------------- ## Evaluation Results @@ -226,8 +223,6 @@ Clicking on a status shows the complete GemCutter log for the benchmark run. As described above (in section _2. Inspect the evaluation results_), the artifact provides python scripts to directly extract the data shown in the paper from the benchmark results. ----------------------------------------------------------------------------------- - ## Source Code ### GemCutter @@ -255,7 +250,6 @@ The code for this paper is the following: More recent versions of Goblint can be found at . ----------------------------------------------------------------------------------- ## Verifier Binaries @@ -270,7 +264,6 @@ To build Goblint from scratch, run `make setup && make release`. Both GemCutter and Goblint can be invoked via the BenchExec benchmarking tool () which is installed in the VM. For examples, see the benchmark definition files `~/witness-generation/goblint.xml` resp. `~/witness-validation/gemcutter.xml` and the scripts `~/scripts/generate-witnesses.sh` resp. `~/scripts/validate-witnesses.sh`. ----------------------------------------------------------------------------------- ## Benchmark Programs @@ -279,7 +272,6 @@ These benchmarks are taken from the publicly available sv-benchmarks set (). The benchmarks are written in C and use POSIX threads (`pthreads`) to model concurrency. ----------------------------------------------------------------------------------- ## Extending & Reusing This Artifact From 73295e4bc72ab75a00bcb9406c054d90dde742f3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:37:32 +0200 Subject: [PATCH 682/689] Fix and add links in VMCAI25 artifact description --- docs/artifact-descriptions/vmcai25.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index d53faa310a..8b0cabbbaf 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -36,7 +36,7 @@ The final section gives information on how to reuse this artifact. The artifact is a virtual machine (VM). Follow these steps to set it up: * If you have not done so already, install VirtualBox. - (https://www.virtualbox.org/wiki/Downloads) + () * Download the artifact. * Import the artifact via the VirtualBox UI (`File > Import Appliance`) or by running `VBoxManage import ghost-witnesses.ova`. @@ -65,7 +65,7 @@ The times for the Table 2 are given first in seconds and then pretty-printed as For a more detailed inspection and visualization of the data, take a look at the generated HTML report. Just open the file `~/witness-validation/paper-evaluation/results.2024-09-24_22-00-48.table.html` in firefox. -For detailed information, see the "Evaluation Results" section below. +For detailed information, see the ["Evaluation Results" section](#evaluation-results) below. ### 3. Quick Test of the Benchmark Setup @@ -220,7 +220,7 @@ Clicking on a status shows the complete GemCutter log for the benchmark run. > **Note:** If you are trying to view logs for individual runs through the HTML table (by clicking on the evaluation result `true` or `false`), you may encounter a warning because browsers block access to local files. Follow the instructions in the message to enable log viewing. -As described above (in section _2. Inspect the evaluation results_), the artifact provides python scripts to directly extract the data shown in the paper from the benchmark results. +As described above (in [section _2. Inspect the evaluation results_](#2-inspect-the-evaluation-results)), the artifact provides python scripts to directly extract the data shown in the paper from the benchmark results. ## Source Code From 2c90552b8e03581f4d9d83e2a90fbf0de2e25419 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 12:38:07 +0200 Subject: [PATCH 683/689] Fix duplicated path in VMCAI25 artifact description --- docs/artifact-descriptions/vmcai25.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/artifact-descriptions/vmcai25.md b/docs/artifact-descriptions/vmcai25.md index 8b0cabbbaf..282be65ff0 100644 --- a/docs/artifact-descriptions/vmcai25.md +++ b/docs/artifact-descriptions/vmcai25.md @@ -195,7 +195,7 @@ The evaluation results that form the basis for the experimental data in the pape The witnesses generated by Goblint that formed the basis for this evaluation can be found in `~/witness-generation/paper-evaluation/`. See below for detailed info to reproduce the tables and figures of the paper. -The file `~/witness-validation/paper-evaluation/~/witness-validation/paper-evaluation/` contains an HTML overview page generated by the BenchExec benchmarking tool, which displays individual results, quantile and scatter plots. Through the filtering sidebar (top right corner), detailed analyses can be made. +The file `~/witness-validation/paper-evaluation/` contains an HTML overview page generated by the BenchExec benchmarking tool, which displays individual results, quantile and scatter plots. Through the filtering sidebar (top right corner), detailed analyses can be made. The table contains the following configurations : From 1e88c86a1cd795cdde2a76166d5323e0a9e51f91 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 15:53:24 +0200 Subject: [PATCH 684/689] Add potential NOTIMEOUT to 06-symbeq/34-var_eq-exponential-context --- tests/regression/06-symbeq/34-var_eq-exponential-context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/06-symbeq/34-var_eq-exponential-context.c b/tests/regression/06-symbeq/34-var_eq-exponential-context.c index bc478374f0..8b9b76a89e 100644 --- a/tests/regression/06-symbeq/34-var_eq-exponential-context.c +++ b/tests/regression/06-symbeq/34-var_eq-exponential-context.c @@ -1,5 +1,5 @@ // SKIP PARAM: --set ana.activated[+] var_eq - +// NOTIMEOUT? void level0(int *p) { } From 55e497387b7dc07967a494bb7f3c0a40e3128973 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 15:57:21 +0200 Subject: [PATCH 685/689] Renumber 06-symbeq/41-var_eq_multithread to fix duplicate ID --- .../{41-var_eq_multithread.c => 47-var_eq_multithread.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/regression/06-symbeq/{41-var_eq_multithread.c => 47-var_eq_multithread.c} (100%) diff --git a/tests/regression/06-symbeq/41-var_eq_multithread.c b/tests/regression/06-symbeq/47-var_eq_multithread.c similarity index 100% rename from tests/regression/06-symbeq/41-var_eq_multithread.c rename to tests/regression/06-symbeq/47-var_eq_multithread.c From c24821f83adacfa211fb3082192046088a22877c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 16:03:10 +0200 Subject: [PATCH 686/689] Fix double-locking in symbolic regression tests --- tests/regression/06-symbeq/20-mult_accs_nr.c | 2 +- tests/regression/06-symbeq/21-mult_accs_rc.c | 2 +- tests/regression/06-symbeq/21-mult_accs_rc.t | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/regression/06-symbeq/20-mult_accs_nr.c b/tests/regression/06-symbeq/20-mult_accs_nr.c index 7d66e3f5d2..50c8f19a62 100644 --- a/tests/regression/06-symbeq/20-mult_accs_nr.c +++ b/tests/regression/06-symbeq/20-mult_accs_nr.c @@ -15,7 +15,7 @@ void *t_fun(void *arg) { pthread_mutex_lock(&s->mutex); s->data = 5; // NORACE s->lore = 6; // NORACE - pthread_mutex_lock(&s->mutex); + pthread_mutex_unlock(&s->mutex); return NULL; } diff --git a/tests/regression/06-symbeq/21-mult_accs_rc.c b/tests/regression/06-symbeq/21-mult_accs_rc.c index 62550fab55..4acadb4a58 100644 --- a/tests/regression/06-symbeq/21-mult_accs_rc.c +++ b/tests/regression/06-symbeq/21-mult_accs_rc.c @@ -14,7 +14,7 @@ void *t_fun(void *arg) { pthread_mutex_lock(&s->mutex); s = get_s(); s->data = 5; // RACE! - pthread_mutex_lock(&s->mutex); + pthread_mutex_unlock(&s->mutex); return NULL; } diff --git a/tests/regression/06-symbeq/21-mult_accs_rc.t b/tests/regression/06-symbeq/21-mult_accs_rc.t index ca2e219b05..2eacd0382e 100644 --- a/tests/regression/06-symbeq/21-mult_accs_rc.t +++ b/tests/regression/06-symbeq/21-mult_accs_rc.t @@ -3,7 +3,7 @@ Disable info messages because race summary contains (safe) memory location count $ goblint --enable warn.deterministic --disable warn.info --enable ana.race.direct-arithmetic --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" 21-mult_accs_rc.c 2>&1 | tee default-output-1.txt [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:14:3-14:32) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:16:3-16:14) - [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:17:3-17:32) + [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:17:3-17:34) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:28:3-28:16) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:29:3-29:15) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) @@ -11,7 +11,8 @@ Disable info messages because race summary contains (safe) memory location count write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) write with [symblock:{p-lock:*.mutex}, mhp:{created={[main, t_fun@21-mult_accs_rc.c:31:3-31:37]}}, thread:[main]] (conf. 100) (exp: & *d) (21-mult_accs_rc.c:34:3-34:9) [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:14:3-14:32) - [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:17:3-17:32) + [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:17:3-17:34) + [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:17:3-17:34) [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:33:3-33:24) [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) @@ -23,14 +24,15 @@ Disable info messages because race summary contains (safe) memory location count $ goblint --enable warn.deterministic --disable warn.info --disable ana.race.direct-arithmetic --set ana.activated[+] "'var_eq'" --set ana.activated[+] "'symb_locks'" --enable allglobs 21-mult_accs_rc.c 2>&1 | tee default-output-2.txt [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:14:3-14:32) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:16:3-16:14) - [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:17:3-17:32) + [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:17:3-17:34) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:28:3-28:16) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:29:3-29:15) [Warning][Behavior > Undefined > NullPointerDereference][CWE-476] May dereference NULL pointer (21-mult_accs_rc.c:34:3-34:9) [Success][Race] Memory location (struct s).data (safe): write with thread:[main, t_fun@21-mult_accs_rc.c:31:3-31:37] (conf. 100) (exp: & s->data) (21-mult_accs_rc.c:16:3-16:14) [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:14:3-14:32) - [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:17:3-17:32) + [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:17:3-17:34) + [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:17:3-17:34) [Warning][Unknown] locking NULL mutex (21-mult_accs_rc.c:33:3-33:24) [Warning][Unknown] unlocking NULL mutex (21-mult_accs_rc.c:35:3-35:26) [Warning][Unknown] unlocking unknown mutex which may not be held (21-mult_accs_rc.c:35:3-35:26) From 87ce3a5788ff89ffb931414ae29a6ca26442f6f5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 10 Dec 2024 16:05:11 +0200 Subject: [PATCH 687/689] Comment reversal of PartitionDomain.SetSet --- src/domain/partitionDomain.ml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/domain/partitionDomain.ml b/src/domain/partitionDomain.ml index 316f4fb705..e97946e463 100644 --- a/src/domain/partitionDomain.ml +++ b/src/domain/partitionDomain.ml @@ -106,6 +106,9 @@ struct let show _ = "Partitions" + (* Top and bottom are reversed: + Bottom will be All (equations), i.e. contradiction, + Top will be empty set, i.e. no equations. *) let top = E.bot let bot = E.top let is_top = E.is_bot From 4a9b52f57702586b1e876cde83bdedac3119b6f6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 Dec 2024 10:56:50 +0200 Subject: [PATCH 688/689] Fix invalid widen call in slr3 for globals --- src/solver/sLR.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/sLR.ml b/src/solver/sLR.ml index 69d415307a..299bbbce52 100644 --- a/src/solver/sLR.ml +++ b/src/solver/sLR.ml @@ -66,7 +66,7 @@ module SLR3 = if tracing then trace "sol" "Contrib:%a" S.Dom.pretty tmp; let tmp = if wpx then - if HM.mem globals x then S.Dom.widen old tmp (* TODO: no join in second argument, can call widen incorrectly? *) + if HM.mem globals x then S.Dom.widen old (S.Dom.join old tmp) else box old tmp else tmp in From b0243f91c6a3013d797b7a6cde8c59a605cfe0c4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 16 Dec 2024 11:00:43 +0200 Subject: [PATCH 689/689] Disable broken two solver --- src/solver/sLR.ml | 2 +- tests/regression/00-sanity/01-assert.t | 115 ------------------------- 2 files changed, 1 insertion(+), 116 deletions(-) diff --git a/src/solver/sLR.ml b/src/solver/sLR.ml index 299bbbce52..03ba9307aa 100644 --- a/src/solver/sLR.ml +++ b/src/solver/sLR.ml @@ -527,7 +527,7 @@ let _ = Selector.add_solver ("widen2", (module PostSolver.EqIncrSolverFromEqSolver (W2))); Selector.add_solver ("widen3", (module PostSolver.EqIncrSolverFromEqSolver (W3))); let module S2 = TwoPhased (struct let ver = 1 end) in - Selector.add_solver ("two", (module PostSolver.EqIncrSolverFromEqSolver (S2))); (* TODO: broken even on 00-sanity/01-assert *) + (* Selector.add_solver ("two", (module PostSolver.EqIncrSolverFromEqSolver (S2))); (* TODO: broken even on 00-sanity/01-assert *) *) let module S1 = Make (struct let ver = 1 end) in Selector.add_solver ("new", (module PostSolver.EqIncrSolverFromEqSolver (S1))); Selector.add_solver ("slr+", (module PostSolver.EqIncrSolverFromEqSolver (S1))) diff --git a/tests/regression/00-sanity/01-assert.t b/tests/regression/00-sanity/01-assert.t index cd8c4c06f8..9b3b55f530 100644 --- a/tests/regression/00-sanity/01-assert.t +++ b/tests/regression/00-sanity/01-assert.t @@ -139,121 +139,6 @@ Test SLR solvers: dead: 2 total lines: 9 - $ goblint --enable warn.deterministic --set solver two 01-assert.c - [Error] Fixpoint not reached at L:entry state of main (299) on 01-assert.c:4:1-15:1 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), - mallocWrapper:(wrapper call:Unknown node, unique calls:{}), - base:({ - }, {}, {}, {}), - threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), - threadflag:Singlethreaded, - threadreturn:true, - escape:{}, - mutexEvents:(), - access:(), - mutex:(lockset:{}, multiplicity:{}), - race:(), - mhp:(), - assert:(), - pthreadMutexType:()], map:{})} - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):PathSensitive (ProjectiveSet (MCP.D * map)):{(MCP.D:[expRelation:(), - mallocWrapper:(wrapper call:Unknown node, unique calls:{}), - base:({ - }, {}, {}, {}), - threadid:(wrapper call:unknown node, Thread:[main], created:(current function:bot, callees:bot)), - threadflag:Singlethreaded, - threadreturn:true, - escape:{}, - mutexEvents:(), - access:(), - mutex:(lockset:{}, multiplicity:{}), - race:(), - mhp:(), - assert:(), - pthreadMutexType:()], map:{})} instead of bot - - [Error] Fixpoint not reached at L:node 1 "success = 1;" on 01-assert.c:5:7-5:18 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 2 "silence = 1;" on 01-assert.c:6:7-6:18 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 3 "fail = 0;" on 01-assert.c:7:7-7:15 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 4 "__goblint_assert(success);" on 01-assert.c:10:3-10:28 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 5 "__goblint_assert(unknown == 4);" on 01-assert.c:11:3-11:33 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 6 "__goblint_assert(fail);" on 01-assert.c:12:3-12:25 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 7 "return (0);" on 01-assert.c:13:10-13:11 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node 9 "__goblint_assert(silence);" on 01-assert.c:14:3-14:28 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:node -299 "return;" on 01-assert.c:15:1-15:1 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Error] Fixpoint not reached at L:call of main (299) on 01-assert.c:4:1-15:1 - Solver computed: - bot - Right-Hand-Side: - HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code - Difference: HConsed lifted PathSensitive (ProjectiveSet (MCP.D * map)):Dead code instead of bot - - [Warning][Deadcode] Function 'main' does not return - [Warning][Deadcode] Function 'main' is uncalled: 8 LLoC (01-assert.c:4:1-15:1) - [Info][Deadcode] Logical lines of code (LLoC) summary: - live: 0 - dead: 8 (8 in uncalled functions) - total lines: 8 - [Error][Unsound] Fixpoint not reached - [3] - $ goblint --enable warn.deterministic --set solver new 01-assert.c [Error][Assert] Assertion "fail" will fail. (01-assert.c:12:3-12:25) [Warning][Assert] Assertion "unknown == 4" is unknown. (01-assert.c:11:3-11:33)