From b811f982702426339c2e17e48db68dd719578e58 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Thu, 15 Oct 2026 19:01:51 -0400 Subject: [PATCH 01/44] test: add regression corpus runner for the Rust runtime cutover --- scripts/cutover/run-corpus.sh | 52 ++++++++++++++++++++++++++++++ scripts/cutover/test-run-corpus.sh | 27 ++++++++++++++++ tests/cutover/README.md | 42 ++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100755 scripts/cutover/run-corpus.sh create mode 100755 scripts/cutover/test-run-corpus.sh create mode 100644 tests/cutover/README.md diff --git a/scripts/cutover/run-corpus.sh b/scripts/cutover/run-corpus.sh new file mode 100755 index 000000000..c0c7b7131 --- /dev/null +++ b/scripts/cutover/run-corpus.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# Executa o corpus de regressão e grava, por tarefa/propriedade/gerador/repetição, +# o veredito, a tag de map2check_property, linha, função, witness, tempo e RSS. +# Uso: run-corpus.sh +set -euo pipefail +BIN_DIR="$(cd "$1" && pwd)"; OUT="$2" +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +CASES="${CASES:-$ROOT/tests/regression_test/test_cases/sv-benchmarks}" +GENS="${GENS:-fuzzer symex}"; REPS="${REPS:-5}"; TIMEOUT="${TIMEOUT:-45}" + +flags_for() { + case "$1" in + valid-memsafety) echo "--memtrack" ;; + valid-memcleanup) echo "--memtrack --memcleanup-property" ;; + no-overflow) echo "--check-overflow" ;; + unreach-call) echo "--target-function" ;; + *) return 1 ;; + esac +} + +printf 'task\tprp\tgen\trep\tverdict\ttag\tline\tfunction\twitness\twall_s\tmaxrss_kb\n' > "$OUT" +while IFS= read -r yml; do + dir="$(dirname "$yml")" + input="$dir/$(sed -nE "s/^input_files: *'?([^' ]+)'?.*/\1/p" "$yml")" + while IFS= read -r prp; do + flags="$(flags_for "$prp")" || continue + for gen in $GENS; do + for rep in $(seq 1 "$REPS"); do + work="$(mktemp -d)" + # shellcheck disable=SC2086 + ( cd "$work" && /usr/bin/time -f '%e\t%M' -o time.txt \ + timeout "$TIMEOUT" "$BIN_DIR/map2check" --nondet-generator "$gen" $flags "$input" \ + > out.txt 2>&1 ) || true + verdict=TIMEOUT + grep -q 'VERIFICATION SUCCEEDED' "$work/out.txt" && verdict=SUCCEEDED + grep -q 'VERIFICATION FAILED' "$work/out.txt" && verdict=FAILED + grep -q 'VERIFICATION UNKNOWN' "$work/out.txt" && verdict=UNKNOWN + tag=-; line=-; func=- + if [ -f "$work/map2check_property" ]; then + tag="$(sed -n 1p "$work/map2check_property")" + line="$(sed -nE 's/^Line: *//p' "$work/map2check_property" | head -1)"; line="${line:--}" + func="$(sed -nE 's/^Function: *//p' "$work/map2check_property" | head -1)"; func="${func:--}" + fi + witness=0; ls "$work"/*.graphml "$work"/map2check_checked_error >/dev/null 2>&1 && witness=1 + timing="$(tail -1 "$work/time.txt" 2>/dev/null || printf -- '-\t-')" + printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \ + "${yml#"$CASES"/}" "$prp" "$gen" "$rep" "$verdict" "$tag" "$line" "$func" "$witness" "$timing" >> "$OUT" + rm -rf "$work" + done + done + done < <(sed -nE 's#.*property_file: *.*/([a-z-]+)\.prp.*#\1#p' "$yml") +done < <(find "$CASES" -name '*.yml' | sort) diff --git a/scripts/cutover/test-run-corpus.sh b/scripts/cutover/test-run-corpus.sh new file mode 100755 index 000000000..4c6a5aeb8 --- /dev/null +++ b/scripts/cutover/test-run-corpus.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Testa run-corpus.sh com um binário falso e um corpus de uma tarefa. +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT +mkdir -p "$T/bin" "$T/cases/x" +cat > "$T/bin/map2check" <<'EOS' +#!/usr/bin/env bash +printf 'FALSE-DEREF\nLine: 7\nFunction: main\n' > map2check_property +echo "VERIFICATION FAILED" +EOS +chmod +x "$T/bin/map2check" +printf 'int main(){}\n' > "$T/cases/x/a.c" +cat > "$T/cases/x/a.yml" <<'EOS' +format_version: '1.0' +input_files: 'a.c' +properties: + - property_file: ../properties/valid-memsafety.prp + expected_verdict: false +EOS +CASES="$T/cases" GENS=fuzzer REPS=1 "$HERE/run-corpus.sh" "$T/bin" "$T/out.tsv" +row="$(sed -n 2p "$T/out.tsv")" +IFS=$'\t' read -r task prp gen rep verdict tag line func witness wall rss <<<"$row" +[ "$task" = "x/a.yml" ] && [ "$prp" = "valid-memsafety" ] && [ "$gen" = fuzzer ] \ + && [ "$verdict" = FAILED ] && [ "$tag" = FALSE-DEREF ] && [ "$line" = 7 ] \ + && [ "$func" = main ] && [ "$witness" = 0 ] || { echo "linha inesperada: $row" >&2; exit 1; } +echo ok diff --git a/tests/cutover/README.md b/tests/cutover/README.md new file mode 100644 index 000000000..5e4384311 --- /dev/null +++ b/tests/cutover/README.md @@ -0,0 +1,42 @@ +# Cutover regression baseline (C runtime) + +Reference data for the Map2Check C -> Rust runtime cutover. Produced by +`scripts/cutover/run-corpus.sh`, consumed by the Rust comparison (Task 4.1). + +- Map2Check commit: `f01e8c3ee66a2d54d91805f87443eaa57b598414` +- Image: `map2check-dev:latest`, ID `sha256:adbb5ec2824d3c3387781c0b6d45ffe365313335bd702dc10a4ae56d097d2b9c` +- CPU: 12th Gen Intel(R) Core(TM) i7-12650H +- The image lacks `/usr/bin/time`; the container installs the `time` package + (`apt-get install -y time`) before the build. The runner needs it. +- Configure flags (as in CI): `-G Ninja -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm -DMAP2CHECK_DYNAMIC_LINK=ON -DCMAKE_INSTALL_PREFIX=/src/release`; + the installed tree needs `lib/klee/runtime` and `lib/clang` symlinks (CI does the same). +- `MAP2CHECK_PATH=/src/release` is exported for the wrapper. + +## Full baseline command + +```sh +docker run --rm -u root -v "$PWD":/src -w /src map2check-dev:latest bash -c ' + apt-get update -qq && apt-get install -y -qq time >/dev/null && + cmake -S . -B build -G Ninja -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm -DMAP2CHECK_DYNAMIC_LINK=ON -DCMAKE_INSTALL_PREFIX=/src/release && + cmake --build build && cmake --install build && + mkdir -p release/lib/klee && + ln -sfn /opt/klee/lib/klee/runtime release/lib/klee/runtime && + ln -sfn /usr/lib/llvm-16/lib/clang release/lib/clang && + GENS="symex" REPS=5 TIMEOUT=45 MAP2CHECK_PATH=/src/release \ + scripts/cutover/run-corpus.sh release tests/cutover/baseline-c.tsv' +``` + +Runner self-test: `bash scripts/cutover/test-run-corpus.sh`. + +## Known issues found during the smoke run (read before running the full baseline) + +- The runner argument is `release` (the dir holding the `map2check` wrapper), not `release/bin`. +- The C binary has no `fuzzer` generator; valid values are `afl` and `symex`. `GENS=fuzzer` + gives "Selected generator don't exist" (runner records TIMEOUT). `afl` needs + `/usr/local/bin/afl-clang-fast`, absent from this image (runner records UNKNOWN). + Only `symex` works in `map2check-dev:latest`, so the command above uses `GENS="symex"`. +- The C pipeline chdirs into a scratch dir and removes it, so `map2check_property` is never + left in the runner's cwd: tag/line/function columns are `-` for C. They are printed on stdout + ("Violated property: file ... line N function F" then "TAG: ...") if Task 4.1 needs them. +- Smoke (symex, REPS=1): 11 FAILED, 4 SUCCEEDED, 26 UNKNOWN (41 rows, ~1 s each; KLEE + "Forcing timeout" yields UNKNOWN). From 58e4f4bcdcd63bd7835838b3769d8bd01ef09097 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Thu, 15 Oct 2026 19:25:57 -0400 Subject: [PATCH 02/44] test: derive C runtime property fields from stdout and pass map2check --timeout in the corpus runner --- scripts/cutover/fixtures/c-failed-stdout.txt | 76 +++++++++++++++++++ .../cutover/fixtures/c-succeeded-stdout.txt | 42 ++++++++++ scripts/cutover/run-corpus.sh | 26 ++++++- scripts/cutover/test-run-corpus.sh | 22 ++++++ tests/cutover/README.md | 23 +++--- 5 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 scripts/cutover/fixtures/c-failed-stdout.txt create mode 100644 scripts/cutover/fixtures/c-succeeded-stdout.txt diff --git a/scripts/cutover/fixtures/c-failed-stdout.txt b/scripts/cutover/fixtures/c-failed-stdout.txt new file mode 100644 index 000000000..1a38518d3 --- /dev/null +++ b/scripts/cutover/fixtures/c-failed-stdout.txt @@ -0,0 +1,76 @@ +Adopting z3 solver... +Adopting symex nondet-generator... +Started Map2Check +Compiling /src/tests/regression_test/test_cases/sv-benchmarks/array-examples/relax-1.c +Adding nondet pass +Adding memtrack pass +Adding map2check pass +Linking with map2check library +Applying optimizations for klee +Executing Klee with map2check +Solver backend caller: z3 +KLEE: NOTE: Using klee-uclibc : /src/release/lib/klee/runtime/klee-uclibc.bca +KLEE: output directory is "/tmp/tmp.CKJE0V2SXY/10a8cc7f8ad88ce445fb123804a07fc4ee780c31.map2check/./klee-out-0" +KLEE: Using Z3 solver backend +KLEE: Deterministic allocator: Using quarantine queue size 8 +KLEE: Deterministic allocator: globals (start-address=0x7f18e9600000 size=10 GiB) +KLEE: Deterministic allocator: constants (start-address=0x7f1669600000 size=10 GiB) +KLEE: Deterministic allocator: heap (start-address=0x7e1669600000 size=1024 GiB) +KLEE: Deterministic allocator: stack (start-address=0x7df669600000 size=128 GiB) +KLEE: WARNING: undefined reference to function: close +KLEE: WARNING: undefined reference to function: fcntl +KLEE: WARNING: undefined reference to function: fstat +KLEE: WARNING: undefined reference to function: ioctl +KLEE: WARNING: undefined reference to function: lseek64 +KLEE: WARNING: undefined reference to function: open +KLEE: WARNING: undefined reference to function: write +KLEE: WARNING ONCE: calling external: ioctl(0, 21505, 138542380482560) at libc/termios/tcgetattr.c:43 12 +KLEE: WARNING ONCE: calling __user_main with extra arguments. +KLEE: WARNING ONCE: calling __map2check_main__ with extra arguments. +KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8. +KLEE: WARNING ONCE: Alignment of memory from call "realloc" is not modelled. Using alignment of 8. +KLEE: NOTE: found huge malloc, returning 0 +KLEE: ERROR: 10a8cc7f8ad88ce445fb123804a07fc4ee780c31.map2check-preprocessed.c:127: concretized symbolic size +KLEE: NOTE: now ignoring this error at this location +KLEE: WARNING ONCE: calling external: open(139738663092224, 577, 438) at libc/stdio/_fopen.c:146 8 +KLEE: WARNING ONCE: calling external: write(12, 139499889754112, 8) at libc/stdio/_WRITE.c:52 11 +KLEE: WARNING ONCE: calling external: close(12) at libc/stdio/fclose.c:56 22 +KLEE: NOTE: found huge malloc, returning 0 +KLEE: ERROR: 10a8cc7f8ad88ce445fb123804a07fc4ee780c31.map2check-preprocessed.c:128: concretized symbolic size +KLEE: NOTE: now ignoring this error at this location +KLEE: WARNING ONCE: silently concretizing (reason: external call) expression (Extract w8 0 (Add w32 48 + (URem w32 (Extract w32 0 (Sub w64 0 + (SExt w64 (ReadLSB w32 0 non_det_ulong)))) + 10))) to value 51 (libc/stdio/_WRITE.c:52) +KLEE: ERROR: (location information missing) abort failure +KLEE: NOTE: now ignoring this error at this location +KLEE: halting execution, dumping remaining states + +KLEE: done: total instructions = 4630430 +KLEE: done: completed paths = 0 +KLEE: done: partially completed paths = 115 +KLEE: done: generated tests = 115 +Exited klee with 0 +Started counter example generation +Counter-example: + +State 0: file /src/tests/regression_test/test_cases/sv-benchmarks/array-examples/relax-1.c +------------------------------------------------------------ +>Symbolic log + Value : -3 + Line Number : 125 + Function Scope : main + +State 1: file /src/tests/regression_test/test_cases/sv-benchmarks/array-examples/relax-1.c +------------------------------------------------------------ +>Symbolic log + Value : -2 + Line Number : 125 + Function Scope : main + +---------------------------------------------------- +Violated property: + file map2check_property line 108 function is_relaxed_prefix + FALSE-DEREF: Reference to pointer was lost + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-succeeded-stdout.txt b/scripts/cutover/fixtures/c-succeeded-stdout.txt new file mode 100644 index 000000000..8dde1fb20 --- /dev/null +++ b/scripts/cutover/fixtures/c-succeeded-stdout.txt @@ -0,0 +1,42 @@ +Adopting z3 solver... +Adopting symex nondet-generator... +Started Map2Check +Compiling /src/tests/regression_test/test_cases/sv-benchmarks/ldv-memsafety/memsetNonZero.c +Adding nondet pass +Adding memtrack pass +Adding map2check pass +Linking with map2check library +Applying optimizations for klee +Executing Klee with map2check +Solver backend caller: z3 +KLEE: NOTE: Using klee-uclibc : /src/release/lib/klee/runtime/klee-uclibc.bca +KLEE: output directory is "/tmp/tmp.gxPGwExe72/053e01a2cec6b58c9d93ee902fbde2c977d3366f.map2check/./klee-out-0" +KLEE: Using Z3 solver backend +KLEE: Deterministic allocator: Using quarantine queue size 8 +KLEE: Deterministic allocator: globals (start-address=0x7fceaa000000 size=10 GiB) +KLEE: Deterministic allocator: constants (start-address=0x7fcc2a000000 size=10 GiB) +KLEE: Deterministic allocator: heap (start-address=0x7ecc2a000000 size=1024 GiB) +KLEE: Deterministic allocator: stack (start-address=0x7eac2a000000 size=128 GiB) +KLEE: WARNING: undefined reference to function: close +KLEE: WARNING: undefined reference to function: fcntl +KLEE: WARNING: undefined reference to function: fstat +KLEE: WARNING: undefined reference to function: ioctl +KLEE: WARNING: undefined reference to function: lseek64 +KLEE: WARNING: undefined reference to function: open +KLEE: WARNING: undefined reference to function: write +KLEE: WARNING ONCE: calling external: ioctl(0, 21505, 139323001274368) at libc/termios/tcgetattr.c:43 12 +KLEE: WARNING ONCE: calling __user_main with extra arguments. +KLEE: WARNING ONCE: calling __map2check_main__ with extra arguments. +KLEE: WARNING ONCE: Alignment of memory from call "malloc" is not modelled. Using alignment of 8. +KLEE: WARNING ONCE: Alignment of memory from call "realloc" is not modelled. Using alignment of 8. +KLEE: WARNING ONCE: calling external: open(140519686537216, 577, 438) at libc/stdio/_fopen.c:146 8 +KLEE: WARNING ONCE: calling external: write(12, 140239976792064, 5) at libc/stdio/_WRITE.c:52 11 +KLEE: WARNING ONCE: calling external: close(12) at libc/stdio/fclose.c:56 22 + +KLEE: done: total instructions = 91449 +KLEE: done: completed paths = 1 +KLEE: done: partially completed paths = 0 +KLEE: done: generated tests = 1 +Exited klee with 0 + +VERIFICATION SUCCEEDED diff --git a/scripts/cutover/run-corpus.sh b/scripts/cutover/run-corpus.sh index c0c7b7131..287b5c548 100755 --- a/scripts/cutover/run-corpus.sh +++ b/scripts/cutover/run-corpus.sh @@ -6,7 +6,7 @@ set -euo pipefail BIN_DIR="$(cd "$1" && pwd)"; OUT="$2" ROOT="$(cd "$(dirname "$0")/../.." && pwd)" CASES="${CASES:-$ROOT/tests/regression_test/test_cases/sv-benchmarks}" -GENS="${GENS:-fuzzer symex}"; REPS="${REPS:-5}"; TIMEOUT="${TIMEOUT:-45}" +GENS="${GENS:-afl symex}"; REPS="${REPS:-5}"; TIMEOUT="${TIMEOUT:-45}" flags_for() { case "$1" in @@ -29,7 +29,7 @@ while IFS= read -r yml; do work="$(mktemp -d)" # shellcheck disable=SC2086 ( cd "$work" && /usr/bin/time -f '%e\t%M' -o time.txt \ - timeout "$TIMEOUT" "$BIN_DIR/map2check" --nondet-generator "$gen" $flags "$input" \ + timeout "$((TIMEOUT + 15))" "$BIN_DIR/map2check" --timeout "$TIMEOUT" --nondet-generator "$gen" $flags "$input" \ > out.txt 2>&1 ) || true verdict=TIMEOUT grep -q 'VERIFICATION SUCCEEDED' "$work/out.txt" && verdict=SUCCEEDED @@ -37,11 +37,33 @@ while IFS= read -r yml; do grep -q 'VERIFICATION UNKNOWN' "$work/out.txt" && verdict=UNKNOWN tag=-; line=-; func=- if [ -f "$work/map2check_property" ]; then + # Rust runtime: the property file is left in the cwd. tag="$(sed -n 1p "$work/map2check_property")" line="$(sed -nE 's/^Line: *//p' "$work/map2check_property" | head -1)"; line="${line:--}" func="$(sed -nE 's/^Function: *//p' "$work/map2check_property" | head -1)"; func="${func:--}" + elif [ "$verdict" = FAILED ]; then + # C runtime: the property file lives in a scratch dir that is deleted, so + # parse stdout (modules/frontend/counter_example/counter_example.hpp): + # Violated property: + # file map2check_property line N function F (absent for MEMTRACK/MEMCLEANUP) + # FALSE-DEREF: Reference to pointer was lost | FALSE-FREE: ... | OVERFLOW | + # FALSE: Target Reached | FALSE-ASSERT | FALSE-MEMTRACK | FALSE-MEMCLEANUP + clean="$(sed -E 's/\x1b\[[0-9;]*m//g' "$work/out.txt")" + viol="$(printf '%s\n' "$clean" | sed -n '/^Violated property:/,/^VERIFICATION/p')" + loc="$(printf '%s\n' "$viol" | sed -nE 's/^[[:space:]]*file .* line ([0-9]+) function (.*)$/\1 \2/p' | head -1)" + [ -n "$loc" ] && { line="${loc%% *}"; func="${loc#* }"; func="${func:--}"; } + case "$viol" in + *FALSE-DEREF*) tag=FALSE-DEREF ;; + *FALSE-FREE*) tag=FALSE-FREE ;; + *FALSE-MEMTRACK*) tag=FALSE-MEMTRACK ;; + *FALSE-MEMCLEANUP*) tag=FALSE-MEMCLEANUP ;; + *FALSE-ASSERT*) tag=ASSERT ;; + *"FALSE: Target Reached"*) tag=TARGET-REACHED ;; + *OVERFLOW*) tag=OVERFLOW ;; + esac fi witness=0; ls "$work"/*.graphml "$work"/map2check_checked_error >/dev/null 2>&1 && witness=1 + grep -qE 'Generating witness|\.graphml' "$work/out.txt" && witness=1 timing="$(tail -1 "$work/time.txt" 2>/dev/null || printf -- '-\t-')" printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \ "${yml#"$CASES"/}" "$prp" "$gen" "$rep" "$verdict" "$tag" "$line" "$func" "$witness" "$timing" >> "$OUT" diff --git a/scripts/cutover/test-run-corpus.sh b/scripts/cutover/test-run-corpus.sh index 4c6a5aeb8..2d7ed066c 100755 --- a/scripts/cutover/test-run-corpus.sh +++ b/scripts/cutover/test-run-corpus.sh @@ -24,4 +24,26 @@ IFS=$'\t' read -r task prp gen rep verdict tag line func witness wall rss <<<"$r [ "$task" = "x/a.yml" ] && [ "$prp" = "valid-memsafety" ] && [ "$gen" = fuzzer ] \ && [ "$verdict" = FAILED ] && [ "$tag" = FALSE-DEREF ] && [ "$line" = 7 ] \ && [ "$func" = main ] && [ "$witness" = 0 ] || { echo "linha inesperada: $row" >&2; exit 1; } + +# Runtime C: sem map2check_property no cwd; tag/linha/função vêm do stdout. +FIX="$HERE/fixtures" +mkdir -p "$T/cbin" +cat > "$T/cbin/map2check" <&2; exit 1; } +cat > "$T/cbin/map2check" <&2; exit 1; } echo ok diff --git a/tests/cutover/README.md b/tests/cutover/README.md index 5e4384311..8c14341c7 100644 --- a/tests/cutover/README.md +++ b/tests/cutover/README.md @@ -22,21 +22,22 @@ docker run --rm -u root -v "$PWD":/src -w /src map2check-dev:latest bash -c ' mkdir -p release/lib/klee && ln -sfn /opt/klee/lib/klee/runtime release/lib/klee/runtime && ln -sfn /usr/lib/llvm-16/lib/clang release/lib/clang && - GENS="symex" REPS=5 TIMEOUT=45 MAP2CHECK_PATH=/src/release \ + GENS="afl symex" REPS=5 TIMEOUT=45 MAP2CHECK_PATH=/src/release \ scripts/cutover/run-corpus.sh release tests/cutover/baseline-c.tsv' ``` Runner self-test: `bash scripts/cutover/test-run-corpus.sh`. -## Known issues found during the smoke run (read before running the full baseline) +## Notes on the C runtime (found in the smoke run) - The runner argument is `release` (the dir holding the `map2check` wrapper), not `release/bin`. -- The C binary has no `fuzzer` generator; valid values are `afl` and `symex`. `GENS=fuzzer` - gives "Selected generator don't exist" (runner records TIMEOUT). `afl` needs - `/usr/local/bin/afl-clang-fast`, absent from this image (runner records UNKNOWN). - Only `symex` works in `map2check-dev:latest`, so the command above uses `GENS="symex"`. -- The C pipeline chdirs into a scratch dir and removes it, so `map2check_property` is never - left in the runner's cwd: tag/line/function columns are `-` for C. They are printed on stdout - ("Violated property: file ... line N function F" then "TAG: ...") if Task 4.1 needs them. -- Smoke (symex, REPS=1): 11 FAILED, 4 SUCCEEDED, 26 UNKNOWN (41 rows, ~1 s each; KLEE - "Forcing timeout" yields UNKNOWN). +- Valid generators are `afl` and `symex` (no `fuzzer`). `afl` needs `/usr/local/bin/afl-clang-fast`, + absent from `map2check-dev:latest`; a rebuilt image (`map2check-dev:cutover-f01e8c3e`) adds AFL++. + With the old image only `GENS=symex` works (afl rows come out UNKNOWN in 0.08 s). +- The C pipeline deletes its scratch dir, so `map2check_property` is not left in cwd. The runner + derives tag/line/function from stdout (fixtures in `scripts/cutover/fixtures/`); FALSE-MEMTRACK + and FALSE-MEMCLEANUP carry no line/function (`-`). Witness is 1 only if `--generate-witness` + output is seen (the runner does not pass it). +- The runner passes `--timeout $TIMEOUT` to map2check (default is 0 = unlimited-ish and caused + premature "Forcing timeout" UNKNOWNs); the outer `timeout` is TIMEOUT+15. +- Smoke (symex, REPS=1, 41 rows): 13 FAILED, 8 SUCCEEDED, 20 UNKNOWN. From 33b41e81dc55cd0b8e48bfe9e26efdf55c2c35fd Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Thu, 15 Oct 2026 19:29:36 -0400 Subject: [PATCH 03/44] test: normalise corpus runner tags across C and Rust paths and cover every tag --- .../cutover/fixtures/c-assert-synthetic.txt | 5 ++ .../fixtures/c-false-divbyzero-synthetic.txt | 5 ++ .../fixtures/c-false-free-synthetic.txt | 5 ++ .../fixtures/c-false-memcleanup-synthetic.txt | 4 + .../fixtures/c-false-memtrack-synthetic.txt | 4 + .../cutover/fixtures/c-overflow-synthetic.txt | 5 ++ .../fixtures/c-target-reached-synthetic.txt | 5 ++ .../cutover/fixtures/c-unmapped-synthetic.txt | 5 ++ scripts/cutover/run-corpus.sh | 71 +++++++++------ scripts/cutover/test-run-corpus.sh | 88 +++++++++++++++---- 10 files changed, 156 insertions(+), 41 deletions(-) create mode 100644 scripts/cutover/fixtures/c-assert-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-false-divbyzero-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-false-free-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-false-memcleanup-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-false-memtrack-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-overflow-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-target-reached-synthetic.txt create mode 100644 scripts/cutover/fixtures/c-unmapped-synthetic.txt diff --git a/scripts/cutover/fixtures/c-assert-synthetic.txt b/scripts/cutover/fixtures/c-assert-synthetic.txt new file mode 100644 index 000000000..71a2801ac --- /dev/null +++ b/scripts/cutover/fixtures/c-assert-synthetic.txt @@ -0,0 +1,5 @@ +Violated property: + file map2check_property line 42 function foo + FALSE-ASSERT + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-false-divbyzero-synthetic.txt b/scripts/cutover/fixtures/c-false-divbyzero-synthetic.txt new file mode 100644 index 000000000..15796abfb --- /dev/null +++ b/scripts/cutover/fixtures/c-false-divbyzero-synthetic.txt @@ -0,0 +1,5 @@ +Violated property: + file map2check_property line 42 function foo + FALSE-DIVBYZERO + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-false-free-synthetic.txt b/scripts/cutover/fixtures/c-false-free-synthetic.txt new file mode 100644 index 000000000..298f2d9ed --- /dev/null +++ b/scripts/cutover/fixtures/c-false-free-synthetic.txt @@ -0,0 +1,5 @@ +Violated property: + file map2check_property line 42 function foo + FALSE-FREE: Operand of free must have zero pointer offset + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-false-memcleanup-synthetic.txt b/scripts/cutover/fixtures/c-false-memcleanup-synthetic.txt new file mode 100644 index 000000000..c747b1bc9 --- /dev/null +++ b/scripts/cutover/fixtures/c-false-memcleanup-synthetic.txt @@ -0,0 +1,4 @@ +Violated property: + FALSE-MEMCLEANUP + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-false-memtrack-synthetic.txt b/scripts/cutover/fixtures/c-false-memtrack-synthetic.txt new file mode 100644 index 000000000..7d6d01d5c --- /dev/null +++ b/scripts/cutover/fixtures/c-false-memtrack-synthetic.txt @@ -0,0 +1,4 @@ +Violated property: + FALSE-MEMTRACK + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-overflow-synthetic.txt b/scripts/cutover/fixtures/c-overflow-synthetic.txt new file mode 100644 index 000000000..b2a79b23e --- /dev/null +++ b/scripts/cutover/fixtures/c-overflow-synthetic.txt @@ -0,0 +1,5 @@ +Violated property: + file map2check_property line 42 function foo + OVERFLOW + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-target-reached-synthetic.txt b/scripts/cutover/fixtures/c-target-reached-synthetic.txt new file mode 100644 index 000000000..f0623bafc --- /dev/null +++ b/scripts/cutover/fixtures/c-target-reached-synthetic.txt @@ -0,0 +1,5 @@ +Violated property: + file map2check_property line 42 function foo + FALSE: Target Reached + +VERIFICATION FAILED diff --git a/scripts/cutover/fixtures/c-unmapped-synthetic.txt b/scripts/cutover/fixtures/c-unmapped-synthetic.txt new file mode 100644 index 000000000..1e580de3c --- /dev/null +++ b/scripts/cutover/fixtures/c-unmapped-synthetic.txt @@ -0,0 +1,5 @@ +Violated property: + file map2check_property line 42 function foo + FALSE-SOMETHING-NEW + +VERIFICATION FAILED diff --git a/scripts/cutover/run-corpus.sh b/scripts/cutover/run-corpus.sh index 287b5c548..487db1e75 100755 --- a/scripts/cutover/run-corpus.sh +++ b/scripts/cutover/run-corpus.sh @@ -36,35 +36,56 @@ while IFS= read -r yml; do grep -q 'VERIFICATION FAILED' "$work/out.txt" && verdict=FAILED grep -q 'VERIFICATION UNKNOWN' "$work/out.txt" && verdict=UNKNOWN tag=-; line=-; func=- - if [ -f "$work/map2check_property" ]; then - # Rust runtime: the property file is left in the cwd. - tag="$(sed -n 1p "$work/map2check_property")" - line="$(sed -nE 's/^Line: *//p' "$work/map2check_property" | head -1)"; line="${line:--}" - func="$(sed -nE 's/^Function: *//p' "$work/map2check_property" | head -1)"; func="${func:--}" - elif [ "$verdict" = FAILED ]; then - # C runtime: the property file lives in a scratch dir that is deleted, so - # parse stdout (modules/frontend/counter_example/counter_example.hpp): - # Violated property: - # file map2check_property line N function F (absent for MEMTRACK/MEMCLEANUP) - # FALSE-DEREF: Reference to pointer was lost | FALSE-FREE: ... | OVERFLOW | - # FALSE: Target Reached | FALSE-ASSERT | FALSE-MEMTRACK | FALSE-MEMCLEANUP - clean="$(sed -E 's/\x1b\[[0-9;]*m//g' "$work/out.txt")" - viol="$(printf '%s\n' "$clean" | sed -n '/^Violated property:/,/^VERIFICATION/p')" - loc="$(printf '%s\n' "$viol" | sed -nE 's/^[[:space:]]*file .* line ([0-9]+) function (.*)$/\1 \2/p' | head -1)" - [ -n "$loc" ] && { line="${loc%% *}"; func="${loc#* }"; func="${func:--}"; } - case "$viol" in - *FALSE-DEREF*) tag=FALSE-DEREF ;; - *FALSE-FREE*) tag=FALSE-FREE ;; - *FALSE-MEMTRACK*) tag=FALSE-MEMTRACK ;; - *FALSE-MEMCLEANUP*) tag=FALSE-MEMCLEANUP ;; - *FALSE-ASSERT*) tag=ASSERT ;; - *"FALSE: Target Reached"*) tag=TARGET-REACHED ;; - *OVERFLOW*) tag=OVERFLOW ;; + # tag/line/function are only meaningful for a FAILED verdict; every other + # verdict gets "-" whichever source (property file or stdout) was used. + if [ "$verdict" = FAILED ]; then + raw= + ptag=; [ -f "$work/map2check_property" ] && ptag="$(sed -n 1p "$work/map2check_property")" + case "$ptag" in + ""|NONE|UNKNOWN) ptag= ;; esac + if [ -n "$ptag" ]; then + # Rust runtime: the property file is left in the cwd. + tag="$ptag" + line="$(sed -nE 's/^Line: *//p' "$work/map2check_property" | head -1)"; line="${line:--}" + func="$(sed -nE 's/^Function: *//p' "$work/map2check_property" | head -1)"; func="${func:--}" + elif [ -f "$work/map2check_property_memtrack" ]; then + # Same precedence as the frontend (modules/frontend/utils/tools.cpp:198-207): + # map2check_property_memtrack is checked before map2check_property_memcleanup. + tag=FALSE-MEMTRACK + elif [ -f "$work/map2check_property_memcleanup" ]; then + tag=FALSE-MEMCLEANUP + else + # C runtime: the property file lives in a scratch dir that is deleted, so + # parse stdout (modules/frontend/counter_example/counter_example.hpp:115-170): + # Violated property: + # file map2check_property line N function F (absent for MEMTRACK/MEMCLEANUP) + # FALSE-DEREF: Reference to pointer was lost | FALSE-FREE: ... | OVERFLOW | + # FALSE: Target Reached | FALSE-ASSERT | FALSE-MEMTRACK | FALSE-MEMCLEANUP | + # FALSE-DIVBYZERO (lines 152-157) + clean="$(sed -E 's/\x1b\[[0-9;]*m//g' "$work/out.txt")" + viol="$(printf '%s\n' "$clean" | sed -n '/^Violated property:/,/^VERIFICATION/p')" + loc="$(printf '%s\n' "$viol" | sed -nE 's/^[[:space:]]*file .* line ([0-9]+) function (.*)$/\1 \2/p' | head -1)" + [ -n "$loc" ] && { line="${loc%% *}"; func="${loc#* }"; func="${func:--}"; } + case "$viol" in + *FALSE-DEREF*) tag=FALSE-DEREF ;; + *FALSE-FREE*) tag=FALSE-FREE ;; + *FALSE-MEMTRACK*) tag=FALSE-MEMTRACK ;; + *FALSE-MEMCLEANUP*) tag=FALSE-MEMCLEANUP ;; + *FALSE-DIVBYZERO*) tag=FALSE-DIVBYZERO ;; + *FALSE-ASSERT*) tag=ASSERT ;; + *"FALSE: Target Reached"*) tag=TARGET-REACHED ;; + *OVERFLOW*) tag=OVERFLOW ;; + *) tag=UNMAPPED + raw="$(printf '%s' "$viol" | tr '\n\t' ' ')" + echo "run-corpus: UNMAPPED property for ${yml#"$CASES"/} ($prp, $gen): $raw" >&2 ;; + esac + fi fi witness=0; ls "$work"/*.graphml "$work"/map2check_checked_error >/dev/null 2>&1 && witness=1 grep -qE 'Generating witness|\.graphml' "$work/out.txt" && witness=1 - timing="$(tail -1 "$work/time.txt" 2>/dev/null || printf -- '-\t-')" + timing="$(tail -1 "$work/time.txt" 2>/dev/null || true)" + case "$timing" in *$'\t'*) ;; *) timing=$'-\t-' ;; esac printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \ "${yml#"$CASES"/}" "$prp" "$gen" "$rep" "$verdict" "$tag" "$line" "$func" "$witness" "$timing" >> "$OUT" rm -rf "$work" diff --git a/scripts/cutover/test-run-corpus.sh b/scripts/cutover/test-run-corpus.sh index 2d7ed066c..7946b0c87 100755 --- a/scripts/cutover/test-run-corpus.sh +++ b/scripts/cutover/test-run-corpus.sh @@ -1,5 +1,11 @@ #!/usr/bin/env bash # Testa run-corpus.sh com um binário falso e um corpus de uma tarefa. +# Os fixtures *-synthetic.txt espelham o formato exato impresso por +# modules/frontend/counter_example/counter_example.hpp: FALSE-FREE (l.115-123), +# TARGET-REACHED (l.124-133), OVERFLOW (l.143-150), FALSE-DIVBYZERO (l.152-159), +# FALSE-MEMTRACK/MEMCLEANUP (l.160-171, sem linha "file ... line ... function"), +# ASSERT (l.172-181). c-unmapped inventa uma tag desconhecida. c-failed/c-succeeded +# sao stdout capturado de uma execucao real do runtime C. set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT @@ -18,32 +24,82 @@ properties: - property_file: ../properties/valid-memsafety.prp expected_verdict: false EOS -CASES="$T/cases" GENS=fuzzer REPS=1 "$HERE/run-corpus.sh" "$T/bin" "$T/out.tsv" +CASES="$T/cases" GENS=afl REPS=1 "$HERE/run-corpus.sh" "$T/bin" "$T/out.tsv" row="$(sed -n 2p "$T/out.tsv")" IFS=$'\t' read -r task prp gen rep verdict tag line func witness wall rss <<<"$row" -[ "$task" = "x/a.yml" ] && [ "$prp" = "valid-memsafety" ] && [ "$gen" = fuzzer ] \ +[ "$task" = "x/a.yml" ] && [ "$prp" = "valid-memsafety" ] && [ "$gen" = afl ] \ && [ "$verdict" = FAILED ] && [ "$tag" = FALSE-DEREF ] && [ "$line" = 7 ] \ && [ "$func" = main ] && [ "$witness" = 0 ] || { echo "linha inesperada: $row" >&2; exit 1; } -# Runtime C: sem map2check_property no cwd; tag/linha/função vêm do stdout. + FIX="$HERE/fixtures" mkdir -p "$T/cbin" -cat > "$T/cbin/map2check" < "$T/cbin/map2check" <<'EOS' #!/usr/bin/env bash -cat "$FIX/c-failed-stdout.txt" +cat "$FIXTURE" EOS chmod +x "$T/cbin/map2check" -CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/c.tsv" -IFS=$'\t' read -r task prp gen rep verdict tag line func witness wall rss <<<"$(sed -n 2p "$T/c.tsv")" -[ "$verdict" = FAILED ] && [ "$tag" = FALSE-DEREF ] && [ "$line" = 108 ] \ - && [ "$func" = is_relaxed_prefix ] && [ "$witness" = 0 ] \ - || { echo "linha C inesperada: $verdict $tag $line $func $witness" >&2; exit 1; } -cat > "$T/cbin/map2check" < "$T/cases/x/b.yml" <<'EOS' +format_version: '1.0' +input_files: 'b.c' +properties: + - property_file: ../properties/valid-memsafety.prp + expected_verdict: false +EOS + +# fixture | verdict | tag | line | function (caminho C: so stdout) +while IFS='|' read -r fx exp_verdict exp_tag exp_line exp_func; do + FIXTURE="$FIX/$fx" CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/c.tsv" 2>"$T/err" + row="$(sed -n 2p "$T/c.tsv")" + [ "$(awk -F'\t' '{print NF}' <<<"$row")" = 11 ] || { echo "colunas != 11: $row" >&2; exit 1; } + IFS=$'\t' read -r task prp gen rep verdict tag line func witness wall rss <<<"$row" + [ "$verdict" = "$exp_verdict" ] && [ "$tag" = "$exp_tag" ] && [ "$line" = "$exp_line" ] \ + && [ "$func" = "$exp_func" ] && [ "$witness" = 0 ] \ + || { echo "$fx inesperado: $verdict $tag $line $func $witness" >&2; exit 1; } + if [ "$exp_tag" = UNMAPPED ]; then grep -q 'UNMAPPED.*FALSE-SOMETHING-NEW' "$T/err" || { echo "sem aviso UNMAPPED" >&2; exit 1; }; fi +done <<'EOS' +c-failed-stdout.txt|FAILED|FALSE-DEREF|108|is_relaxed_prefix +c-succeeded-stdout.txt|SUCCEEDED|-|-|- +c-false-free-synthetic.txt|FAILED|FALSE-FREE|42|foo +c-false-memtrack-synthetic.txt|FAILED|FALSE-MEMTRACK|-|- +c-false-memcleanup-synthetic.txt|FAILED|FALSE-MEMCLEANUP|-|- +c-overflow-synthetic.txt|FAILED|OVERFLOW|42|foo +c-assert-synthetic.txt|FAILED|ASSERT|42|foo +c-target-reached-synthetic.txt|FAILED|TARGET-REACHED|42|foo +c-false-divbyzero-synthetic.txt|FAILED|FALSE-DIVBYZERO|42|foo +c-unmapped-synthetic.txt|FAILED|UNMAPPED|42|foo +EOS + +# Caminho Rust: arquivos de propriedade no cwd. spec: nome-do-arquivo|conteudo (\n) | tag | line | func +V="VERIFICATION FAILED" +mkrust() { # $1 = shell snippet que cria arquivos + cat > "$T/cbin/map2check" <&2; exit 1; } +} +check_rust() { # desc exp_verdict exp_tag exp_line exp_func + CASES="$T/cases" GENS=afl REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/r.tsv" + IFS=$'\t' read -r task prp gen rep verdict tag line func witness wall rss <<<"$(sed -n 2p "$T/r.tsv")" + [ "$verdict" = "$2" ] && [ "$tag" = "$3" ] && [ "$line" = "$4" ] && [ "$func" = "$5" ] \ + || { echo "Rust '$1' inesperado: $verdict $tag $line $func" >&2; exit 1; } +} +V="VERIFICATION SUCCEEDED" +mkrust "printf 'NONE\n' > map2check_property" +check_rust "NONE em SUCCEEDED" SUCCEEDED - - - +V="VERIFICATION FAILED" +mkrust "printf 'FALSE-MEMTRACK\n' > map2check_property_memtrack" +check_rust "so memtrack" FAILED FALSE-MEMTRACK - - +mkrust "printf 'x\n' > map2check_property_memcleanup" +check_rust "so memcleanup" FAILED FALSE-MEMCLEANUP - - +cat > "$T/cbin/map2check" <<'EOS' +#!/usr/bin/env bash +printf 'OVERFLOW\nLine: 3\nFunction: f\n' > map2check_property +echo "VERIFICATION UNKNOWN" +EOS +check_rust "violacao com veredito UNKNOWN" UNKNOWN - - - + echo ok From b3c10cb7050441dcdd99b2091da6d0b166e1065a Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Thu, 15 Oct 2026 20:39:42 -0400 Subject: [PATCH 04/44] test: add C runtime baseline for the Rust runtime cutover --- tests/cutover/README.md | 9 + tests/cutover/baseline-c.tsv | 411 +++++++++++++++++++++++++++++++++++ 2 files changed, 420 insertions(+) create mode 100644 tests/cutover/baseline-c.tsv diff --git a/tests/cutover/README.md b/tests/cutover/README.md index 8c14341c7..6df467e73 100644 --- a/tests/cutover/README.md +++ b/tests/cutover/README.md @@ -41,3 +41,12 @@ Runner self-test: `bash scripts/cutover/test-run-corpus.sh`. - The runner passes `--timeout $TIMEOUT` to map2check (default is 0 = unlimited-ish and caused premature "Forcing timeout" UNKNOWNs); the outer `timeout` is TIMEOUT+15. - Smoke (symex, REPS=1, 41 rows): 13 FAILED, 8 SUCCEEDED, 20 UNKNOWN. + +## Baseline completa do runtime C (`baseline-c.tsv`) + +- Gerada em 2026-10-15 sobre `develop` `f01e8c3e` com `GENS="afl symex" REPS=5 TIMEOUT=45`. +- Imagem: `map2check-dev:cutover-f01e8c3e` (`sha256:0e5ba2669491ccf6e762d8c25af9218ffc71e53e769700fc435d21b8bf92280d`), reconstruída do `Dockerfile.dev` de `develop` (contém AFL++ 4.40c). Pacote `time` instalado em tempo de execução. Build em `build-afl/`, instalação em `release-afl/` (`MAP2CHECK_PATH=/src/release-afl`). +- 410 linhas (41 tarefas×propriedade × 2 geradores × 5 repetições), todas com 11 colunas. +- Vereditos: `afl` 55 FAILED / 150 UNKNOWN; `symex` 65 FAILED / 40 SUCCEEDED / 100 UNKNOWN. O AFL++ não prova TRUE: nenhum SUCCEEDED com `afl` é esperado. +- Tags: 40 FALSE-DEREF, 40 FALSE-FREE, 20 FALSE-MEMTRACK, 20 TARGET-REACHED; nenhuma UNMAPPED. +- Esta baseline é a referência de estado conhecido do C. O gate da Task 4.2 a regenera no merge-base da branch de migração. diff --git a/tests/cutover/baseline-c.tsv b/tests/cutover/baseline-c.tsv new file mode 100644 index 000000000..f4824abed --- /dev/null +++ b/tests/cutover/baseline-c.tsv @@ -0,0 +1,411 @@ +task prp gen rep verdict tag line function witness wall_s maxrss_kb +array-examples/relax-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.57 94004 +array-examples/relax-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.57 94396 +array-examples/relax-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.59 94712 +array-examples/relax-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.60 94272 +array-examples/relax-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.58 94384 +array-examples/relax-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.53 179192 +array-examples/relax-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.22 179916 +array-examples/relax-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.44 179808 +array-examples/relax-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.01 172368 +array-examples/relax-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.20 170552 +array-examples/standard_sentinel-2.yml unreach-call afl 1 UNKNOWN - - - 0 9.80 12826256 +array-examples/standard_sentinel-2.yml unreach-call afl 2 UNKNOWN - - - 0 10.03 12978816 +array-examples/standard_sentinel-2.yml unreach-call afl 3 UNKNOWN - - - 0 9.78 13267136 +array-examples/standard_sentinel-2.yml unreach-call afl 4 UNKNOWN - - - 0 9.78 12790856 +array-examples/standard_sentinel-2.yml unreach-call afl 5 UNKNOWN - - - 0 9.79 13080608 +array-examples/standard_sentinel-2.yml unreach-call symex 1 UNKNOWN - - - 0 31.40 161520 +array-examples/standard_sentinel-2.yml unreach-call symex 2 UNKNOWN - - - 0 31.38 162184 +array-examples/standard_sentinel-2.yml unreach-call symex 3 UNKNOWN - - - 0 31.39 161608 +array-examples/standard_sentinel-2.yml unreach-call symex 4 UNKNOWN - - - 0 31.38 166240 +array-examples/standard_sentinel-2.yml unreach-call symex 5 UNKNOWN - - - 0 31.39 165124 +array-examples/standard_two_index_04.yml unreach-call afl 1 UNKNOWN - - - 0 9.75 12787264 +array-examples/standard_two_index_04.yml unreach-call afl 2 UNKNOWN - - - 0 9.98 11925820 +array-examples/standard_two_index_04.yml unreach-call afl 3 UNKNOWN - - - 0 9.77 12409084 +array-examples/standard_two_index_04.yml unreach-call afl 4 UNKNOWN - - - 0 9.77 12805344 +array-examples/standard_two_index_04.yml unreach-call afl 5 UNKNOWN - - - 0 9.77 12787428 +array-examples/standard_two_index_04.yml unreach-call symex 1 UNKNOWN - - - 0 31.39 168068 +array-examples/standard_two_index_04.yml unreach-call symex 2 UNKNOWN - - - 0 31.37 171948 +array-examples/standard_two_index_04.yml unreach-call symex 3 UNKNOWN - - - 0 31.37 175372 +array-examples/standard_two_index_04.yml unreach-call symex 4 UNKNOWN - - - 0 31.38 176060 +array-examples/standard_two_index_04.yml unreach-call symex 5 UNKNOWN - - - 0 31.38 168992 +array-examples/standard_two_index_05.yml unreach-call afl 1 UNKNOWN - - - 0 9.77 12779032 +array-examples/standard_two_index_05.yml unreach-call afl 2 UNKNOWN - - - 0 9.76 12771116 +array-examples/standard_two_index_05.yml unreach-call afl 3 UNKNOWN - - - 0 9.77 12796900 +array-examples/standard_two_index_05.yml unreach-call afl 4 UNKNOWN - - - 0 9.78 12867308 +array-examples/standard_two_index_05.yml unreach-call afl 5 UNKNOWN - - - 0 9.77 12954076 +array-examples/standard_two_index_05.yml unreach-call symex 1 UNKNOWN - - - 0 31.39 168888 +array-examples/standard_two_index_05.yml unreach-call symex 2 UNKNOWN - - - 0 31.40 168636 +array-examples/standard_two_index_05.yml unreach-call symex 3 UNKNOWN - - - 0 31.39 171820 +array-examples/standard_two_index_05.yml unreach-call symex 4 UNKNOWN - - - 0 31.39 176112 +array-examples/standard_two_index_05.yml unreach-call symex 5 UNKNOWN - - - 0 31.38 168096 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.59 92856 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.56 93864 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.54 92584 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.55 92540 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.57 93932 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 1 FAILED FALSE-DEREF 522 main 0 5.28 169384 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 2 FAILED FALSE-DEREF 522 main 0 5.35 169064 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 3 FAILED FALSE-DEREF 522 main 0 5.51 168864 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 4 FAILED FALSE-DEREF 522 main 0 5.36 168600 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 5 FAILED FALSE-DEREF 522 main 0 5.33 169072 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.45 93052 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.44 93784 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.44 93208 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 93404 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.43 92916 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.44 169196 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.42 169288 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.43 168900 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.49 165840 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.43 169556 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.79 93804 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.83 93856 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.78 93156 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.79 93264 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.85 93260 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.49 144292 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.47 144372 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.43 144224 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.40 143940 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.42 143548 +array-memsafety/lis_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.46 93948 +array-memsafety/lis_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.45 93036 +array-memsafety/lis_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 93236 +array-memsafety/lis_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.44 94052 +array-memsafety/lis_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.44 93228 +array-memsafety/lis_unsafe.yml valid-memsafety symex 1 UNKNOWN - - - 0 3.67 169700 +array-memsafety/lis_unsafe.yml valid-memsafety symex 2 UNKNOWN - - - 0 3.69 170300 +array-memsafety/lis_unsafe.yml valid-memsafety symex 3 UNKNOWN - - - 0 3.63 170284 +array-memsafety/lis_unsafe.yml valid-memsafety symex 4 UNKNOWN - - - 0 3.73 170240 +array-memsafety/lis_unsafe.yml valid-memsafety symex 5 UNKNOWN - - - 0 3.89 168000 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.42 93692 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 341132 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 341152 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.59 341424 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.42 92568 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.41 127480 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.41 127864 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.41 127168 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 0.40 127432 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 0.40 127176 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 1 FAILED FALSE-FREE 46 main 0 0.57 92848 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 2 FAILED FALSE-FREE 46 main 0 0.56 93204 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 3 FAILED FALSE-FREE 46 main 0 0.55 92796 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 4 FAILED FALSE-FREE 46 main 0 0.56 93632 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 5 FAILED FALSE-FREE 46 main 0 0.68 93140 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 1 FAILED FALSE-FREE 46 main 0 0.53 127676 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 2 FAILED FALSE-FREE 46 main 0 0.53 127828 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 3 FAILED FALSE-FREE 46 main 0 0.53 127884 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 4 FAILED FALSE-FREE 46 main 0 0.51 127700 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 5 FAILED FALSE-FREE 46 main 0 0.53 127476 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.51 341160 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 341312 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 93668 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.47 93072 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.42 92848 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 0.37 127508 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 0.36 129608 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 0.36 127476 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 0.36 127872 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 0.37 127548 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 92748 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 93244 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.42 93028 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.42 93460 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 93100 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.35 127436 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.33 127032 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.36 127992 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.37 127516 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.34 126720 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.44 94064 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.44 93100 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.44 94080 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.45 93048 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.44 93460 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.34 127740 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.34 127888 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.34 128356 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.36 128496 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.34 128376 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.66 94836 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.68 94456 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.73 94516 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.69 95040 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.68 94740 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 8.12 171120 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 7.28 168388 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 7.41 168304 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 7.45 168448 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 7.00 168256 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.56 570924 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.65 571496 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.63 571932 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.58 570600 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.59 572628 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 13.36 140468 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 13.35 140724 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 13.57 141216 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 13.82 140812 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 13.24 140676 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 779 free_17 0 0.71 95436 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 779 free_17 0 0.70 95232 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 779 free_17 0 0.74 95472 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 779 free_17 0 0.71 94984 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 779 free_17 0 0.69 95228 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 779 free_17 0 26.62 180200 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 779 free_17 0 28.10 181016 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 779 free_17 0 27.14 180724 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 779 free_17 0 26.65 181324 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 779 free_17 0 27.89 181108 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.56 340896 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.58 465440 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.70 341228 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.58 465540 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.57 465840 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 4.42 138084 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 4.70 138096 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 4.42 139128 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 4.28 139212 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 4.58 139044 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.43 93408 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 93464 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.47 340916 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.41 93568 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.41 92752 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.37 126488 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.37 126904 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.36 127108 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 4 SUCCEEDED - - - 0 0.37 127540 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 5 SUCCEEDED - - - 0 0.35 126540 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 1 FAILED FALSE-DEREF 533 main 0 0.70 93468 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 2 FAILED FALSE-DEREF 533 main 0 0.57 93176 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 3 FAILED FALSE-DEREF 533 main 0 0.60 92880 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 4 FAILED FALSE-DEREF 533 main 0 0.60 93632 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 5 FAILED FALSE-DEREF 533 main 0 0.58 92984 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 0 - 0 1.54 136564 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 0 - 0 1.49 136340 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 0 - 0 1.51 136440 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 0 - 0 1.58 136360 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 0 - 0 1.48 136184 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.46 341200 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 341168 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 341380 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341248 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.46 340980 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 14.48 136556 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 14.02 136468 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 14.12 136716 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 15.23 136292 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 14.17 137000 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 1 FAILED FALSE-FREE 536 main 0 0.57 93084 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 2 FAILED FALSE-FREE 536 main 0 0.55 93056 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 3 FAILED FALSE-FREE 536 main 0 0.56 92520 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 4 FAILED FALSE-FREE 536 main 0 0.56 93148 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 5 FAILED FALSE-FREE 536 main 0 0.57 93088 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 1 FAILED FALSE-FREE 536 main 0 1.66 136548 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 2 FAILED FALSE-FREE 536 main 0 1.64 135704 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 3 FAILED FALSE-FREE 536 main 0 1.60 136668 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 4 FAILED FALSE-FREE 536 main 0 1.61 136748 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 5 FAILED FALSE-FREE 536 main 0 1.73 135512 +list-ext-properties/list-ext.yml unreach-call afl 1 UNKNOWN - - - 0 0.48 91848 +list-ext-properties/list-ext.yml unreach-call afl 2 UNKNOWN - - - 0 0.47 92220 +list-ext-properties/list-ext.yml unreach-call afl 3 UNKNOWN - - - 0 0.47 91684 +list-ext-properties/list-ext.yml unreach-call afl 4 UNKNOWN - - - 0 0.48 91976 +list-ext-properties/list-ext.yml unreach-call afl 5 UNKNOWN - - - 0 0.48 91908 +list-ext-properties/list-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 556 main 0 3.58 172148 +list-ext-properties/list-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 556 main 0 3.62 172764 +list-ext-properties/list-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 556 main 0 3.63 172212 +list-ext-properties/list-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 556 main 0 3.54 172144 +list-ext-properties/list-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 556 main 0 3.53 172360 +list-ext-properties/list-ext.yml valid-memsafety afl 1 FAILED FALSE-DEREF 558 main 0 0.59 93112 +list-ext-properties/list-ext.yml valid-memsafety afl 2 FAILED FALSE-DEREF 558 main 0 0.57 93116 +list-ext-properties/list-ext.yml valid-memsafety afl 3 FAILED FALSE-DEREF 558 main 0 0.57 93760 +list-ext-properties/list-ext.yml valid-memsafety afl 4 FAILED FALSE-DEREF 558 main 0 0.58 93908 +list-ext-properties/list-ext.yml valid-memsafety afl 5 FAILED FALSE-DEREF 558 main 0 0.58 93492 +list-ext-properties/list-ext.yml valid-memsafety symex 1 FAILED FALSE-DEREF 558 main 0 32.19 248492 +list-ext-properties/list-ext.yml valid-memsafety symex 2 FAILED FALSE-DEREF 558 main 0 32.15 253512 +list-ext-properties/list-ext.yml valid-memsafety symex 3 FAILED FALSE-DEREF 558 main 0 32.21 257240 +list-ext-properties/list-ext.yml valid-memsafety symex 4 FAILED FALSE-DEREF 558 main 0 32.19 247784 +list-ext-properties/list-ext.yml valid-memsafety symex 5 FAILED FALSE-DEREF 558 main 0 32.06 247848 +list-ext-properties/simple-ext.yml unreach-call afl 1 FAILED TARGET-REACHED 540 main 0 0.48 92032 +list-ext-properties/simple-ext.yml unreach-call afl 2 FAILED TARGET-REACHED 540 main 0 0.46 92280 +list-ext-properties/simple-ext.yml unreach-call afl 3 FAILED TARGET-REACHED 540 main 0 0.48 92280 +list-ext-properties/simple-ext.yml unreach-call afl 4 FAILED TARGET-REACHED 540 main 0 0.48 92148 +list-ext-properties/simple-ext.yml unreach-call afl 5 FAILED TARGET-REACHED 540 main 0 0.49 91516 +list-ext-properties/simple-ext.yml unreach-call symex 1 UNKNOWN - - - 0 0.43 133616 +list-ext-properties/simple-ext.yml unreach-call symex 2 UNKNOWN - - - 0 0.43 135976 +list-ext-properties/simple-ext.yml unreach-call symex 3 UNKNOWN - - - 0 0.44 134264 +list-ext-properties/simple-ext.yml unreach-call symex 4 UNKNOWN - - - 0 0.43 133976 +list-ext-properties/simple-ext.yml unreach-call symex 5 UNKNOWN - - - 0 0.44 134048 +list-ext-properties/simple-ext.yml valid-memcleanup afl 1 UNKNOWN - - - 0 9.45 602568 +list-ext-properties/simple-ext.yml valid-memcleanup afl 2 UNKNOWN - - - 0 9.45 609512 +list-ext-properties/simple-ext.yml valid-memcleanup afl 3 UNKNOWN - - - 0 9.44 584136 +list-ext-properties/simple-ext.yml valid-memcleanup afl 4 UNKNOWN - - - 0 9.45 555328 +list-ext-properties/simple-ext.yml valid-memcleanup afl 5 UNKNOWN - - - 0 9.45 602592 +list-ext-properties/simple-ext.yml valid-memcleanup symex 1 UNKNOWN - - - 0 0.93 134628 +list-ext-properties/simple-ext.yml valid-memcleanup symex 2 UNKNOWN - - - 0 0.94 134548 +list-ext-properties/simple-ext.yml valid-memcleanup symex 3 UNKNOWN - - - 0 0.92 134228 +list-ext-properties/simple-ext.yml valid-memcleanup symex 4 UNKNOWN - - - 0 0.95 134752 +list-ext-properties/simple-ext.yml valid-memcleanup symex 5 UNKNOWN - - - 0 0.92 134360 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.56 92956 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.56 92944 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.56 92864 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.55 92792 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.57 93696 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 0.57 128788 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 0.57 127680 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 0.56 128020 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 0.56 127724 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 0.56 128276 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 341536 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 340528 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 341028 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.43 340948 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.43 341176 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.48 134520 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.48 134392 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.50 134208 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 0.47 134368 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 0.48 134124 +map2check-assert/array_bug.yml unreach-call afl 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.47 92012 +map2check-assert/array_bug.yml unreach-call afl 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.47 91464 +map2check-assert/array_bug.yml unreach-call afl 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.47 91748 +map2check-assert/array_bug.yml unreach-call afl 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.47 91336 +map2check-assert/array_bug.yml unreach-call afl 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.48 91960 +map2check-assert/array_bug.yml unreach-call symex 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 5.63 171504 +map2check-assert/array_bug.yml unreach-call symex 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 5.51 171348 +map2check-assert/array_bug.yml unreach-call symex 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 5.63 171480 +map2check-assert/array_bug.yml unreach-call symex 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 5.43 171368 +map2check-assert/array_bug.yml unreach-call symex 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 5.43 171484 +map2check-assert/byte_add_bug.yml unreach-call afl 1 UNKNOWN - - - 0 9.35 91956 +map2check-assert/byte_add_bug.yml unreach-call afl 2 UNKNOWN - - - 0 9.34 91800 +map2check-assert/byte_add_bug.yml unreach-call afl 3 UNKNOWN - - - 0 9.34 91740 +map2check-assert/byte_add_bug.yml unreach-call afl 4 UNKNOWN - - - 0 9.35 92316 +map2check-assert/byte_add_bug.yml unreach-call afl 5 UNKNOWN - - - 0 9.36 91548 +map2check-assert/byte_add_bug.yml unreach-call symex 1 SUCCEEDED - - - 0 0.34 126848 +map2check-assert/byte_add_bug.yml unreach-call symex 2 SUCCEEDED - - - 0 0.34 127120 +map2check-assert/byte_add_bug.yml unreach-call symex 3 SUCCEEDED - - - 0 0.34 127516 +map2check-assert/byte_add_bug.yml unreach-call symex 4 SUCCEEDED - - - 0 0.34 127096 +map2check-assert/byte_add_bug.yml unreach-call symex 5 SUCCEEDED - - - 0 0.34 127636 +map2check-assert/check_if_bug.yml unreach-call afl 1 UNKNOWN - - - 0 0.32 91884 +map2check-assert/check_if_bug.yml unreach-call afl 2 UNKNOWN - - - 0 0.32 92300 +map2check-assert/check_if_bug.yml unreach-call afl 3 UNKNOWN - - - 0 0.34 91540 +map2check-assert/check_if_bug.yml unreach-call afl 4 UNKNOWN - - - 0 0.34 91488 +map2check-assert/check_if_bug.yml unreach-call afl 5 UNKNOWN - - - 0 0.34 92312 +map2check-assert/check_if_bug.yml unreach-call symex 1 UNKNOWN - - - 0 31.76 184048 +map2check-assert/check_if_bug.yml unreach-call symex 2 UNKNOWN - - - 0 31.73 183980 +map2check-assert/check_if_bug.yml unreach-call symex 3 UNKNOWN - - - 0 31.69 184208 +map2check-assert/check_if_bug.yml unreach-call symex 4 UNKNOWN - - - 0 31.70 184808 +map2check-assert/check_if_bug.yml unreach-call symex 5 UNKNOWN - - - 0 32.05 183988 +map2check-assert/ex01_false.yml unreach-call afl 1 UNKNOWN - - - 0 1.34 91788 +map2check-assert/ex01_false.yml unreach-call afl 2 UNKNOWN - - - 0 1.34 91048 +map2check-assert/ex01_false.yml unreach-call afl 3 UNKNOWN - - - 0 1.35 91416 +map2check-assert/ex01_false.yml unreach-call afl 4 UNKNOWN - - - 0 1.34 91164 +map2check-assert/ex01_false.yml unreach-call afl 5 UNKNOWN - - - 0 1.34 92128 +map2check-assert/ex01_false.yml unreach-call symex 1 UNKNOWN - - - 0 2.34 144456 +map2check-assert/ex01_false.yml unreach-call symex 2 UNKNOWN - - - 0 2.34 143984 +map2check-assert/ex01_false.yml unreach-call symex 3 UNKNOWN - - - 0 2.35 146832 +map2check-assert/ex01_false.yml unreach-call symex 4 UNKNOWN - - - 0 2.33 144828 +map2check-assert/ex01_false.yml unreach-call symex 5 UNKNOWN - - - 0 2.34 144428 +map2check-assert/ex02_false.yml unreach-call afl 1 UNKNOWN - - - 0 0.32 91924 +map2check-assert/ex02_false.yml unreach-call afl 2 UNKNOWN - - - 0 0.33 91980 +map2check-assert/ex02_false.yml unreach-call afl 3 UNKNOWN - - - 0 0.32 90976 +map2check-assert/ex02_false.yml unreach-call afl 4 UNKNOWN - - - 0 0.32 91352 +map2check-assert/ex02_false.yml unreach-call afl 5 UNKNOWN - - - 0 0.34 91500 +map2check-assert/ex02_false.yml unreach-call symex 1 UNKNOWN - - - 0 31.43 226008 +map2check-assert/ex02_false.yml unreach-call symex 2 UNKNOWN - - - 0 31.40 225284 +map2check-assert/ex02_false.yml unreach-call symex 3 UNKNOWN - - - 0 31.42 226316 +map2check-assert/ex02_false.yml unreach-call symex 4 UNKNOWN - - - 0 31.45 225168 +map2check-assert/ex02_false.yml unreach-call symex 5 UNKNOWN - - - 0 31.41 225940 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 93208 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 93164 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 93076 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 93024 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 93992 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.86 170120 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.64 170640 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.74 170336 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.80 170444 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.82 170004 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.44 92720 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.43 92896 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.44 93140 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.43 93044 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.44 92716 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.44 158940 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.44 158588 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.45 158932 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.46 158628 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.45 159076 +memsafety-ext/tree_stack.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.45 93188 +memsafety-ext/tree_stack.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.44 93248 +memsafety-ext/tree_stack.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.44 92784 +memsafety-ext/tree_stack.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.45 93636 +memsafety-ext/tree_stack.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.46 93188 +memsafety-ext/tree_stack.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.59 185740 +memsafety-ext/tree_stack.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.60 185704 +memsafety-ext/tree_stack.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.59 185012 +memsafety-ext/tree_stack.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.60 185712 +memsafety-ext/tree_stack.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.59 185792 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.46 94004 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.45 94012 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 93436 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.44 93832 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.46 93128 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.36 141752 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.35 141352 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.35 141632 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.35 141724 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.35 143564 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 93820 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.47 93500 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 93620 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 93192 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.48 94340 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.94 252540 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.94 252424 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.95 252816 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.93 253012 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.94 252560 +memsafety/960521-1-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 532 main 0 0.57 92852 +memsafety/960521-1-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 532 main 0 0.58 93680 +memsafety/960521-1-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 532 main 0 0.55 93092 +memsafety/960521-1-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 532 main 0 0.55 93052 +memsafety/960521-1-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 532 main 0 0.57 93996 +memsafety/960521-1-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 532 main 0 0.93 128024 +memsafety/960521-1-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 532 main 0 0.93 128048 +memsafety/960521-1-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 532 main 0 0.93 127556 +memsafety/960521-1-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 532 main 0 0.93 127876 +memsafety/960521-1-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 532 main 0 0.95 127848 +memsafety/960521-1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.42 92840 +memsafety/960521-1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 93088 +memsafety/960521-1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.42 92696 +memsafety/960521-1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.42 92924 +memsafety/960521-1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.42 93016 +memsafety/960521-1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.35 127700 +memsafety/960521-1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.36 127884 +memsafety/960521-1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.33 127240 +memsafety/960521-1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.34 126888 +memsafety/960521-1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.34 128212 +memsafety/960521-1-3.yml valid-memsafety afl 1 FAILED FALSE-DEREF 529 main 0 0.60 92724 +memsafety/960521-1-3.yml valid-memsafety afl 2 FAILED FALSE-DEREF 529 main 0 0.59 92932 +memsafety/960521-1-3.yml valid-memsafety afl 3 FAILED FALSE-DEREF 529 main 0 0.56 93140 +memsafety/960521-1-3.yml valid-memsafety afl 4 FAILED FALSE-DEREF 529 main 0 0.55 93088 +memsafety/960521-1-3.yml valid-memsafety afl 5 FAILED FALSE-DEREF 529 main 0 0.57 92612 +memsafety/960521-1-3.yml valid-memsafety symex 1 FAILED FALSE-DEREF 529 main 0 0.90 127524 +memsafety/960521-1-3.yml valid-memsafety symex 2 FAILED FALSE-DEREF 529 main 0 0.89 128592 +memsafety/960521-1-3.yml valid-memsafety symex 3 FAILED FALSE-DEREF 529 main 0 0.91 128252 +memsafety/960521-1-3.yml valid-memsafety symex 4 FAILED FALSE-DEREF 529 main 0 0.91 127236 +memsafety/960521-1-3.yml valid-memsafety symex 5 FAILED FALSE-DEREF 529 main 0 0.91 128108 +memsafety/test-0102-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.46 93192 +memsafety/test-0102-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.48 93720 +memsafety/test-0102-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 93556 +memsafety/test-0102-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.46 93712 +memsafety/test-0102-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.46 93240 +memsafety/test-0102-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.37 150448 +memsafety/test-0102-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.38 150584 +memsafety/test-0102-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.38 150436 +memsafety/test-0102-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.38 149240 +memsafety/test-0102-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.40 150276 From d32c614e864f2484b51f98a97b814cd125d77817 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:10:14 -0400 Subject: [PATCH 05/44] build: build and install the Rust runtime instead of the C bitcode library --- CMakeLists.txt | 2 + cmake/Map2CheckRustRuntime.cmake | 76 ++++++++++++++++++++++++ modules/backend/CMakeLists.txt | 1 - tests/cutover/test_rust_runtime_cmake.sh | 61 +++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 cmake/Map2CheckRustRuntime.cmake create mode 100755 tests/cutover/test_rust_runtime_cmake.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index a10f305e4..f149a5c93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,8 @@ if(ENABLE_TEST) add_subdirectory(tests) endif() +include(cmake/Map2CheckRustRuntime.cmake) + add_subdirectory(modules) if(BUILD_DOC) diff --git a/cmake/Map2CheckRustRuntime.cmake b/cmake/Map2CheckRustRuntime.cmake new file mode 100644 index 000000000..5474239a7 --- /dev/null +++ b/cmake/Map2CheckRustRuntime.cmake @@ -0,0 +1,76 @@ +# Map2Check runtime: map2check-library (Rust). Replaces modules/backend/library +# (the C bitcode runtime, no longer part of the build). +# +# Installs ${prefix}/lib/libmap2check.a and, when available, +# ${prefix}/lib/map2check-klee.bc (KLEE runtime bitcode, LLVM 16). +set(MAP2CHECK_RUST_LIB_DIR "" CACHE PATH "Directory with a prebuilt libmap2check.a (empty = build from MAP2CHECK_RUST_SRC)") +set(MAP2CHECK_RUST_SRC "" CACHE PATH "map2check-library checkout used when MAP2CHECK_RUST_LIB_DIR is empty") +set(MAP2CHECK_RUST_KLEE_BC "" CACHE FILEPATH "Prebuilt KLEE runtime bitcode (empty = none, or built from MAP2CHECK_RUST_SRC when rustc 1.72.1 is available)") + +# --- Static library --- +if(MAP2CHECK_RUST_LIB_DIR) + set(_m2c_rust_lib "${MAP2CHECK_RUST_LIB_DIR}/libmap2check.a") + if(NOT EXISTS "${_m2c_rust_lib}") + message(FATAL_ERROR "libmap2check.a not found in ${MAP2CHECK_RUST_LIB_DIR} " + "(build it with: cargo build --profile runtime --features libfuzzer,wasm)") + endif() +elseif(MAP2CHECK_RUST_SRC) + find_program(M2C_CARGO cargo REQUIRED) + set(_m2c_rust_lib "${MAP2CHECK_RUST_SRC}/target/runtime/libmap2check.a") + add_custom_command(OUTPUT "${_m2c_rust_lib}" + COMMAND ${M2C_CARGO} build --profile runtime --features libfuzzer,wasm + WORKING_DIRECTORY "${MAP2CHECK_RUST_SRC}" + COMMENT "Building the Rust runtime (libmap2check.a)" + VERBATIM) + add_custom_target(Map2CheckRustRuntime ALL DEPENDS "${_m2c_rust_lib}") +else() + message(FATAL_ERROR "Set MAP2CHECK_RUST_LIB_DIR or MAP2CHECK_RUST_SRC to provide the Rust runtime") +endif() +install(FILES "${_m2c_rust_lib}" DESTINATION lib) +message(STATUS "Rust runtime: ${_m2c_rust_lib}") + +# --- KLEE bitcode (optional) --- +find_program(M2C_LLVM_DIS NAMES llvm-dis-16 llvm-dis + HINTS "${LLVM_TOOLS_BINARY_DIR}" "${LLVM_DIR}/../../../bin") + +if(MAP2CHECK_RUST_KLEE_BC) + if(NOT EXISTS "${MAP2CHECK_RUST_KLEE_BC}") + message(FATAL_ERROR "MAP2CHECK_RUST_KLEE_BC=${MAP2CHECK_RUST_KLEE_BC} does not exist") + endif() + if(NOT M2C_LLVM_DIS) + message(FATAL_ERROR "llvm-dis-16 not found: cannot validate MAP2CHECK_RUST_KLEE_BC") + endif() + execute_process(COMMAND "${M2C_LLVM_DIS}" "${MAP2CHECK_RUST_KLEE_BC}" -o /dev/null + RESULT_VARIABLE _m2c_dis_rc ERROR_VARIABLE _m2c_dis_err OUTPUT_QUIET) + if(NOT _m2c_dis_rc EQUAL 0) + message(FATAL_ERROR "MAP2CHECK_RUST_KLEE_BC=${MAP2CHECK_RUST_KLEE_BC} cannot be read by ${M2C_LLVM_DIS}: ${_m2c_dis_err}") + endif() + install(FILES "${MAP2CHECK_RUST_KLEE_BC}" DESTINATION lib RENAME map2check-klee.bc) + message(STATUS "Rust runtime KLEE bitcode: ${MAP2CHECK_RUST_KLEE_BC}") +elseif(MAP2CHECK_RUST_SRC AND EXISTS "${MAP2CHECK_RUST_SRC}/scripts/build-klee-runtime.sh") + # Optional: build it through the library script (needs rustc 1.72.1 + LLVM 16 tools). + find_program(M2C_RUSTUP rustup) + set(_m2c_klee_ok FALSE) + if(M2C_RUSTUP AND M2C_LLVM_DIS) + execute_process(COMMAND "${M2C_RUSTUP}" run 1.72.1 rustc --version + RESULT_VARIABLE _m2c_rc OUTPUT_QUIET ERROR_QUIET) + if(_m2c_rc EQUAL 0) + set(_m2c_klee_ok TRUE) + endif() + endif() + if(_m2c_klee_ok) + set(_m2c_klee_bc "${CMAKE_BINARY_DIR}/map2check-klee.bc") + add_custom_command(OUTPUT "${_m2c_klee_bc}" + COMMAND "${MAP2CHECK_RUST_SRC}/scripts/build-klee-runtime.sh" "${_m2c_klee_bc}" + WORKING_DIRECTORY "${MAP2CHECK_RUST_SRC}" + COMMENT "Building the Rust runtime KLEE bitcode" + VERBATIM) + add_custom_target(Map2CheckRustKleeBitcode ALL DEPENDS "${_m2c_klee_bc}") + install(FILES "${_m2c_klee_bc}" DESTINATION lib RENAME map2check-klee.bc) + message(STATUS "Rust runtime KLEE bitcode: will be built from ${MAP2CHECK_RUST_SRC}") + else() + message(STATUS "Rust runtime KLEE bitcode: skipped (set MAP2CHECK_RUST_KLEE_BC, or provide rustc 1.72.1 + llvm-dis)") + endif() +else() + message(STATUS "Rust runtime KLEE bitcode: none (MAP2CHECK_RUST_KLEE_BC unset)") +endif() diff --git a/modules/backend/CMakeLists.txt b/modules/backend/CMakeLists.txt index ac84c66be..6b246d7e7 100644 --- a/modules/backend/CMakeLists.txt +++ b/modules/backend/CMakeLists.txt @@ -1,2 +1 @@ add_subdirectory(pass) -add_subdirectory(library) diff --git a/tests/cutover/test_rust_runtime_cmake.sh b/tests/cutover/test_rust_runtime_cmake.sh new file mode 100755 index 000000000..04b3aaad7 --- /dev/null +++ b/tests/cutover/test_rust_runtime_cmake.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# CMake/install layer of the Rust runtime: only libmap2check.a (and optionally +# map2check-klee.bc) is installed, no C runtime bitcode; configure fails loudly +# without a library or with an unreadable bitcode. +# +# Env: MAP2CHECK_RUST_LIB_DIR directory with libmap2check.a (required) +# CMAKE_ARGS extra configure flags (e.g. -G Ninja -DLLVM_DIR=...) +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +LIB="${MAP2CHECK_RUST_LIB_DIR:?set MAP2CHECK_RUST_LIB_DIR}" +read -r -a EXTRA <<<"${CMAKE_ARGS:-}" +W="$(mktemp -d)" +trap 'rm -rf "$W"' EXIT +fail() { echo "FAIL: $*" >&2; exit 1; } + +install_tree() { # ; prints nothing, installs to $W/-p + local n="$1"; shift + cmake -S "$ROOT" -B "$W/$n-b" "${EXTRA[@]}" -DCMAKE_INSTALL_PREFIX="$W/$n-p" "$@" >/dev/null + cmake --build "$W/$n-b" -j >/dev/null + cmake --install "$W/$n-b" >/dev/null +} + +# 1. Only the Rust static library is installed; no C runtime .bc. +install_tree plain -DMAP2CHECK_RUST_LIB_DIR="$LIB" +P="$W/plain-p" +test -f "$P/lib/libmap2check.a" || fail "libmap2check.a not installed" +if ls "$P"/lib/*.bc 2>/dev/null | grep .; then fail "bitcode installed without MAP2CHECK_RUST_KLEE_BC"; fi +if find "$P" -name '*.bc' | grep -E 'map2check|memtrack|bbtrack|nondet|caller|container|analysis|list|btree|AnalysisMode' ; then + fail "C runtime bitcode still installed" +fi + +# 2. A readable KLEE bitcode is installed as lib/map2check-klee.bc. +LLVM_DIS="${LLVM_DIS:-llvm-dis-16}"; LLVM_AS="${LLVM_AS:-llvm-as-16}" +echo 'define i32 @f() { ret i32 0 }' >"$W/ok.ll" +"$LLVM_AS" "$W/ok.ll" -o "$W/ok.bc" +install_tree klee -DMAP2CHECK_RUST_LIB_DIR="$LIB" -DMAP2CHECK_RUST_KLEE_BC="$W/ok.bc" +P="$W/klee-p" +test -f "$P/lib/map2check-klee.bc" || fail "map2check-klee.bc not installed" +if ls "$P"/lib/*.bc | grep -vE 'map2check-klee\.bc$'; then fail "extra bitcode installed"; fi + +# 3. No library: configure must fail, with a clear message. +E="$W/empty"; mkdir "$E" +if cmake -S "$ROOT" -B "$W/bad1" "${EXTRA[@]}" -DMAP2CHECK_RUST_LIB_DIR="$E" >"$W/bad1.log" 2>&1; then + fail "configure should fail without libmap2check.a" +fi +grep -q "libmap2check.a not found" "$W/bad1.log" || fail "no clear message for missing library" +if cmake -S "$ROOT" -B "$W/bad2" "${EXTRA[@]}" -DMAP2CHECK_RUST_LIB_DIR= -DMAP2CHECK_RUST_SRC= >"$W/bad2.log" 2>&1; then + fail "configure should fail with neither MAP2CHECK_RUST_LIB_DIR nor MAP2CHECK_RUST_SRC" +fi +grep -q "MAP2CHECK_RUST_LIB_DIR or MAP2CHECK_RUST_SRC" "$W/bad2.log" || fail "no clear message for unset variables" + +# 4. Unreadable bitcode: configure must fail. +echo 'not bitcode' >"$W/bad.bc" +if cmake -S "$ROOT" -B "$W/bad3" "${EXTRA[@]}" -DMAP2CHECK_RUST_LIB_DIR="$LIB" -DMAP2CHECK_RUST_KLEE_BC="$W/bad.bc" >"$W/bad3.log" 2>&1; then + fail "configure should fail with an unreadable bitcode" +fi +grep -q "cannot be read" "$W/bad3.log" || fail "no clear message for unreadable bitcode" +if cmake -S "$ROOT" -B "$W/bad4" "${EXTRA[@]}" -DMAP2CHECK_RUST_LIB_DIR="$LIB" -DMAP2CHECK_RUST_KLEE_BC="$W/missing.bc" >"$W/bad4.log" 2>&1; then + fail "configure should fail with a missing bitcode file" +fi +echo ok From 54c49d41cd72c1d098ec078c0fe32f3669468c79 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:40:18 -0400 Subject: [PATCH 06/44] build: stop building the C runtime unit tests --- tests/unit/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index d413da1de..a63ef7e23 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -3,5 +3,8 @@ function(map2check_test EXECUTABLE) add_test(NAME ${EXECUTABLE} COMMAND ${EXECUTABLE}) endfunction(map2check_test) -add_subdirectory(backend-library) +# backend-library unit tests exercise the C runtime objects, which are no longer +# built (the runtime is the Rust library). The files stay until their assertions +# are ported to Rust (plan Task 5.2) and are deleted with the C runtime (Task 6.2). +# add_subdirectory(backend-library) add_subdirectory(frontend) From 393b6a2eb0563b6f238b9060bcaec7e29e840305 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:53:13 -0400 Subject: [PATCH 07/44] feat(pass): add the runtime hook table of map2check-library and its tests RuntimeABI.hpp/.cpp is the single place that names the runtime functions the passes emit: every RuntimeHook maps to a core symbol of map2check-library and its exact LLVM type, as given by docs/cutover/abi-mapping.tsv and map2check.h. Hooks whose core is '-' (the _uint binops, check_deref, overflowError) are not in the table. tests/unit/pass checks the table against a vendored copy of the mapping (RuntimeABI.*) and, per hook, the IR each pass emits (PassIR.*). The PassIR tests of the passes are red until each pass is migrated. kProgramUnwindFlags names the -fexceptions flag of D1 condition 11. --- modules/backend/pass/CMakeLists.txt | 7 +- modules/backend/pass/RuntimeABI.cpp | 156 +++++++++++ modules/backend/pass/RuntimeABI.hpp | 92 +++++++ modules/frontend/utils/clang.hpp | 10 + tests/unit/CMakeLists.txt | 1 + tests/unit/pass/AbiMapping.hpp | 82 ++++++ tests/unit/pass/CMakeLists.txt | 62 +++++ tests/unit/pass/PassIRTest.cpp | 380 +++++++++++++++++++++++++++ tests/unit/pass/RuntimeABITest.cpp | 180 +++++++++++++ tests/unit/pass/data/abi-mapping.tsv | 77 ++++++ tests/unit/pass/inputs/assert.c | 7 + tests/unit/pass/inputs/assert_fail.c | 7 + tests/unit/pass/inputs/assume.c | 13 + tests/unit/pass/inputs/loop.c | 9 + tests/unit/pass/inputs/main.c | 9 + tests/unit/pass/inputs/target.c | 9 + tests/unit/pass/inputs/track_bb.c | 9 + 17 files changed, 1109 insertions(+), 1 deletion(-) create mode 100644 modules/backend/pass/RuntimeABI.cpp create mode 100644 modules/backend/pass/RuntimeABI.hpp create mode 100644 tests/unit/pass/AbiMapping.hpp create mode 100644 tests/unit/pass/CMakeLists.txt create mode 100644 tests/unit/pass/PassIRTest.cpp create mode 100644 tests/unit/pass/RuntimeABITest.cpp create mode 100644 tests/unit/pass/data/abi-mapping.tsv create mode 100644 tests/unit/pass/inputs/assert.c create mode 100644 tests/unit/pass/inputs/assert_fail.c create mode 100644 tests/unit/pass/inputs/assume.c create mode 100644 tests/unit/pass/inputs/loop.c create mode 100644 tests/unit/pass/inputs/main.c create mode 100644 tests/unit/pass/inputs/target.c create mode 100644 tests/unit/pass/inputs/track_bb.c diff --git a/modules/backend/pass/CMakeLists.txt b/modules/backend/pass/CMakeLists.txt index d96789e65..42074679a 100755 --- a/modules/backend/pass/CMakeLists.txt +++ b/modules/backend/pass/CMakeLists.txt @@ -1,9 +1,12 @@ add_library(DebugInfo OBJECT DebugInfo.cpp) +# Names and types of the runtime functions the passes emit (map2check-library). +add_library(RuntimeABI OBJECT RuntimeABI.cpp) # BUG: If we do not set this flag opt will not work with our pass # even if it was the same build from llvm set(CXX_FLAGS "${CXX_FLAGS} -fno-rtti ") set_target_properties(DebugInfo PROPERTIES COMPILE_FLAGS ${CXX_FLAGS}) +set_target_properties(RuntimeABI PROPERTIES COMPILE_FLAGS ${CXX_FLAGS}) list(APPEND MAP2CHECK_PASS_LIB "") list(APPEND MAP2CHECK_PASS_LIB "NonDetPass") @@ -19,7 +22,9 @@ list(APPEND MAP2CHECK_PASS_LIB "LoopPredAssumePass") foreach(F ${MAP2CHECK_PASS_LIB}) - add_library(${F} SHARED ${F}.cpp $) + add_library(${F} SHARED ${F}.cpp $ + $) set_target_properties(${F} PROPERTIES COMPILE_FLAGS ${CXX_FLAGS}) install(TARGETS ${F} DESTINATION lib) endforeach() + diff --git a/modules/backend/pass/RuntimeABI.cpp b/modules/backend/pass/RuntimeABI.cpp new file mode 100644 index 000000000..e34c69d0e --- /dev/null +++ b/modules/backend/pass/RuntimeABI.cpp @@ -0,0 +1,156 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * LLVM -> NCSA + * + * SPDX-License-Identifier: (GPL-2.0 AND NCSA) + **/ + +#include "RuntimeABI.hpp" + +#include +#include + +namespace Map2Check { + +namespace { + +llvm::FunctionType* fn(llvm::Type* ret, llvm::ArrayRef params) { + return llvm::FunctionType::get(ret, params, false); +} + +} // namespace + +RuntimeCall runtimeCall(RuntimeHook hook, llvm::LLVMContext& ctx) { + llvm::Type* v = llvm::Type::getVoidTy(ctx); + llvm::Type* i16 = llvm::Type::getInt16Ty(ctx); + llvm::Type* i32 = llvm::Type::getInt32Ty(ctx); + llvm::Type* i64 = llvm::Type::getInt64Ty(ctx); + llvm::Type* p = llvm::PointerType::get(ctx, 0); + + switch (hook) { + // abi-mapping: map2check_init -> map2check_set_mode+map2check_init + case RuntimeHook::SetMode: + return {"map2check_set_mode", fn(v, {i32})}; + case RuntimeHook::Init: + return {"map2check_init", fn(v, {})}; + // abi-mapping: map2check_success + case RuntimeHook::Success: + return {"map2check_success", fn(v, {})}; + // abi-mapping: map2check_track_bb (returns bbtrack_log_t*, ignored) + case RuntimeHook::TrackBB: + return {"map2check_save_basic_block_log", fn(p, {i32, p})}; + // abi-mapping: map2check_target_function + case RuntimeHook::TargetReached: + return {"map2check_reach_target", fn(v, {p, i32, i32})}; + // abi-mapping: map2check_assert (condition moves from first to last) + case RuntimeHook::Assert: + return {"map2check_is_valid_assert", fn(v, {i32, p, i32})}; + // abi-mapping: map2check_assume, map2check_assume_loop, + // map2check_crab_assume (an i1 condition is zero-extended to i32) + case RuntimeHook::Assume: + return {"__VERIFIER_assume", fn(v, {i32})}; + // abi-mapping: map2check_binop_{add,sub,mul,sdiv,srem}; no scope argument + case RuntimeHook::BinopAdd: + return {"map2check_binop_add_signed", fn(v, {i64, i64, i32, i32, p})}; + case RuntimeHook::BinopSub: + return {"map2check_binop_sub_signed", fn(v, {i64, i64, i32, i32, p})}; + case RuntimeHook::BinopMul: + return {"map2check_binop_mul_signed", fn(v, {i64, i64, i32, i32, p})}; + case RuntimeHook::BinopSDiv: + return {"map2check_binop_div_signed", fn(v, {i64, i64, i32, i32, p})}; + case RuntimeHook::BinopSRem: + return {"map2check_binop_rem_signed", fn(v, {i64, i64, i32, i32, p})}; + // abi-mapping: map2check_malloc / map2check_calloc (sizes narrow to i32) + case RuntimeHook::Malloc: + return {"map2check_map_malloc", fn(v, {p, i32})}; + case RuntimeHook::Calloc: + return {"map2check_map_calloc", fn(v, {p, i32, i32})}; + // abi-mapping: map2check_alloca / map2check_non_static_alloca + case RuntimeHook::Alloca: + return {"map2check_map_alloca", fn(v, {p, p, i32, i32, i32, i32})}; + case RuntimeHook::NonStaticAlloca: + return {"map2check_map_non_static_alloca", + fn(v, {p, p, i32, i32, i32, i32})}; + // abi-mapping: map2check_function + case RuntimeHook::FunctionAddr: + return {"map2check_map_funct_address", fn(v, {p, p})}; + // abi-mapping: map2check_add_store_pointer + case RuntimeHook::StorePointer: + return {"map2check_map_store_pointer", fn(v, {p, p, i32, p, i32, p})}; + // abi-mapping: map2check_load (now with line, scope, size, function) + case RuntimeHook::Load: + return {"map2check_check_load", fn(v, {p, i32, i32, i32, p})}; + // abi-mapping: map2check_free -> map2check_check_free+map2check_map_free + // (name, pointer-variable slot, loaded value, scope, line, function) + case RuntimeHook::CheckFree: + return {"map2check_check_free", fn(v, {p, p, p, i32, i32, p})}; + case RuntimeHook::MapFree: + return {"map2check_map_free", fn(v, {p, p, p, i32, i32, p})}; + // abi-mapping: map2check_free_resolved_address (i1 nullValid -> i16) + case RuntimeHook::FreeResolved: + return {"map2check_check_free_resolved_address", fn(v, {p, i32, p, i16})}; + // abi-mapping: map2check_posix + case RuntimeHook::PosixMemalign: + return {"map2check_map_posix_memalign", fn(v, {p, i32})}; + // abi-mapping: map2check_wasm_* (feature wasm of the library) + case RuntimeHook::WasmMalloc: + return {"map2check_wasm_malloc", fn(v, {i64, i64})}; + case RuntimeHook::WasmFree: + return {"map2check_wasm_free", fn(v, {i64, i64})}; + case RuntimeHook::WasmCheckAccess: + return {"map2check_wasm_check_access", fn(v, {i64, i64})}; + } + return {nullptr, nullptr}; +} + +llvm::FunctionCallee getOrInsertRuntime(llvm::Module& module, + RuntimeHook hook) { + RuntimeCall call = runtimeCall(hook, module.getContext()); + return module.getOrInsertFunction(call.name, call.type); +} + +// The nondet family of the mapping: map2check_non_det_ becomes +// __VERIFIER_nondet_, map2check_nondet_ becomes +// map2check_save_nondet_log_. +std::string nonDetGenerator(llvm::StringRef cType) { + llvm::StringRef suffix = llvm::StringSwitch(cType) + .Case("int", "int") + .Case("unsigned", "uint") + .Case("uint", "uint") + .Case("char", "char") + .Case("uchar", "uchar") + .Case("short", "short") + .Case("ushort", "ushort") + .Case("long", "long") + .Case("ulong", "ulong") + .Case("bool", "bool") + .Case("pointer", "pointer") + .Case("pchar", "pchar") + .Case("size_t", "size_t") + .Case("loff_t", "loff_t") + .Case("sector_t", "sector_t") + .Case("double", "double") + .Default(""); + return suffix.empty() ? "" : ("__VERIFIER_nondet_" + suffix).str(); +} + +std::string nonDetLogger(llvm::StringRef cType) { + bool known = llvm::StringSwitch(cType) + .Cases("int", "unsigned", "uint", "char", "uchar", true) + .Cases("short", "ushort", "long", "ulong", "bool", true) + .Cases("pointer", "pchar", "size_t", "loff_t", true) + .Cases("sector_t", "double", true) + .Default(false); + return known ? ("map2check_save_nondet_log_" + cType).str() : ""; +} + +llvm::FunctionType* nonDetLoggerType(llvm::LLVMContext& ctx) { + llvm::Type* i32 = llvm::Type::getInt32Ty(ctx); + llvm::Type* p = llvm::PointerType::get(ctx, 0); + return fn(p, {i32, i32, i32, p, p}); +} + +} // namespace Map2Check diff --git a/modules/backend/pass/RuntimeABI.hpp b/modules/backend/pass/RuntimeABI.hpp new file mode 100644 index 000000000..d0fd2e2e9 --- /dev/null +++ b/modules/backend/pass/RuntimeABI.hpp @@ -0,0 +1,92 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * LLVM -> NCSA + * + * SPDX-License-Identifier: (GPL-2.0 AND NCSA) + **/ + +// The one place that names the runtime functions the passes emit. +// +// The runtime is map2check-library (Rust). Its core C API is the contract: +// every name and LLVM type below is a row of docs/cutover/abi-mapping.tsv of +// that repository, and the types are the core signatures of its map2check.h +// lowered for x86-64 (int32_t/uint32_t -> i32, int16_t -> i16, +// int64_t/uint64_t -> i64, pointers -> ptr). There is no compatibility layer: +// a pass builds its arguments in the core order and calls the core symbol. +// tests/unit/pass/RuntimeABITest.cpp checks this table against the mapping. + +#ifndef MODULES_BACKEND_PASS_RUNTIMEABI_HPP_ +#define MODULES_BACKEND_PASS_RUNTIMEABI_HPP_ + +#include +#include +#include +#include + +#include + +namespace Map2Check { + +enum class RuntimeHook { + SetMode, // map2check_set_mode(i32 mode) + Init, // map2check_init() + Success, // map2check_success() + TrackBB, // map2check_save_basic_block_log(i32 line, ptr fn) -> ptr + TargetReached, // map2check_reach_target(ptr fn, i32 scope, i32 line) + Assert, // map2check_is_valid_assert(i32 line, ptr fn, i32 cond) + Assume, // __VERIFIER_assume(i32 cond) + BinopAdd, // map2check_binop_add_signed(i64 a, i64 b, i32 bits, + BinopSub, // i32 line, ptr fn), likewise sub/mul/div/rem + BinopMul, + BinopSDiv, + BinopSRem, + Malloc, // map2check_map_malloc(ptr, i32 size) + Calloc, // map2check_map_calloc(ptr, i32 qty, i32 size) + Alloca, // map2check_map_alloca(ptr name, ptr addr, i32 size, + // i32 size_primitive, i32 line, i32 scope) + NonStaticAlloca, // map2check_map_non_static_alloca(same as Alloca) + FunctionAddr, // map2check_map_funct_address(ptr name, ptr addr) + StorePointer, // map2check_map_store_pointer(ptr var, ptr value, + // i32 scope, ptr name, i32 line, ptr fn) + Load, // map2check_check_load(ptr, i32 line, i32 scope, + // i32 size, ptr fn) + CheckFree, // map2check_check_free(ptr name, ptr var_slot, ptr value, + // i32 scope, i32 line, ptr fn) + MapFree, // map2check_map_free(same as CheckFree) + FreeResolved, // map2check_check_free_resolved_address(ptr, i32 line, + // ptr fn, i16 is_null_valid) + PosixMemalign, // map2check_map_posix_memalign(ptr memptr, i32 size) + WasmMalloc, // map2check_wasm_malloc(i64 offset, i64 size) + WasmFree, // map2check_wasm_free(i64 offset, i64 line) + WasmCheckAccess, // map2check_wasm_check_access(i64 offset, i64 size) + Last = WasmCheckAccess +}; + +/// A function of the core runtime API: name + type, for getOrInsertFunction. +struct RuntimeCall { + const char* name; + llvm::FunctionType* type; +}; + +RuntimeCall runtimeCall(RuntimeHook hook, llvm::LLVMContext& ctx); + +/// Declares (or finds) the hook in `module`, with its core type. +llvm::FunctionCallee getOrInsertRuntime(llvm::Module& module, RuntimeHook hook); + +/// __VERIFIER_nondet_ for the C type suffix used by the passes +/// ("int", "unsigned", "pointer", ...); "" when the type is not in the mapping. +std::string nonDetGenerator(llvm::StringRef cType); + +/// map2check_save_nondet_log_; "" when the type is not in the mapping. +std::string nonDetLogger(llvm::StringRef cType); + +/// Type shared by every nondet logger: +/// (i32 line, i32 scope, i32 type_var, ptr value, ptr fn) -> ptr. +llvm::FunctionType* nonDetLoggerType(llvm::LLVMContext& ctx); + +} // namespace Map2Check + +#endif // MODULES_BACKEND_PASS_RUNTIMEABI_HPP_ diff --git a/modules/frontend/utils/clang.hpp b/modules/frontend/utils/clang.hpp index a0577d2b8..10bd2686e 100644 --- a/modules/frontend/utils/clang.hpp +++ b/modules/frontend/utils/clang.hpp @@ -14,6 +14,16 @@ namespace Map2Check { +/// Flags every clang invocation that turns the analysed program's C into +/// bitcode must pass (map2check-library D1, condition 11). The runtime +/// rejects a fuzzer input whose __VERIFIER_assume fails by unwinding through +/// the program's frames; without -fexceptions clang marks every C function +/// nounwind, and unwinding through a nounwind function is undefined in LLVM +/// IR. The attributes travel in the bitcode, so the flag belongs on the +/// -emit-llvm step. Never pair it with -fno-unwind-tables or +/// -fno-asynchronous-unwind-tables. +inline constexpr const char* kProgramUnwindFlags = "-fexceptions"; + inline std::string GenerateIRCode(std::string clang_path, std::string include_dir, std::string program) { diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a63ef7e23..788b1f425 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -8,3 +8,4 @@ endfunction(map2check_test) # are ported to Rust (plan Task 5.2) and are deleted with the C runtime (Task 6.2). # add_subdirectory(backend-library) add_subdirectory(frontend) +add_subdirectory(pass) diff --git a/tests/unit/pass/AbiMapping.hpp b/tests/unit/pass/AbiMapping.hpp new file mode 100644 index 000000000..5cf9e1c84 --- /dev/null +++ b/tests/unit/pass/AbiMapping.hpp @@ -0,0 +1,82 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// Reader for docs/cutover/abi-mapping.tsv of map2check-library: columns +// c_symbol, core_symbol (several joined by '+', '-' for none), owner_task, +// notes. Lines starting with '#' are comments. + +#ifndef TESTS_UNIT_PASS_ABIMAPPING_HPP_ +#define TESTS_UNIT_PASS_ABIMAPPING_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +namespace m2c_test { + +struct AbiRow { + std::string cSymbol; + std::vector coreSymbols; // empty when the core is '-' +}; + +inline std::vector loadAbiMapping(const std::string& path) { + std::ifstream in(path); + if (!in.is_open()) throw std::runtime_error("cannot open " + path); + std::vector rows; + std::string line; + bool header = true; + while (std::getline(in, line)) { + if (line.empty() || line[0] == '#') continue; + if (header) { // c_symbol core_symbol owner_task notes + header = false; + continue; + } + std::istringstream fields(line); + AbiRow row; + std::string core; + std::getline(fields, row.cSymbol, '\t'); + std::getline(fields, core, '\t'); + if (core != "-") { + std::istringstream parts(core); + std::string part; + while (std::getline(parts, part, '+')) { + if (!part.empty()) row.coreSymbols.push_back(part); + } + } + rows.push_back(std::move(row)); + } + return rows; +} + +/// Every name in the core_symbol column. +inline std::set loadCoreSymbols(const std::string& path) { + std::set core; + for (const AbiRow& row : loadAbiMapping(path)) { + core.insert(row.coreSymbols.begin(), row.coreSymbols.end()); + } + return core; +} + +/// Every c_symbol that is not also a core symbol: the names of the C runtime +/// that the passes must no longer emit. +inline std::set loadLegacyOnlySymbols(const std::string& path) { + std::set core = loadCoreSymbols(path); + std::set legacy; + for (const AbiRow& row : loadAbiMapping(path)) { + if (core.count(row.cSymbol) == 0) legacy.insert(row.cSymbol); + } + return legacy; +} + +} // namespace m2c_test + +#endif // TESTS_UNIT_PASS_ABIMAPPING_HPP_ diff --git a/tests/unit/pass/CMakeLists.txt b/tests/unit/pass/CMakeLists.txt new file mode 100644 index 000000000..a230cb53d --- /dev/null +++ b/tests/unit/pass/CMakeLists.txt @@ -0,0 +1,62 @@ +# Tests for the LLVM passes against the core API of map2check-library. +# +# RuntimeABITest checks the central hook table (modules/backend/pass/RuntimeABI) +# against the ABI mapping. PassIRTest compiles tiny C inputs with clang-16, runs +# one pass plugin through opt-16 and inspects the resulting module. + +find_program(M2C_TEST_CLANG NAMES clang-16 clang + HINTS "${LLVM_TOOLS_BINARY_DIR}" NO_DEFAULT_PATH) +find_program(M2C_TEST_OPT NAMES opt-16 opt + HINTS "${LLVM_TOOLS_BINARY_DIR}" NO_DEFAULT_PATH) +if(NOT M2C_TEST_CLANG OR NOT M2C_TEST_OPT) + message(FATAL_ERROR "clang/opt not found in ${LLVM_TOOLS_BINARY_DIR}") +endif() + +# The test executables only read and inspect bitcode. Link the LLVM shared +# library when the installation provides it (Debian/apt.llvm.org do): the +# static components pull in zstd::libzstd_shared, which needs its own +# find_package(). +if(TARGET LLVM) + set(M2C_TEST_LLVM_LIBS LLVM) +else() + find_package(zstd QUIET) + llvm_map_components_to_libnames(M2C_TEST_LLVM_LIBS core irreader bitreader support) +endif() + +include(GoogleTest) + +set(M2C_PASS_SRC "${PROJECT_SOURCE_DIR}/modules/backend/pass") + +function(m2c_pass_test NAME) + add_executable(${NAME} ${ARGN} "${M2C_PASS_SRC}/RuntimeABI.cpp") + target_include_directories(${NAME} PRIVATE ${LLVM_INCLUDE_DIRS}) + separate_arguments(_m2c_llvm_defs NATIVE_COMMAND "${LLVM_DEFINITIONS}") + target_compile_options(${NAME} PRIVATE ${_m2c_llvm_defs}) + target_compile_definitions(${NAME} PRIVATE + MAP2CHECK_ABI_MAPPING_TSV="${CMAKE_CURRENT_SOURCE_DIR}/data/abi-mapping.tsv" + M2C_TEST_INPUTS="${CMAKE_CURRENT_SOURCE_DIR}/inputs" + M2C_TEST_WORKDIR="${CMAKE_CURRENT_BINARY_DIR}/work-${NAME}" + M2C_TEST_CLANG="${M2C_TEST_CLANG}" + M2C_TEST_OPT="${M2C_TEST_OPT}" + M2C_PASS_PLUGIN_DIR="$" + M2C_PASS_PLUGIN_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") + target_link_libraries(${NAME} ${M2C_TEST_LLVM_LIBS} gtest_main) + # One ctest entry per test case (RuntimeABI.*, PassIR.*), so a failing hook + # is visible by name in the ctest summary. + gtest_discover_tests(${NAME} DISCOVERY_MODE PRE_TEST) +endfunction() + +m2c_pass_test(RuntimeABITest RuntimeABITest.cpp) + +# PassIRTest loads the pass plugins into the system opt. With sanitizers on, +# the plugins are ASan/UBSan-instrumented and opt is not, so they cannot be +# loaded ("Failed to load passes"); the IR checks then run in the regular +# build only. RuntimeABITest still runs under the sanitizers. +if(MAP2CHECK_ENABLE_SANITIZERS) + message(STATUS "PassIRTest skipped: sanitized pass plugins cannot load into opt") +else() + m2c_pass_test(PassIRTest PassIRTest.cpp) + # The plugins are loaded by opt at test time; build them before the test. + add_dependencies(PassIRTest + TrackBasicBlockPass AssertPass TargetPass LoopPredAssumePass Map2CheckLibrary) +endif() diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp new file mode 100644 index 000000000..a147cf363 --- /dev/null +++ b/tests/unit/pass/PassIRTest.cpp @@ -0,0 +1,380 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// Per-hook IR tests: compile a tiny C input with clang-16 -O0 -g -emit-llvm, +// run one pass plugin through opt-16, verify the module and check that the +// pass calls the core API of map2check-library (name, type, argument order). + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../../modules/backend/pass/RuntimeABI.hpp" +#include "../../../modules/frontend/utils/clang.hpp" + +using Map2Check::runtimeCall; +using Map2Check::RuntimeHook; + +namespace { + +llvm::LLVMContext& context() { + static llvm::LLVMContext ctx; + return ctx; +} + +std::string freshWorkDir() { + static unsigned counter = 0; + std::filesystem::path dir = std::filesystem::path(M2C_TEST_WORKDIR) / + ("run" + std::to_string(counter++)); + std::filesystem::remove_all(dir); + std::filesystem::create_directories(dir); + return dir.string(); +} + +int run(const std::string& command) { + int rc = std::system(command.c_str()); + if (rc != 0) llvm::errs() << "command failed (" << rc << "): " << command << "\n"; + return rc; +} + +/// Compiles inputs/ to bitcode as the tests do (-O0 -g, plus +/// `extraClangFlags`) and returns the path of the .bc file, or "" on error. +std::string compileInput(const std::string& dir, const std::string& input, + const std::string& extraClangFlags = "") { + std::string bc = dir + "/input.bc"; + std::ostringstream cmd; + cmd << M2C_TEST_CLANG << " -O0 -g -c -emit-llvm -Wno-everything " + << extraClangFlags << " -o " << bc << " " << M2C_TEST_INPUTS << "/" + << input << " 2> " << dir << "/clang.err"; + return run(cmd.str()) == 0 ? bc : ""; +} + +/// Runs plugin lib with -passes='' (plus `optFlags`) on +/// inputs/ and parses the result. +std::unique_ptr runPassOn(const std::string& plugin, + const std::string& pipeline, + const std::string& input, + const std::string& optFlags = "", + const std::string& clangFlags = "") { + std::string dir = freshWorkDir(); + std::string bc = compileInput(dir, input, clangFlags); + if (bc.empty()) return nullptr; + std::string out = dir + "/output.bc"; + std::ostringstream cmd; + cmd << M2C_TEST_OPT << " -load-pass-plugin=" << M2C_PASS_PLUGIN_DIR << "/lib" + << plugin << M2C_PASS_PLUGIN_SUFFIX << " " << optFlags << " -passes='" + << pipeline << "' " << bc << " -o " << out << " 2> " << dir + << "/opt.err"; + if (run(cmd.str()) != 0) return nullptr; + llvm::SMDiagnostic err; + std::unique_ptr m = llvm::parseIRFile(out, err, context()); + if (!m) err.print("PassIRTest", llvm::errs()); + return m; +} + +std::vector callsTo(llvm::Module& m, llvm::StringRef name) { + std::vector found; + for (llvm::Function& f : m) { + for (llvm::BasicBlock& bb : f) { + for (llvm::Instruction& i : bb) { + auto* call = llvm::dyn_cast(&i); + if (call == nullptr) continue; + auto* callee = llvm::dyn_cast( + call->getCalledOperand()->stripPointerCasts()); + if (callee != nullptr && callee->getName() == name) { + found.push_back(call); + } + } + } + } + return found; +} + +bool calls(llvm::Module& m, llvm::StringRef name) { + return !callsTo(m, name).empty(); +} + +/// Position of the first call to `name` in function `fn`, or -1. +int callIndex(llvm::Module& m, llvm::StringRef name, + llvm::StringRef fn = "__map2check_main__") { + llvm::Function* f = m.getFunction(fn); + if (f == nullptr) return -1; + int index = 0; + for (llvm::BasicBlock& bb : *f) { + for (llvm::Instruction& i : bb) { + if (auto* call = llvm::dyn_cast(&i)) { + auto* callee = llvm::dyn_cast( + call->getCalledOperand()->stripPointerCasts()); + if (callee != nullptr && callee->getName() == name) return index; + } + ++index; + } + } + return -1; +} + +/// The callee of every call to the hook is declared with the core type, and +/// each call passes arguments of exactly those types. +void expectCoreCalls(llvm::Module& m, RuntimeHook hook) { + Map2Check::RuntimeCall core = runtimeCall(hook, m.getContext()); + std::vector found = callsTo(m, core.name); + ASSERT_FALSE(found.empty()) << "no call to " << core.name; + llvm::Function* decl = m.getFunction(core.name); + ASSERT_NE(decl, nullptr); + EXPECT_EQ(decl->getFunctionType(), core.type) << core.name; + for (llvm::CallInst* call : found) { + EXPECT_EQ(call->getFunctionType(), core.type) << core.name; + ASSERT_EQ(call->arg_size(), core.type->getNumParams()) << core.name; + for (unsigned a = 0; a < call->arg_size(); ++a) { + EXPECT_EQ(call->getArgOperand(a)->getType(), core.type->getParamType(a)) + << core.name << " argument " << a; + } + } +} + +/// The string a `ptr` argument points to (a private global from +/// CreateGlobalStringPtr), or "" when it is not one. +std::string stringArg(llvm::Value* v) { + auto* gv = llvm::dyn_cast(v->stripPointerCasts()); + if (gv == nullptr || !gv->hasInitializer()) return ""; + auto* data = llvm::dyn_cast(gv->getInitializer()); + if (data == nullptr || !data->isCString()) return ""; + return data->getAsCString().str(); +} + +int64_t intArg(llvm::Value* v) { + auto* c = llvm::dyn_cast(v); + return c == nullptr ? -1 : c->getSExtValue(); +} + +#define ASSERT_VALID(m) \ + do { \ + ASSERT_NE((m), nullptr); \ + ASSERT_FALSE(llvm::verifyModule(*(m), &llvm::errs())); \ + } while (0) + +} // namespace + +// --------------------------------------------------------------------------- +// TrackBasicBlockPass -> TrackBB +// --------------------------------------------------------------------------- + +TEST(PassIR, TrackBasicBlockEmitsSaveBasicBlockLog) { + auto m = runPassOn("TrackBasicBlockPass", "track-basic-block", "track_bb.c"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::TrackBB); + EXPECT_FALSE(calls(*m, "map2check_track_bb")); + EXPECT_EQ(m->getFunction("map2check_track_bb"), nullptr); + for (llvm::CallInst* call : callsTo(*m, "map2check_save_basic_block_log")) { + // (line, function name): a source line and the enclosing function. + EXPECT_GT(intArg(call->getArgOperand(0)), 0); + EXPECT_EQ(stringArg(call->getArgOperand(1)), + call->getFunction()->getName().str()); + } + // Both functions are tracked. + bool inHelper = false; + bool inMain = false; + for (llvm::CallInst* call : callsTo(*m, "map2check_save_basic_block_log")) { + inHelper |= call->getFunction()->getName() == "helper"; + inMain |= call->getFunction()->getName() == "main"; + } + EXPECT_TRUE(inHelper); + EXPECT_TRUE(inMain); +} + +// --------------------------------------------------------------------------- +// AssertPass -> Assert +// --------------------------------------------------------------------------- + +TEST(PassIR, AssertEmitsIsValidAssertWithConditionLast) { + auto m = runPassOn("AssertPass", "assert-pass", "assert.c"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Assert); + EXPECT_FALSE(calls(*m, "map2check_assert")); + EXPECT_EQ(m->getFunction("map2check_assert"), nullptr); + std::vector found = callsTo(*m, "map2check_is_valid_assert"); + ASSERT_EQ(found.size(), 1u); + llvm::CallInst* call = found[0]; + // (line, function, expression): the condition moved from first to last. + EXPECT_EQ(intArg(call->getArgOperand(0)), 5); + EXPECT_EQ(stringArg(call->getArgOperand(1)), "main"); + std::vector asserts = callsTo(*m, "__VERIFIER_assert"); + ASSERT_EQ(asserts.size(), 1u); + EXPECT_EQ(call->getArgOperand(2), asserts[0]->getArgOperand(0)); +} + +TEST(PassIR, AssertFailEmitsIsValidAssertWithFalseCondition) { + auto m = runPassOn("AssertPass", "assert-pass", "assert_fail.c"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Assert); + std::vector found = callsTo(*m, "map2check_is_valid_assert"); + ASSERT_EQ(found.size(), 1u); + std::vector fails = callsTo(*m, "__assert_fail"); + ASSERT_EQ(fails.size(), 1u); + // line and function come from the __assert_fail arguments; condition is 0. + EXPECT_EQ(found[0]->getArgOperand(0), fails[0]->getArgOperand(2)); + EXPECT_EQ(found[0]->getArgOperand(1), fails[0]->getArgOperand(3)); + EXPECT_EQ(intArg(found[0]->getArgOperand(2)), 0); +} + +// --------------------------------------------------------------------------- +// TargetPass -> TargetReached +// --------------------------------------------------------------------------- + +TEST(PassIR, TargetEmitsReachTarget) { + auto m = runPassOn("TargetPass", "target-pass", "target.c", + "-function-name=reach_error"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::TargetReached); + EXPECT_FALSE(calls(*m, "map2check_target_function")); + EXPECT_EQ(m->getFunction("map2check_target_function"), nullptr); + std::vector found = callsTo(*m, "map2check_reach_target"); + ASSERT_EQ(found.size(), 1u); + // (function, scope, line), emitted right before the target call. + EXPECT_EQ(stringArg(found[0]->getArgOperand(0)), "main"); + EXPECT_EQ(intArg(found[0]->getArgOperand(2)), 6); + auto* next = llvm::dyn_cast(found[0]->getNextNode()); + ASSERT_NE(next, nullptr); + EXPECT_EQ(next->getCalledOperand()->stripPointerCasts()->getName(), + "reach_error"); +} + +// --------------------------------------------------------------------------- +// LoopPredAssumePass -> Assume +// --------------------------------------------------------------------------- + +TEST(PassIR, LoopPredAssumeEmitsVerifierAssumeWithZext) { + auto m = runPassOn("LoopPredAssumePass", "loop-pred-assume", "loop.c"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Assume); + EXPECT_FALSE(calls(*m, "map2check_assume_loop")); + EXPECT_EQ(m->getFunction("map2check_assume_loop"), nullptr); + std::vector found = callsTo(*m, "__VERIFIER_assume"); + ASSERT_EQ(found.size(), 1u); + // The i1 loop predicate is widened to the i32 the core takes. + auto* zext = llvm::dyn_cast(found[0]->getArgOperand(0)); + ASSERT_NE(zext, nullptr); + EXPECT_TRUE(zext->getSrcTy()->isIntegerTy(1)); + EXPECT_TRUE(llvm::isa(zext->getOperand(0))); +} + +// --------------------------------------------------------------------------- +// Map2CheckLibrary -> SetMode, Init, Success +// --------------------------------------------------------------------------- + +struct ModeCase { + const char* option; + int value; +}; + +class LibraryMode : public ::testing::TestWithParam {}; + +TEST_P(LibraryMode, EmitsSetModeBeforeInit) { + const ModeCase& mode = GetParam(); + auto m = runPassOn("Map2CheckLibrary", "map2check-library", "main.c", + std::string("-m2c-analysis-mode=") + mode.option); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::SetMode); + expectCoreCalls(*m, RuntimeHook::Init); + int setMode = callIndex(*m, "map2check_set_mode"); + int init = callIndex(*m, "map2check_init"); + ASSERT_GE(setMode, 0); + ASSERT_GE(init, 0); + EXPECT_LT(setMode, init); + std::vector found = callsTo(*m, "map2check_set_mode"); + ASSERT_EQ(found.size(), 1u); + EXPECT_EQ(intArg(found[0]->getArgOperand(0)), mode.value); +} + +INSTANTIATE_TEST_SUITE_P( + PassIR, LibraryMode, + ::testing::Values(ModeCase{"none", 0}, ModeCase{"memtrack", 1}, + ModeCase{"memcleanup", 2}, ModeCase{"overflow", 3}, + ModeCase{"assert", 4}, ModeCase{"target", 5}), + [](const ::testing::TestParamInfo& info) { + return std::string(info.param.option); + }); + +TEST(PassIR, LibraryInitTakesNoArgumentAndSuccessPrecedesExits) { + auto m = runPassOn("Map2CheckLibrary", "map2check-library", "main.c", + "-m2c-analysis-mode=memtrack"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Init); + expectCoreCalls(*m, RuntimeHook::Success); + EXPECT_EQ(m->getFunction("main"), nullptr); + ASSERT_NE(m->getFunction("__map2check_main__"), nullptr); + // One success before exit(1), one before the return. + EXPECT_EQ(callsTo(*m, "map2check_success").size(), 2u); + for (llvm::CallInst* call : callsTo(*m, "exit")) { + auto* prev = llvm::dyn_cast(call->getPrevNode()); + ASSERT_NE(prev, nullptr); + EXPECT_EQ(prev->getCalledOperand()->getName(), "map2check_success"); + } +} + +TEST(PassIR, LibraryDefaultModeIsNone) { + auto m = runPassOn("Map2CheckLibrary", "map2check-library", "main.c"); + ASSERT_VALID(m); + std::vector found = callsTo(*m, "map2check_set_mode"); + ASSERT_EQ(found.size(), 1u); + EXPECT_EQ(intArg(found[0]->getArgOperand(0)), 0); +} + +// --------------------------------------------------------------------------- +// D1 condition 11: the analysed program keeps a defined unwind. +// --------------------------------------------------------------------------- + +// Compiled with the flags the frontend uses for the program's bitcode, the +// renamed entry point is not nounwind, so the assume-rejection unwind of the +// library may cross it. +TEST(PassIR, ProgramBitcodeIsNotNounwind) { + auto m = runPassOn("Map2CheckLibrary", "map2check-library", "assume.c", + "-m2c-analysis-mode=assert", + Map2Check::kProgramUnwindFlags); + ASSERT_VALID(m); + llvm::Function* entry = m->getFunction("__map2check_main__"); + ASSERT_NE(entry, nullptr); + EXPECT_FALSE(entry->hasFnAttribute(llvm::Attribute::NoUnwind)); + llvm::Function* step = m->getFunction("step"); + ASSERT_NE(step, nullptr); + EXPECT_FALSE(step->hasFnAttribute(llvm::Attribute::NoUnwind)); +} + +// Control: without the flag clang does mark the entry nounwind, so the test +// above measures the flag and not the input. +TEST(PassIR, ProgramBitcodeWithoutFlagIsNounwind) { + auto m = runPassOn("Map2CheckLibrary", "map2check-library", "assume.c", + "-m2c-analysis-mode=assert"); + ASSERT_VALID(m); + llvm::Function* entry = m->getFunction("__map2check_main__"); + ASSERT_NE(entry, nullptr); + EXPECT_TRUE(entry->hasFnAttribute(llvm::Attribute::NoUnwind)); +} + +TEST(PassIR, ProgramUnwindFlagsNeverDisableUnwindTables) { + std::string flags = Map2Check::kProgramUnwindFlags; + EXPECT_NE(flags.find("-fexceptions"), std::string::npos); + EXPECT_EQ(flags.find("-fno-unwind-tables"), std::string::npos); + EXPECT_EQ(flags.find("-fno-asynchronous-unwind-tables"), std::string::npos); +} diff --git a/tests/unit/pass/RuntimeABITest.cpp b/tests/unit/pass/RuntimeABITest.cpp new file mode 100644 index 000000000..6b9446f23 --- /dev/null +++ b/tests/unit/pass/RuntimeABITest.cpp @@ -0,0 +1,180 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// The hook table of the passes against docs/cutover/abi-mapping.tsv: every +// emitted name is a core symbol of map2check-library, none is a name of the +// C runtime, and the LLVM types are the core signatures of map2check.h. + +#include + +#include +#include +#include + +#include +#include +#include + +#include "../../../modules/backend/pass/RuntimeABI.hpp" +#include "AbiMapping.hpp" + +using Map2Check::nonDetGenerator; +using Map2Check::nonDetLogger; +using Map2Check::RuntimeCall; +using Map2Check::runtimeCall; +using Map2Check::RuntimeHook; + +namespace { + +std::vector allHooks() { + std::vector hooks; + for (int h = 0; h <= static_cast(RuntimeHook::Last); ++h) { + hooks.push_back(static_cast(h)); + } + return hooks; +} + +// The C types of the nondet family in the mapping (map2check_non_det_). +const std::vector kNonDetTypes = { + "int", "unsigned", "char", "pointer", "long", "ushort", + "short", "ulong", "bool", "uchar", "pchar", "size_t", + "loff_t", "sector_t", "uint", "double"}; + +} // namespace + +TEST(RuntimeABI, NamesMatchMapping) { + llvm::LLVMContext ctx; + std::set core = m2c_test::loadCoreSymbols(MAP2CHECK_ABI_MAPPING_TSV); + ASSERT_FALSE(core.empty()); + for (RuntimeHook h : allHooks()) { + RuntimeCall call = runtimeCall(h, ctx); + ASSERT_NE(call.name, nullptr) << "hook " << static_cast(h); + ASSERT_NE(call.type, nullptr) << call.name; + EXPECT_TRUE(core.count(call.name)) << call.name; + } +} + +TEST(RuntimeABI, NoLegacyNameRemains) { + llvm::LLVMContext ctx; + std::set legacy = + m2c_test::loadLegacyOnlySymbols(MAP2CHECK_ABI_MAPPING_TSV); + ASSERT_TRUE(legacy.count("map2check_track_bb")); // the loader sees the C names + for (RuntimeHook h : allHooks()) { + EXPECT_FALSE(legacy.count(runtimeCall(h, ctx).name)) + << runtimeCall(h, ctx).name; + } + for (const std::string& t : kNonDetTypes) { + EXPECT_FALSE(legacy.count(nonDetGenerator(t))) << t; + EXPECT_FALSE(legacy.count(nonDetLogger(t))) << t; + } +} + +TEST(RuntimeABI, HookNamesAreDistinct) { + llvm::LLVMContext ctx; + std::set seen; + for (RuntimeHook h : allHooks()) { + EXPECT_TRUE(seen.insert(runtimeCall(h, ctx).name).second) + << runtimeCall(h, ctx).name; + } +} + +TEST(RuntimeABI, NonDetNamesMatchMapping) { + std::set core = m2c_test::loadCoreSymbols(MAP2CHECK_ABI_MAPPING_TSV); + for (const std::string& t : kNonDetTypes) { + EXPECT_TRUE(core.count(nonDetGenerator(t))) << nonDetGenerator(t); + EXPECT_TRUE(core.count(nonDetLogger(t))) << nonDetLogger(t); + } + // The mapping renames the "unsigned" generator to the uint one, but keeps a + // dedicated "unsigned" logger. + EXPECT_EQ(nonDetGenerator("unsigned"), "__VERIFIER_nondet_uint"); + EXPECT_EQ(nonDetLogger("unsigned"), "map2check_save_nondet_log_unsigned"); + EXPECT_EQ(nonDetGenerator("not_a_type"), ""); + EXPECT_EQ(nonDetLogger("not_a_type"), ""); +} + +// The mapping rows the generators replace: map2check_non_det_ and +// map2check_nondet_ resolve to exactly these core names. +TEST(RuntimeABI, NonDetNamesFollowTheirRows) { + for (const m2c_test::AbiRow& row : + m2c_test::loadAbiMapping(MAP2CHECK_ABI_MAPPING_TSV)) { + const std::string generatorPrefix = "map2check_non_det_"; + const std::string loggerPrefix = "map2check_nondet_"; + if (row.cSymbol.rfind(generatorPrefix, 0) == 0) { + ASSERT_EQ(row.coreSymbols.size(), 1u) << row.cSymbol; + EXPECT_EQ(nonDetGenerator(row.cSymbol.substr(generatorPrefix.size())), + row.coreSymbols[0]); + } else if (row.cSymbol.rfind(loggerPrefix, 0) == 0) { + ASSERT_EQ(row.coreSymbols.size(), 1u) << row.cSymbol; + EXPECT_EQ(nonDetLogger(row.cSymbol.substr(loggerPrefix.size())), + row.coreSymbols[0]); + } + } +} + +// The LLVM types are the core C signatures of map2check.h, lowered for +// x86-64: int32_t/uint32_t -> i32, int16_t -> i16, int64_t/uint64_t -> i64, +// pointers -> ptr. A pointer return (save_basic_block_log) stays ptr. +TEST(RuntimeABI, TypesMatchCoreSignatures) { + llvm::LLVMContext ctx; + llvm::Type* v = llvm::Type::getVoidTy(ctx); + llvm::Type* i16 = llvm::Type::getInt16Ty(ctx); + llvm::Type* i32 = llvm::Type::getInt32Ty(ctx); + llvm::Type* i64 = llvm::Type::getInt64Ty(ctx); + llvm::Type* p = llvm::PointerType::get(ctx, 0); + auto fn = [](llvm::Type* ret, std::vector params) { + return llvm::FunctionType::get(ret, params, false); + }; + struct Expected { + RuntimeHook hook; + const char* name; + llvm::FunctionType* type; + }; + const std::vector expected = { + {RuntimeHook::SetMode, "map2check_set_mode", fn(v, {i32})}, + {RuntimeHook::Init, "map2check_init", fn(v, {})}, + {RuntimeHook::Success, "map2check_success", fn(v, {})}, + {RuntimeHook::TrackBB, "map2check_save_basic_block_log", fn(p, {i32, p})}, + {RuntimeHook::TargetReached, "map2check_reach_target", fn(v, {p, i32, i32})}, + {RuntimeHook::Assert, "map2check_is_valid_assert", fn(v, {i32, p, i32})}, + {RuntimeHook::Assume, "__VERIFIER_assume", fn(v, {i32})}, + {RuntimeHook::BinopAdd, "map2check_binop_add_signed", fn(v, {i64, i64, i32, i32, p})}, + {RuntimeHook::BinopSub, "map2check_binop_sub_signed", fn(v, {i64, i64, i32, i32, p})}, + {RuntimeHook::BinopMul, "map2check_binop_mul_signed", fn(v, {i64, i64, i32, i32, p})}, + {RuntimeHook::BinopSDiv, "map2check_binop_div_signed", fn(v, {i64, i64, i32, i32, p})}, + {RuntimeHook::BinopSRem, "map2check_binop_rem_signed", fn(v, {i64, i64, i32, i32, p})}, + {RuntimeHook::Malloc, "map2check_map_malloc", fn(v, {p, i32})}, + {RuntimeHook::Calloc, "map2check_map_calloc", fn(v, {p, i32, i32})}, + {RuntimeHook::Alloca, "map2check_map_alloca", fn(v, {p, p, i32, i32, i32, i32})}, + {RuntimeHook::NonStaticAlloca, "map2check_map_non_static_alloca", fn(v, {p, p, i32, i32, i32, i32})}, + {RuntimeHook::FunctionAddr, "map2check_map_funct_address", fn(v, {p, p})}, + {RuntimeHook::StorePointer, "map2check_map_store_pointer", fn(v, {p, p, i32, p, i32, p})}, + {RuntimeHook::Load, "map2check_check_load", fn(v, {p, i32, i32, i32, p})}, + {RuntimeHook::CheckFree, "map2check_check_free", fn(v, {p, p, p, i32, i32, p})}, + {RuntimeHook::MapFree, "map2check_map_free", fn(v, {p, p, p, i32, i32, p})}, + {RuntimeHook::FreeResolved, "map2check_check_free_resolved_address", fn(v, {p, i32, p, i16})}, + {RuntimeHook::PosixMemalign, "map2check_map_posix_memalign", fn(v, {p, i32})}, + {RuntimeHook::WasmMalloc, "map2check_wasm_malloc", fn(v, {i64, i64})}, + {RuntimeHook::WasmFree, "map2check_wasm_free", fn(v, {i64, i64})}, + {RuntimeHook::WasmCheckAccess, "map2check_wasm_check_access", fn(v, {i64, i64})}, + }; + ASSERT_EQ(expected.size(), allHooks().size()); + for (const Expected& e : expected) { + RuntimeCall call = runtimeCall(e.hook, ctx); + EXPECT_STREQ(call.name, e.name); + EXPECT_EQ(call.type, e.type) << e.name; + } +} + +TEST(RuntimeABI, NonDetLoggerTypeIsUniform) { + llvm::LLVMContext ctx; + llvm::Type* i32 = llvm::Type::getInt32Ty(ctx); + llvm::Type* p = llvm::PointerType::get(ctx, 0); + // (line, scope, type_var, value*, function_name) -> non_det_log_t* + EXPECT_EQ(Map2Check::nonDetLoggerType(ctx), + llvm::FunctionType::get(p, {i32, i32, i32, p, p}, false)); +} diff --git a/tests/unit/pass/data/abi-mapping.tsv b/tests/unit/pass/data/abi-mapping.tsv new file mode 100644 index 000000000..c0ff09e20 --- /dev/null +++ b/tests/unit/pass/data/abi-mapping.tsv @@ -0,0 +1,77 @@ +# Vendored from map2check-library docs/cutover/abi-mapping.tsv at commit c8b3236ab198270bf9f1dab7da110158b5615b46 +# (file last changed in 3ad91d9ac9e8e6f37420d6a63e53d4888952d3b0). Task 3.4 replaces this copy with the one +# shipped in the v1.1.0-rc1 release tarball. Lines starting with # are ignored by the loader. +c_symbol core_symbol owner_task notes +map2check_init map2check_set_mode+map2check_init 2.3 C: (i32 isSvComp) → núcleo: set_mode(int32_t, valores de enum AnalysisMode 0-5; outro valor é ignorado)+init(void) (Task 2.3; o modo vinha do .bc ligado, caller.cpp:575-612); o arg int isSvComp é morto: Map2CheckFunctions.c:35 grava sv_comp e nenhum arquivo o lê +map2check_success map2check_success - C: () → núcleo: () (LibraryFunctions.hpp:48) +map2check_track_bb map2check_save_basic_block_log - C: (i32 line,ptr fn) → núcleo: (line:i32,fn); mesma ordem (LibraryFunctions.hpp:54, ffi.rs:111); retorno do núcleo é bbtrack_log_t*, ignorado +map2check_target_function map2check_reach_target 2.3 C: (ptr fn,i32 scope,i32 line) (TargetPass.cpp:89); C runtime grava TARGET_REACHED e aborta (Map2CheckFunctions.c:61-65); núcleo: map2check_reach_target(const char*,i32,i32) (Task 2.3) registra Reachability (=TARGET-REACHED) em qualquer modo, ignora scope e retorna; C encerra na primeira violação; núcleo registra e continua (SD-03/#36, SD-15); término do processo é a Task 2.4 +map2check_assert map2check_is_valid_assert - C: (i32 cond,i32 line,ptr fn) (AssertPass.cpp:23) → núcleo: (line:i32,fn,expression:i32); ORDEM DIFERENTE: cond passa de primeiro a último; C encerra na primeira violação; núcleo registra e continua; SD-03/#36 (Task 2.1) (map2check_error em AnalysisModeAssert.c:20); is_valid_assert imprime o JSON na hora sem encerrar, então um map2check_success posterior imprime um segundo relatório +map2check_assume __VERIFIER_assume - C: (i32) (NonDetPass.cpp:94) → núcleo: (i32 condition); núcleo faz exit(0) se 0 +map2check_assume_loop __VERIFIER_assume - C: (i1) (LoopPredAssumePass.cpp:28; o C runtime recebe char e faz cast para int) → núcleo: (i32); o passe deve emitir zext i1→i32 +map2check_crab_assume __VERIFIER_assume - idem; sem getOrInsertFunction: nasce do rename de verifier.assume (NonDetPass.cpp:216), o tipo do arg segue o chamador; C runtime recebe char (Map2CheckFunctions.c:46) +map2check_binop_add map2check_binop_add_signed 2.5 C: (i64 a,i64 b,i32 width,i32 line,i32 scope,ptr fn) (OperationsFunctions.hpp:74) → núcleo novo: (a:int64,b:int64,bits:uint32,line:uint32,fn); o núcleo não recebe scope e passa a honrar a largura que o passe já envia; overflow reporta OVERFLOW (AnalysisModeOverflow.c:197-206); C encerra na primeira violação (overflowError, AnalysisModeOverflow.c:185) (map2check_error, Map2CheckFunctions.c:72); núcleo registra e continua; SD-03/#36 (Task 2.1) +map2check_binop_add_uint - - C é no-op deliberado (AnalysisModeOverflow.c:219: unsigned wraparound is not overflow); o passe deixa de emitir (OperationsFunctions.hpp:77) +map2check_binop_sub map2check_binop_sub_signed 2.5 C: (i64 a,i64 b,i32 width,i32 line,i32 scope,ptr fn) (OperationsFunctions.hpp:80) → núcleo novo: (a:int64,b:int64,bits:uint32,line:uint32,fn); o núcleo não recebe scope e passa a honrar a largura que o passe já envia; overflow reporta OVERFLOW (AnalysisModeOverflow.c:197-206); C encerra na primeira violação (overflowError, AnalysisModeOverflow.c:185) (map2check_error, Map2CheckFunctions.c:72); núcleo registra e continua; SD-03/#36 (Task 2.1) +map2check_binop_sub_uint - - C é no-op deliberado (AnalysisModeOverflow.c:219: unsigned wraparound is not overflow); o passe deixa de emitir (OperationsFunctions.hpp:83) +map2check_binop_mul map2check_binop_mul_signed 2.5 C: (i64 a,i64 b,i32 width,i32 line,i32 scope,ptr fn) (OperationsFunctions.hpp:86) → núcleo novo: (a:int64,b:int64,bits:uint32,line:uint32,fn); o núcleo não recebe scope e passa a honrar a largura que o passe já envia; overflow reporta OVERFLOW (AnalysisModeOverflow.c:197-206); C encerra na primeira violação (overflowError, AnalysisModeOverflow.c:185) (map2check_error, Map2CheckFunctions.c:72); núcleo registra e continua; SD-03/#36 (Task 2.1) +map2check_binop_mul_uint - - C é no-op deliberado (AnalysisModeOverflow.c:219: unsigned wraparound is not overflow); o passe deixa de emitir (OperationsFunctions.hpp:89) +map2check_binop_sdiv map2check_binop_div_signed 2.5 C: (i64 a,i64 b,i32 width,i32 line,i32 scope,ptr fn) (OperationsFunctions.hpp:92) → núcleo novo: (a:int64,b:int64,bits:uint32,line:uint32,fn); o núcleo não recebe scope e passa a honrar a largura que o passe já envia; divisão por zero reporta FALSE-DIVBYZERO (novo ViolatedProperty, owner 2.5), não OVERFLOW, como no C (AnalysisModeOverflow.c:252 e :266, divisionByZeroError :191); MIN/-1 reporta OVERFLOW; C encerra na primeira violação (overflowError, AnalysisModeOverflow.c:185) (map2check_error, Map2CheckFunctions.c:72); núcleo registra e continua; SD-03/#36 (Task 2.1) +map2check_binop_srem map2check_binop_rem_signed 2.5 C: (i64 a,i64 b,i32 width,i32 line,i32 scope,ptr fn) (OperationsFunctions.hpp:95) → núcleo novo: (a:int64,b:int64,bits:uint32,line:uint32,fn); o núcleo não recebe scope e passa a honrar a largura que o passe já envia; divisão por zero reporta FALSE-DIVBYZERO (novo ViolatedProperty, owner 2.5), não OVERFLOW, como no C (AnalysisModeOverflow.c:252 e :266, divisionByZeroError :191); MIN/-1 reporta OVERFLOW; C encerra na primeira violação (overflowError, AnalysisModeOverflow.c:185) (map2check_error, Map2CheckFunctions.c:72); núcleo registra e continua; SD-03/#36 (Task 2.1) +map2check_malloc map2check_map_malloc - C: (ptr,i64 size) (MemoryTrackPass.cpp:789) → núcleo: (ptr,size:i32); size estreita de i64 para i32 +map2check_calloc map2check_map_calloc - C: (ptr,i64 qty,i64 size) → núcleo: (ptr,qty:i32,size:i32); mesma ordem, estreita para i32 +map2check_alloca map2check_map_alloca - C: (ptr name,ptr addr,i64 size,i64 size_primitive,i64 line,i64 scope) (MemoryTrackPass.cpp:802) → núcleo: (name,addr,size:i32,size_primitive:i32,line:i32,scope:i32); mesma ordem, estreita para i32 +map2check_non_static_alloca map2check_map_non_static_alloca - SD-12 (#38, corrigido): o núcleo agora toma size como contagem de elementos e registra slot estático de size*size_primitive bytes (nunca vazamento), como o C; assinatura do núcleo mantida, igual a map2check_alloca (MemoryTrackPass.cpp:808); C multiplica size*size_primitive (AnalysisModeMemtrack.c:370) +map2check_function map2check_map_funct_address - C: (ptr name,ptr addr) (MemoryTrackPass.cpp:814) → núcleo: (var_name,ptr_address); igual +map2check_add_store_pointer map2check_map_store_pointer - C: (ptr var,ptr value,i64 scope,ptr name,i64 line,ptr fn) (MemoryTrackPass.cpp:779) → núcleo: (var_address,value,scope:u32,var_name,line:i32,fn); mesma ordem +map2check_load map2check_check_load - C: (ptr,i64 size) (MemoryTrackPass.cpp:770) → núcleo: (ptr,line:i32,scope:u32,size:i32,fn); o passe passa a emitir linha, escopo e função (DebugInfo); C encerra na primeira violação; núcleo registra e continua; SD-03/#36 (Task 2.1) (a flag ERROR_DEREF de AnalysisModeMemtrack.c:158 só encerra em check_deref); check_load grava a violação direto +map2check_check_deref - - check_load já registra a violação (ffi.rs:894, LoadChecker); C: (i64 line,ptr fn) (MemoryTrackPass.cpp:785) só lê a flag ERROR_DEREF e encerra (AnalysisModeMemtrack.c:297); o passe deixa de emitir; C encerra na primeira violação; núcleo registra e continua; SD-03/#36 (Task 2.1) +map2check_free map2check_check_free+map2check_map_free - C: (ptr name,ptr var_slot,i64 scope,i64 line,ptr fn) (MemoryTrackPass.cpp:818) → núcleo (ambos, Task 2.5): (name,var_slot,ptr,scope:u32,line:u32,fn), var_slot no lugar em que o passe já o envia e ptr = *var_slot; o núcleo é chaveado no endereço de heap carregado, então o passe carrega *var_slot antes da chamada e a ordem é check_free depois map_free; var_slot só nomeia a variável na linha FREE de list_log.csv (AnalysisModeMemtrack.c:339-347), e check_free guarda essa linha quando falha, como o C, que a acrescenta antes de checar (:346-358); golden FALSE-FREE; o passe não chama nenhum dos dois se o valor carregado for NULL, como o C (AnalysisModeMemtrack.c:342); C encerra na primeira violação; núcleo registra e continua; SD-03/#36 (Task 2.1) (AnalysisModeMemtrack.c:352) +map2check_free_resolved_address map2check_check_free_resolved_address - chamada única; registra a liberação quando a checagem passa (como o C, :178-182); check_free não registra — o passe chama map_free depois; vale também para a instrumentação de realloc (MemoryTrackPass.cpp:169-182); SD-06 (#37, corrigido): endereço sem registro reporta MEMSAFETY_FREE, como is_invalid_free (ListLog.c:95-118); SD-13: free de ponteiro nunca armazenado é válido no núcleo e FALSE_FREE no C; C: (ptr,i64 line,ptr fn,i1 nullValid) (MemoryTrackPass.cpp:774) → núcleo: (ptr,line:u32,fn,is_null_valid:i16); i1 passa a i16 (zext); C encerra na primeira violação; núcleo registra e continua; SD-03/#36 (Task 2.1) (AnalysisModeMemtrack.c:170) +map2check_posix map2check_map_posix_memalign 2.5 chamado em MemoryTrackPass.cpp:120 para posix_memalign; não é obsoleto; C: (ptr,i64 size) (MemoryTrackPass.cpp:793); o C runtime desreferencia ptr (void**) e registra malloc+store_pointer (AnalysisModeMemtrack.c:327-333); núcleo: (ptr_address,size:i32), lê o bloco de *ptr_address e grava malloc e store_pointer(ptr_address,bloco,1,"pointer",1,"cocoiso") como o C; o passe trunca o tamanho para i32 (coerceToParamType); golden POSIX-MEMALIGN +map2check_wasm_malloc map2check_wasm_malloc 2.8 C: (i64,i64) (MemoryTrackPass.cpp:825); núcleo igual (u64 offset,u64 size), feature wasm (Task 2.8): AnalysisModeMemtrack.c:385-397 +map2check_wasm_free map2check_wasm_free 2.8 C: (i64,i64) (MemoryTrackPass.cpp:829); núcleo (u64 offset,i64 line), feature wasm: AnalysisModeMemtrack.c:399-407; offset desconhecido reporta MEMSAFETY_FREE na linha (FALSE_FREE) +map2check_wasm_check_access map2check_wasm_check_access 2.8 C: (i64,i64) (MemoryTrackPass.cpp:833); núcleo igual (u64 offset,u64 access_size), feature wasm: AnalysisModeMemtrack.c:416-423; acesso fora de bloco vivo reporta OVERFLOW, linha 0, como o C (FALSE_OVERFLOW; SD-19); só ativo nos modos que checam memória +__map2check_main__ __map2check_main__ - definido pelo programa instrumentado, não pela biblioteca +overflowError - - morto: errorLines sempre vazio (OverflowPass.cpp:226); C: (i32 line,ptr fn) (OperationsFunctions.hpp:98) reporta FALSE_OVERFLOW e encerra (AnalysisModeOverflow.c:185) +__VERIFIER_assert __VERIFIER_assert - +__VERIFIER_assume __VERIFIER_assume - +__VERIFIER_error __VERIFIER_error - +__VERIFIER_nondet_char __VERIFIER_nondet_char - só comparado pelo nome (exclusões em TrackBasicBlockPass.cpp:113, OverflowPass.cpp:59); não emitido como chamada +__VERIFIER_nondet_int __VERIFIER_nondet_int - só comparado pelo nome (exclusões em TrackBasicBlockPass.cpp:113, OverflowPass.cpp:59); não emitido como chamada +__VERIFIER_nondet_long __VERIFIER_nondet_long - só comparado pelo nome (exclusões em TrackBasicBlockPass.cpp:113, OverflowPass.cpp:59); não emitido como chamada +__VERIFIER_nondet_pointer __VERIFIER_nondet_pointer - só comparado pelo nome (exclusões em TrackBasicBlockPass.cpp:113, OverflowPass.cpp:59); não emitido como chamada +__VERIFIER_nondet_uint __VERIFIER_nondet_uint - só comparado pelo nome (exclusões em TrackBasicBlockPass.cpp:113, OverflowPass.cpp:59); não emitido como chamada +__VERIFIER_nondet_ushort __VERIFIER_nondet_ushort - só comparado pelo nome (exclusões em TrackBasicBlockPass.cpp:113, OverflowPass.cpp:59); não emitido como chamada +map2check_non_det_int __VERIFIER_nondet_int - tipos de NonDetPass.cpp:155-171 (CALL_IF_HELPER) e NonDetPass.hpp:82-97; C: renomeia a chamada __VERIFIER_nondet_ para map2check_non_det_ (NonDetPass.cpp:186) → núcleo: __VERIFIER_nondet_() sem args +map2check_non_det_unsigned __VERIFIER_nondet_uint - idem primeira linha da família +map2check_non_det_char __VERIFIER_nondet_char - idem primeira linha da família +map2check_non_det_pointer __VERIFIER_nondet_pointer - idem primeira linha da família +map2check_non_det_long __VERIFIER_nondet_long - idem primeira linha da família +map2check_non_det_ushort __VERIFIER_nondet_ushort - idem primeira linha da família +map2check_non_det_short __VERIFIER_nondet_short - idem primeira linha da família +map2check_non_det_ulong __VERIFIER_nondet_ulong - idem primeira linha da família +map2check_non_det_bool __VERIFIER_nondet_bool - idem primeira linha da família +map2check_non_det_uchar __VERIFIER_nondet_uchar - idem primeira linha da família +map2check_non_det_pchar __VERIFIER_nondet_pchar 2.5 idem primeira linha da família; sem equivalente núcleo; export novo +map2check_non_det_size_t __VERIFIER_nondet_size_t - idem primeira linha da família +map2check_non_det_loff_t __VERIFIER_nondet_loff_t 2.5 idem primeira linha da família; sem equivalente núcleo; export novo +map2check_non_det_sector_t __VERIFIER_nondet_sector_t 2.5 idem primeira linha da família; sem equivalente núcleo; export novo +map2check_non_det_uint __VERIFIER_nondet_uint - idem primeira linha da família +map2check_non_det_double __VERIFIER_nondet_double - idem primeira linha da família +map2check_nondet_int map2check_save_nondet_log_int - tipos de NonDetFunctions.hpp:77-92 (NON_DET_FUNCTIONS_HELPER); C: (i32 line,i32 scope,i32 value,ptr fn) (double: valor double; pointer: ptrtoint; char/short/long/etc.: cast para i32) → núcleo (ffi.rs:305): (line:i32,scope:i32,type_var:i32,value:T*,function_name) → non_det_log_t*; o passe grava o valor num alloca e passa o ponteiro + type_var +map2check_nondet_unsigned map2check_save_nondet_log_unsigned 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_char map2check_save_nondet_log_char - idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var +map2check_nondet_pointer map2check_save_nondet_log_pointer 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_long map2check_save_nondet_log_long - idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var +map2check_nondet_ushort map2check_save_nondet_log_ushort 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_short map2check_save_nondet_log_short 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_ulong map2check_save_nondet_log_ulong 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_bool map2check_save_nondet_log_bool 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_uchar map2check_save_nondet_log_uchar 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_pchar map2check_save_nondet_log_pchar 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_size_t map2check_save_nondet_log_size_t 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_loff_t map2check_save_nondet_log_loff_t 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_sector_t map2check_save_nondet_log_sector_t 2.5 idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var; sem equivalente núcleo; export novo +map2check_nondet_uint map2check_save_nondet_log_uint - idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var +map2check_nondet_double map2check_save_nondet_log_double - idem primeira linha da família; o passe grava o valor num alloca e passa o ponteiro + type_var diff --git a/tests/unit/pass/inputs/assert.c b/tests/unit/pass/inputs/assert.c new file mode 100644 index 000000000..66bb2cac1 --- /dev/null +++ b/tests/unit/pass/inputs/assert.c @@ -0,0 +1,7 @@ +extern int __VERIFIER_nondet_int(void); +extern void __VERIFIER_assert(int cond); +int main(void) { + int x = __VERIFIER_nondet_int(); + __VERIFIER_assert(x != 42); + return 0; +} diff --git a/tests/unit/pass/inputs/assert_fail.c b/tests/unit/pass/inputs/assert_fail.c new file mode 100644 index 000000000..caa22ea16 --- /dev/null +++ b/tests/unit/pass/inputs/assert_fail.c @@ -0,0 +1,7 @@ +#include +extern int __VERIFIER_nondet_int(void); +int main(void) { + int x = __VERIFIER_nondet_int(); + assert(x != 42); + return 0; +} diff --git a/tests/unit/pass/inputs/assume.c b/tests/unit/pass/inputs/assume.c new file mode 100644 index 000000000..4dce45158 --- /dev/null +++ b/tests/unit/pass/inputs/assume.c @@ -0,0 +1,13 @@ +extern int __VERIFIER_nondet_int(void); +extern void __VERIFIER_assume(int cond); +extern void __VERIFIER_assert(int cond); +static int step(int x) { + __VERIFIER_assume(x > 0); + return x - 1; +} +int main(void) { + int x = __VERIFIER_nondet_int(); + int y = step(x); + __VERIFIER_assert(y >= 0); + return 0; +} diff --git a/tests/unit/pass/inputs/loop.c b/tests/unit/pass/inputs/loop.c new file mode 100644 index 000000000..364021725 --- /dev/null +++ b/tests/unit/pass/inputs/loop.c @@ -0,0 +1,9 @@ +extern int __VERIFIER_nondet_int(void); +int main(void) { + int n = __VERIFIER_nondet_int(); + int i = 0; + while (i < n) { + i++; + } + return i; +} diff --git a/tests/unit/pass/inputs/main.c b/tests/unit/pass/inputs/main.c new file mode 100644 index 000000000..d53e31c08 --- /dev/null +++ b/tests/unit/pass/inputs/main.c @@ -0,0 +1,9 @@ +#include +extern int __VERIFIER_nondet_int(void); +int main(void) { + int x = __VERIFIER_nondet_int(); + if (x == 1) { + exit(1); + } + return 0; +} diff --git a/tests/unit/pass/inputs/target.c b/tests/unit/pass/inputs/target.c new file mode 100644 index 000000000..ef269a475 --- /dev/null +++ b/tests/unit/pass/inputs/target.c @@ -0,0 +1,9 @@ +extern int __VERIFIER_nondet_int(void); +extern void reach_error(void); +int main(void) { + int x = __VERIFIER_nondet_int(); + if (x == 42) { + reach_error(); + } + return 0; +} diff --git a/tests/unit/pass/inputs/track_bb.c b/tests/unit/pass/inputs/track_bb.c new file mode 100644 index 000000000..8df488318 --- /dev/null +++ b/tests/unit/pass/inputs/track_bb.c @@ -0,0 +1,9 @@ +extern int __VERIFIER_nondet_int(void); +int helper(int x) { return x + 1; } +int main(void) { + int x = __VERIFIER_nondet_int(); + if (x > 3) { + x = helper(x); + } + return x; +} From 2f398435cd556d5e44d24756b3b34464ef11fee6 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:53:57 -0400 Subject: [PATCH 08/44] feat(pass): emit map2check_save_basic_block_log from TrackBasicBlockPass TrackBasicBlockPass calls the core map2check_save_basic_block_log(line, function) through RuntimeHook::TrackBB instead of the C runtime's map2check_track_bb; the argument order is unchanged and the returned bbtrack_log_t* is ignored. The plugin could not be loaded by opt: it referenced SourceCodeHelper::getLine without linking tools.cpp, and its default constructor (the one the plugin registration uses) leaves the source helper null, which the empty-line walk dereferenced. Link tools.cpp and log.cpp into the plugin and treat every line as non-empty when there is no source helper. --- modules/backend/pass/CMakeLists.txt | 5 +++++ modules/backend/pass/TrackBasicBlockPass.cpp | 17 +++++++++++------ modules/backend/pass/TrackBasicBlockPass.hpp | 3 +-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/modules/backend/pass/CMakeLists.txt b/modules/backend/pass/CMakeLists.txt index 42074679a..1fbaabc04 100755 --- a/modules/backend/pass/CMakeLists.txt +++ b/modules/backend/pass/CMakeLists.txt @@ -28,3 +28,8 @@ foreach(F ${MAP2CHECK_PASS_LIB}) install(TARGETS ${F} DESTINATION lib) endforeach() +# TrackBasicBlockPass reads the C source through SourceCodeHelper; without +# these objects the plugin fails to load (undefined SourceCodeHelper::getLine). +target_sources(TrackBasicBlockPass PRIVATE + ${PROJECT_SOURCE_DIR}/modules/frontend/utils/tools.cpp + ${PROJECT_SOURCE_DIR}/modules/frontend/utils/log.cpp) diff --git a/modules/backend/pass/TrackBasicBlockPass.cpp b/modules/backend/pass/TrackBasicBlockPass.cpp index 31232a8a4..61ca2a523 100644 --- a/modules/backend/pass/TrackBasicBlockPass.cpp +++ b/modules/backend/pass/TrackBasicBlockPass.cpp @@ -16,6 +16,8 @@ #include #include +#include "RuntimeABI.hpp" + using llvm::CallInst; using llvm::dyn_cast; using llvm::IRBuilder; @@ -35,7 +37,8 @@ PreservedAnalyses TrackBasicBlockPass::run(Function& F, llvm::FunctionAnalysisManager& AM) { this->Ctx = &F.getContext(); this->currentFunction = &F; - this->libraryFunctions = make_unique(&F, &F.getContext()); + this->trackBB = + Map2Check::getOrInsertRuntime(*F.getParent(), Map2Check::RuntimeHook::TrackBB); int countBB = 1; for (auto& B : F) { @@ -221,7 +224,10 @@ void TrackBasicBlockPass::runOnBasicBlock(BasicBlock& B, LLVMContext* Ctx) { unsigned countInst = 1; DebugInfo debugInfoAaEmpty(this->Ctx, BBIteratorToInst(this->st_lastBlockInst)); - if (this->sourceCodeHelper->getLine(debugInfoAaEmpty.getLineNumberInt()) + // Without the C source (plugin built with the default constructor, as + // opt does) every line counts as non-empty. + if (this->sourceCodeHelper != nullptr && + this->sourceCodeHelper->getLine(debugInfoAaEmpty.getLineNumberInt()) .empty()) { flagEmpty = true; } @@ -292,9 +298,6 @@ void TrackBasicBlockPass::instrumentInstBB(BasicBlock::iterator& iT) { iT++; } - // Twine track_bb("map2check_track_bb"); - // Function *calleeFunction; - // calleeFunction->setName(track_bb); // errs() << "inst 1 \n"; IRBuilder<> builder(BBIteratorToInst(iT)); @@ -305,9 +308,11 @@ void TrackBasicBlockPass::instrumentInstBB(BasicBlock::iterator& iT) { // errs() << *debugInfo.getLineNumberValue() << "\n"; // errs() << function_llvm->getName() << "\n"; + // map2check_save_basic_block_log(line, function); the returned + // bbtrack_log_t* is ignored. Value* args[] = {debugInfo.getLineNumberValue(), function_llvm}; - builder.CreateCall(this->libraryFunctions->getTrackBBFunction(), args); + builder.CreateCall(this->trackBB, args); // errs() << "inst 3 \n"; } diff --git a/modules/backend/pass/TrackBasicBlockPass.hpp b/modules/backend/pass/TrackBasicBlockPass.hpp index 85a847a1f..3b942e8e0 100644 --- a/modules/backend/pass/TrackBasicBlockPass.hpp +++ b/modules/backend/pass/TrackBasicBlockPass.hpp @@ -30,7 +30,6 @@ #include "../../frontend/utils/tools.hpp" #include "DebugInfo.hpp" -#include "LibraryFunctions.hpp" // using namespace llvm; namespace Tools = Map2Check; @@ -63,7 +62,7 @@ struct TrackBasicBlockPass : public llvm::PassInfoMixin { private: std::unique_ptr sourceCodeHelper; std::string c_program_path; - std::unique_ptr libraryFunctions; + llvm::FunctionCallee trackBB; bool initializedFunctionName = false; bool isUnreachableInst = false; BasicBlock::iterator st_lastBlockInst; From 233df8cd07fdff647770ba64a2485e71c3a535a8 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:54:37 -0400 Subject: [PATCH 09/44] feat(pass): emit map2check_is_valid_assert from AssertPass AssertPass calls the core map2check_is_valid_assert(line, function, expression) through RuntimeHook::Assert instead of the C runtime's map2check_assert(cond, line, function): the condition moves from first to last. __assert_fail still passes its line and function with a constant-false condition. A __VERIFIER_assert declared with a non-i32 integer parameter passes "condition != 0" widened to i32. --- modules/backend/pass/AssertPass.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/modules/backend/pass/AssertPass.cpp b/modules/backend/pass/AssertPass.cpp index 209280b36..7a3f6a23f 100755 --- a/modules/backend/pass/AssertPass.cpp +++ b/modules/backend/pass/AssertPass.cpp @@ -13,6 +13,8 @@ #include #include +#include "RuntimeABI.hpp" + using llvm::dyn_cast; using llvm::IRBuilder; using llvm::FunctionCallee; @@ -20,10 +22,8 @@ using llvm::PassPluginLibraryInfo; PreservedAnalyses AssertPass::run(Function& F, llvm::FunctionAnalysisManager& AM) { - this->map2check_assert = F.getParent()->getOrInsertFunction( - "map2check_assert", Type::getVoidTy(F.getContext()), - Type::getInt32Ty(F.getContext()), Type::getInt32Ty(F.getContext()), - PointerType::get(F.getContext(), 0)); + this->map2check_assert = Map2Check::getOrInsertRuntime( + *F.getParent(), Map2Check::RuntimeHook::Assert); Function::iterator functionIterator = F.begin(); BasicBlock::iterator instructionIterator = functionIterator->begin(); @@ -47,10 +47,19 @@ void AssertPass::instrumentAssert(CallInst* assertInst, LLVMContext* Ctx) { DebugInfo debugInfo(Ctx, assertInst); Value* condition = assertInst->getArgOperand(0); + // The core takes an i32; a program that declares __VERIFIER_assert with + // another integer parameter type still passes "condition != 0". + if (condition->getType()->isIntegerTy() && + !condition->getType()->isIntegerTy(32)) { + condition = builder.CreateZExt( + builder.CreateIsNotNull(condition), Type::getInt32Ty(*Ctx)); + } Value* function_llvm = builder.CreateGlobalStringPtr(assertInst->getFunction()->getName()); - Value* args[] = {condition, debugInfo.getLineNumberValue(), function_llvm}; + // map2check_is_valid_assert(line, function, expression): the condition + // goes last in the core API. + Value* args[] = {debugInfo.getLineNumberValue(), function_llvm, condition}; builder.CreateCall(this->map2check_assert, args); } @@ -65,7 +74,7 @@ void AssertPass::instrumentAssertFail(CallInst* assertInst, LLVMContext* Ctx) { Value* line = assertInst->getArgOperand(2); Value* function_llvm = assertInst->getArgOperand(3); - Value* args[] = {condition, line, function_llvm}; + Value* args[] = {line, function_llvm, condition}; builder.CreateCall(this->map2check_assert, args); } From 1c7bd5358e54383040b24b2881e2e05868f3fd34 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:54:53 -0400 Subject: [PATCH 10/44] feat(pass): emit map2check_reach_target from TargetPass TargetPass calls the core map2check_reach_target(function, scope, line) through RuntimeHook::TargetReached instead of the C runtime's map2check_target_function; the argument order is unchanged. The core records TARGET-REACHED and returns instead of aborting. --- modules/backend/pass/TargetPass.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/backend/pass/TargetPass.cpp b/modules/backend/pass/TargetPass.cpp index de403a9b4..19d182ec8 100644 --- a/modules/backend/pass/TargetPass.cpp +++ b/modules/backend/pass/TargetPass.cpp @@ -15,6 +15,8 @@ #include #include +#include "RuntimeABI.hpp" + namespace { /// Counts the call sites TargetPass will match, across the whole module. @@ -86,10 +88,8 @@ PreservedAnalyses TargetPass::run(Function& F, } } - this->targetFunctionMap2Check = F.getParent()->getOrInsertFunction( - "map2check_target_function", Type::getVoidTy(F.getContext()), - PointerType::get(F.getContext(), 0), Type::getInt32Ty(F.getContext()), - Type::getInt32Ty(F.getContext())); + this->targetFunctionMap2Check = Map2Check::getOrInsertRuntime( + *F.getParent(), Map2Check::RuntimeHook::TargetReached); Function::iterator functionIterator = F.begin(); BasicBlock::iterator instructionIterator = functionIterator->begin(); @@ -132,6 +132,8 @@ void TargetPass::instrumentErrorInstruction(CallInst* callInst, DebugInfo debugInfo(Ctx, callInst); + // map2check_reach_target(function, scope, line): records TARGET-REACHED and + // returns; the core ignores scope. Value* args[] = {name_llvm, debugInfo.getScopeNumberValue(), debugInfo.getLineNumberValue()}; From a5dbf404632d3c16d2d77558ee9b65554517de64 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:55:08 -0400 Subject: [PATCH 11/44] feat(pass): emit __VERIFIER_assume from LoopPredAssumePass LoopPredAssumePass calls the core __VERIFIER_assume(i32) through RuntimeHook::Assume instead of the C runtime's map2check_assume_loop(i1): the negated loop predicate is zero-extended from i1 to i32. --- modules/backend/pass/LoopPredAssumePass.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/backend/pass/LoopPredAssumePass.cpp b/modules/backend/pass/LoopPredAssumePass.cpp index c203fec46..6291f1eb3 100644 --- a/modules/backend/pass/LoopPredAssumePass.cpp +++ b/modules/backend/pass/LoopPredAssumePass.cpp @@ -13,6 +13,8 @@ #include #include +#include "RuntimeABI.hpp" + using llvm::IRBuilder; namespace { @@ -24,10 +26,8 @@ inline Instruction* BBIteratorToInst(BasicBlock::iterator i) { void LoopPredAssumePass::getConditionInLoop(Loop* L) { BasicBlock* header = L->getHeader(); - this->map2check_assume = - header->getParent()->getParent()->getOrInsertFunction( - "map2check_assume_loop", Type::getVoidTy(header->getContext()), - Type::getInt1Ty(header->getContext())); + this->map2check_assume = Map2Check::getOrInsertRuntime( + *header->getParent()->getParent(), Map2Check::RuntimeHook::Assume); if (BranchInst* bi = dyn_cast(header->getTerminator())) { if (bi->isConditional()) { Value* loopCond = bi->getCondition(); @@ -50,7 +50,9 @@ void LoopPredAssumePass::getConditionInLoop(Loop* L) { IRBuilder<> builder(BBIteratorToInst(iT)); - Value* args[] = {new_loop_cond}; + // __VERIFIER_assume takes an i32; the loop predicate is an i1. + Value* args[] = {builder.CreateZExt( + new_loop_cond, Type::getInt32Ty(header->getContext()))}; builder.CreateCall(this->map2check_assume, args); } } From c6fdcf984c1effded64958bffa66e84ab82b943e Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:56:16 -0400 Subject: [PATCH 12/44] feat(pass): emit map2check_set_mode before map2check_init in Map2CheckLibrary Map2CheckLibrary calls the core map2check_set_mode() and then map2check_init() at the entry, and map2check_success() before returns, exit and abort, through RuntimeHook::SetMode/Init/Success. init no longer takes the dead isSvComp argument of the C runtime. The mode comes from the new -m2c-analysis-mode option (none, memtrack, memcleanup, overflow, assert, target; AnalysisMode values 0-5, default none). The frontend passes it for every run: cover-branches is none and reachability is target. The C runtime got the mode from the AnalysisMode*.bc it linked; the Rust runtime is one library for every mode. LibraryFunctions.hpp, whose only remaining user was this pass, is gone with the C names it declared. --- modules/backend/pass/LibraryFunctions.hpp | 60 --------------------- modules/backend/pass/LoopPredAssumePass.hpp | 1 - modules/backend/pass/Map2CheckLibrary.cpp | 46 +++++++++++++--- modules/backend/pass/Map2CheckLibrary.hpp | 21 ++++++-- modules/frontend/caller.cpp | 23 ++++++++ modules/frontend/caller.hpp | 2 + tests/unit/pass/PassIRTest.cpp | 3 ++ 7 files changed, 85 insertions(+), 71 deletions(-) delete mode 100755 modules/backend/pass/LibraryFunctions.hpp diff --git a/modules/backend/pass/LibraryFunctions.hpp b/modules/backend/pass/LibraryFunctions.hpp deleted file mode 100755 index 75f8e43dd..000000000 --- a/modules/backend/pass/LibraryFunctions.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (C) 2014 - 2020 Map2Check tool - * This file is part of the Map2Check tool, and is made available under - * the terms of the GNU General Public License version 2. - * - * LLVM -> NCSA - * - * SPDX-License-Identifier: (GPL-2.0 AND NCSA) - **/ - -#ifndef MODULES_BACKEND_PASS_LIBRARYFUNCTIONS_HPP_ -#define MODULES_BACKEND_PASS_LIBRARYFUNCTIONS_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using llvm::Constant; -using llvm::FunctionCallee; -using llvm::PointerType; -using llvm::Function; - -class LibraryFunctions { - FunctionCallee map2check_init; - FunctionCallee map2check_exit; - FunctionCallee map2check_track_bb; - - public: - FunctionCallee getInitFunction() { return this->map2check_init; } - FunctionCallee getTrackBBFunction() { return this->map2check_track_bb; } - FunctionCallee getExitFunction() { return this->map2check_exit; } - - LibraryFunctions(Function* F, LLVMContext* Ctx) { - this->map2check_init = F->getParent()->getOrInsertFunction( - "map2check_init", Type::getVoidTy(*Ctx), Type::getInt32Ty(*Ctx)); - - this->map2check_exit = F->getParent()->getOrInsertFunction( - "map2check_success", Type::getVoidTy(*Ctx)); - - this->map2check_exit = F->getParent()->getOrInsertFunction( - "map2check_success", Type::getVoidTy(*Ctx)); - - this->map2check_track_bb = F->getParent()->getOrInsertFunction( - "map2check_track_bb", Type::getVoidTy(*Ctx), Type::getInt32Ty(*Ctx), - PointerType::get(*Ctx, 0)); - } -}; - -#endif // MODULES_BACKEND_PASS_LIBRARYFUNCTIONS_HPP_ diff --git a/modules/backend/pass/LoopPredAssumePass.hpp b/modules/backend/pass/LoopPredAssumePass.hpp index 8efa3549c..2a568fb2e 100644 --- a/modules/backend/pass/LoopPredAssumePass.hpp +++ b/modules/backend/pass/LoopPredAssumePass.hpp @@ -32,7 +32,6 @@ #include "../../frontend/utils/tools.hpp" #include "DebugInfo.hpp" -#include "LibraryFunctions.hpp" namespace Tools = Map2Check; diff --git a/modules/backend/pass/Map2CheckLibrary.cpp b/modules/backend/pass/Map2CheckLibrary.cpp index 209f4f956..6395bde44 100644 --- a/modules/backend/pass/Map2CheckLibrary.cpp +++ b/modules/backend/pass/Map2CheckLibrary.cpp @@ -16,6 +16,8 @@ #include #include +#include "RuntimeABI.hpp" + using llvm::CallInst; using llvm::dyn_cast; using llvm::IRBuilder; @@ -27,9 +29,38 @@ static llvm::cl::opt EntryFunction( llvm::cl::desc("Name of the entry function (default: main)"), llvm::cl::init("main")); +// Values of map2check-library's AnalysisMode (map2check_set_mode). The +// frontend passes the mode of the run; the C runtime got it from the +// AnalysisMode*.bc it linked, the Rust runtime is one library for every mode. +static llvm::cl::opt AnalysisModeOption( + "m2c-analysis-mode", + llvm::cl::desc("Analysis mode passed to map2check_set_mode"), + llvm::cl::values( + clEnumValN(Map2CheckLibrary::AnalysisMode::None, "none", + "no property (cover-branches)"), + clEnumValN(Map2CheckLibrary::AnalysisMode::Memtrack, "memtrack", + "memory safety"), + clEnumValN(Map2CheckLibrary::AnalysisMode::Memcleanup, "memcleanup", + "memory cleanup"), + clEnumValN(Map2CheckLibrary::AnalysisMode::Overflow, "overflow", + "signed integer overflow"), + clEnumValN(Map2CheckLibrary::AnalysisMode::Assert, "assert", + "__VERIFIER_assert"), + clEnumValN(Map2CheckLibrary::AnalysisMode::Target, "target", + "reachability of the target function")), + llvm::cl::init(Map2CheckLibrary::AnalysisMode::None)); + +Map2CheckLibrary::Map2CheckLibrary() : mode(AnalysisModeOption) {} + PreservedAnalyses Map2CheckLibrary::run(Function& F, llvm::FunctionAnalysisManager& AM) { - this->libraryFunctions = make_unique(&F, &F.getContext()); + llvm::Module& M = *F.getParent(); + this->setModeFunction = + Map2Check::getOrInsertRuntime(M, Map2Check::RuntimeHook::SetMode); + this->initFunction = + Map2Check::getOrInsertRuntime(M, Map2Check::RuntimeHook::Init); + this->successFunction = + Map2Check::getOrInsertRuntime(M, Map2Check::RuntimeHook::Success); Function::iterator functionIterator = F.begin(); BasicBlock::iterator instructionIterator = functionIterator->begin(); @@ -64,15 +95,18 @@ PreservedAnalyses Map2CheckLibrary::run(Function& F, void Map2CheckLibrary::instrumentStartInstruction(LLVMContext* Ctx) { IRBuilder<> builder(reinterpret_cast(&*currentInstruction)); - Value* argument = - ConstantInt::getSigned(Type::getInt32Ty(*Ctx), this->SVCOMP ? 1 : 0); - Value* args[] = {argument}; - builder.CreateCall(this->libraryFunctions->getInitFunction(), args); + // map2check_set_mode(mode) must precede map2check_init(); init no longer + // takes the dead isSvComp argument of the C runtime. + Value* mode = ConstantInt::getSigned(Type::getInt32Ty(*Ctx), + static_cast(this->mode)); + Value* args[] = {mode}; + builder.CreateCall(this->setModeFunction, args); + builder.CreateCall(this->initFunction); } void Map2CheckLibrary::instrumentReleaseInstruction(LLVMContext* Ctx) { IRBuilder<> builder(reinterpret_cast(&*currentInstruction)); - builder.CreateCall(this->libraryFunctions->getExitFunction()); + builder.CreateCall(this->successFunction); } void Map2CheckLibrary::runOnCallInstruction(CallInst* callInst, diff --git a/modules/backend/pass/Map2CheckLibrary.hpp b/modules/backend/pass/Map2CheckLibrary.hpp index 299bf69e1..6db3f4b8c 100755 --- a/modules/backend/pass/Map2CheckLibrary.hpp +++ b/modules/backend/pass/Map2CheckLibrary.hpp @@ -29,7 +29,6 @@ #include #include "DebugInfo.hpp" -#include "LibraryFunctions.hpp" using llvm::BasicBlock; using llvm::CallInst; @@ -42,7 +41,19 @@ using std::make_unique; using llvm::Value; struct Map2CheckLibrary : public llvm::PassInfoMixin { - explicit Map2CheckLibrary(bool svcomp = false) : SVCOMP(svcomp) {} + /// map2check-library's AnalysisMode, the argument of map2check_set_mode. + enum class AnalysisMode : int { + None = 0, + Memtrack = 1, + Memcleanup = 2, + Overflow = 3, + Assert = 4, + Target = 5 + }; + + /// Mode from the -m2c-analysis-mode option (default none). + Map2CheckLibrary(); + explicit Map2CheckLibrary(AnalysisMode mode) : mode(mode) {} PreservedAnalyses run(Function& F, llvm::FunctionAnalysisManager& AM); static bool isRequired() { return true; } @@ -54,8 +65,10 @@ struct Map2CheckLibrary : public llvm::PassInfoMixin { Value* getFunctionNameValue() { return this->functionName; } private: - std::unique_ptr libraryFunctions; - bool SVCOMP = false; + AnalysisMode mode = AnalysisMode::None; + llvm::FunctionCallee setModeFunction; + llvm::FunctionCallee initFunction; + llvm::FunctionCallee successFunction; Value* functionName = NULL; BasicBlock::iterator currentInstruction; }; diff --git a/modules/frontend/caller.cpp b/modules/frontend/caller.cpp index 2c557fb1f..af441f5e1 100644 --- a/modules/frontend/caller.cpp +++ b/modules/frontend/caller.cpp @@ -448,6 +448,26 @@ void Caller::applyNonDetGenerator() { } } +const char* Caller::runtimeAnalysisMode(Map2CheckMode mode) { + // Values of -m2c-analysis-mode (Map2CheckLibrary), i.e. map2check-library's + // AnalysisMode. Cover-branches checks no property; reachability is Target. + switch (mode) { + case Map2CheckMode::MEMTRACK_MODE: + return "memtrack"; + case Map2CheckMode::MEMCLEANUP_MODE: + return "memcleanup"; + case Map2CheckMode::OVERFLOW_MODE: + return "overflow"; + case Map2CheckMode::ASSERT_MODE: + return "assert"; + case Map2CheckMode::REACHABILITY_MODE: + return "target"; + case Map2CheckMode::COVER_BRANCHES_MODE: + return "none"; + } + return "none"; +} + int Caller::callPass(std::string target_function, bool sv_comp) { std::ostringstream transformCommand; transformCommand.str(""); @@ -527,6 +547,9 @@ int Caller::callPass(std::string target_function, bool sv_comp) { passesArg << ",map2check-library"; transformCommand << " -entry-function=" << this->entryFunction; + // The Rust runtime is one library for every mode: Map2CheckLibrary emits + // map2check_set_mode() before map2check_init(). + transformCommand << " -m2c-analysis-mode=" << runtimeAnalysisMode(map2checkMode); if (loadsMemoryTrackPass) { transformCommand << " -m2c-entry-function=" << this->entryFunction; } diff --git a/modules/frontend/caller.hpp b/modules/frontend/caller.hpp index eba63101d..b27d7693a 100644 --- a/modules/frontend/caller.hpp +++ b/modules/frontend/caller.hpp @@ -54,6 +54,8 @@ class Caller { /** Get optimization flags for original C file * @return Flags for clang */ static std::string preOptimizationFlags(); + /** Value of opt's -m2c-analysis-mode for `mode` (map2check_set_mode). */ + static const char* runtimeAnalysisMode(Map2CheckMode mode); /** Get optimization flags for final bytecode * @return Flags for opt */ static std::string postOptimizationFlags(); diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index a147cf363..d50d9a868 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -288,6 +288,9 @@ struct ModeCase { int value; }; +// Stable ctest names: print the option, not the bytes of the struct. +void PrintTo(const ModeCase& mode, std::ostream* os) { *os << mode.option; } + class LibraryMode : public ::testing::TestWithParam {}; TEST_P(LibraryMode, EmitsSetModeBeforeInit) { From 5c984eccfa0dfaa2d53906085c5a9e7f7fbe802f Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 11:57:25 -0400 Subject: [PATCH 13/44] build(frontend): compile the analysed program to bitcode with -fexceptions map2check-library rejects a fuzzer input whose __VERIFIER_assume fails by unwinding through the program's frames (D1 condition 11). Without -fexceptions clang marks every C function nounwind, and unwinding through a nounwind function is undefined in LLVM IR; the attributes travel in the bitcode, so the flag belongs on the -emit-llvm step. Every place where the program's C becomes bitcode now passes Map2Check::kProgramUnwindFlags: the -compiled.bc compile, the weak target stub linked after slicing, the wasm entry wrapper and both WasmLifter clang runs. No step adds -fno-unwind-tables or -fno-asynchronous-unwind-tables. The Clam route (--add-invariants) compiles through clam.py and is not changed. --- modules/frontend/caller.cpp | 5 +++++ modules/frontend/wasm_lifter.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/modules/frontend/caller.cpp b/modules/frontend/caller.cpp index af441f5e1..2e81872a5 100644 --- a/modules/frontend/caller.cpp +++ b/modules/frontend/caller.cpp @@ -29,6 +29,7 @@ #include #include "test_suite/ktest_reader.hpp" +#include "utils/clang.hpp" #include "utils/gen_crypto_hash.hpp" #include "utils/log.hpp" #include "utils/slicer.hpp" @@ -311,6 +312,7 @@ bool Caller::sliceWithRespectToTarget(const std::string &targetFunction, } std::ostringstream compileStub; compileStub << Map2Check::clangBinary << " -Wno-everything -c -emit-llvm -g" + << " " << Map2Check::kProgramUnwindFlags << " " << Caller::preOptimizationFlags() << " -o " << stubBitcode << " " << stubSource << " >> slicer.output 2>&1"; std::ostringstream linkStub; @@ -715,6 +717,7 @@ std::string Caller::generateWasmWrapperStatic(const std::string& wasmOutHeaderPa } std::ostringstream compileCmd; compileCmd << Map2Check::clangBinary << " -c -emit-llvm" + << " " << Map2Check::kProgramUnwindFlags << " -I" << wasmIncludePath << " -I" << headerDir << " " << wrapperPath << " -o " << wrapperBcPath; @@ -1116,6 +1119,8 @@ void Caller::compileCFile(bool is_llvm_bc) { << " -Wno-everything " << " -Winteger-overflow " << " -c -emit-llvm -g" + // D1 condition 11: the runtime unwinds through these frames. + << " " << Map2Check::kProgramUnwindFlags << " " << Caller::preOptimizationFlags() << " -o " << compiledFile << " " << programHash << "-preprocessed.c " << " > " << programHash << "-clang.out 2>&1"; diff --git a/modules/frontend/wasm_lifter.cpp b/modules/frontend/wasm_lifter.cpp index f5528a316..c3255f5f7 100644 --- a/modules/frontend/wasm_lifter.cpp +++ b/modules/frontend/wasm_lifter.cpp @@ -13,6 +13,7 @@ #include #include +#include "utils/clang.hpp" #include "utils/log.hpp" namespace Map2Check { @@ -108,6 +109,8 @@ void WasmLifter::runClang(const std::string& cPath, std::ostringstream cmd; cmd << config_.clangPath << " -c -emit-llvm" + // D1 condition 11: the runtime unwinds through the lifted frames. + << " " << Map2Check::kProgramUnwindFlags << " -I\"" << config_.wasmRtIncludePath << "\"" << " -I\"" << hPath.substr(0, hPath.find_last_of("/")) << "\"" << " -Wno-unused-command-line-argument"; @@ -128,6 +131,7 @@ void WasmLifter::runClangEmitLLVM(const std::string& cPath, std::ostringstream cmd; cmd << config_.clangPath << " -S -emit-llvm" + << " " << Map2Check::kProgramUnwindFlags << " -I\"" << config_.wasmRtIncludePath << "\"" << " -I\"" << hPath.substr(0, hPath.find_last_of("/")) << "\""; From 29ec10235df1431450a6be1ac0cbe12a057d0d79 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 12:12:13 -0400 Subject: [PATCH 14/44] test(frontend): pin the frontend mode to AnalysisMode mapping runtimeAnalysisMode moves from a Caller static to an inline function in caller.hpp, next to the new kDefaultMode (MEMTRACK, the mode of a run without a mode flag, now used by map2check.cpp). AnalysisModeTest checks that every frontend mode maps to its number (MEMTRACK 1, MEMCLEANUP 2, OVERFLOW 3, ASSERT 4, REACHABILITY 5, COVER_BRANCHES 0, default 1), and PassIR/FrontendMode feeds each value through opt and checks the constant map2check_set_mode receives. --- modules/frontend/caller.cpp | 20 -------- modules/frontend/caller.hpp | 27 ++++++++++- modules/frontend/map2check.cpp | 2 +- tests/unit/frontend/AnalysisModeTest.cpp | 62 ++++++++++++++++++++++++ tests/unit/frontend/CMakeLists.txt | 5 ++ tests/unit/pass/PassIRTest.cpp | 39 +++++++++++++++ 6 files changed, 132 insertions(+), 23 deletions(-) create mode 100644 tests/unit/frontend/AnalysisModeTest.cpp diff --git a/modules/frontend/caller.cpp b/modules/frontend/caller.cpp index 2e81872a5..33ed6dac1 100644 --- a/modules/frontend/caller.cpp +++ b/modules/frontend/caller.cpp @@ -450,26 +450,6 @@ void Caller::applyNonDetGenerator() { } } -const char* Caller::runtimeAnalysisMode(Map2CheckMode mode) { - // Values of -m2c-analysis-mode (Map2CheckLibrary), i.e. map2check-library's - // AnalysisMode. Cover-branches checks no property; reachability is Target. - switch (mode) { - case Map2CheckMode::MEMTRACK_MODE: - return "memtrack"; - case Map2CheckMode::MEMCLEANUP_MODE: - return "memcleanup"; - case Map2CheckMode::OVERFLOW_MODE: - return "overflow"; - case Map2CheckMode::ASSERT_MODE: - return "assert"; - case Map2CheckMode::REACHABILITY_MODE: - return "target"; - case Map2CheckMode::COVER_BRANCHES_MODE: - return "none"; - } - return "none"; -} - int Caller::callPass(std::string target_function, bool sv_comp) { std::ostringstream transformCommand; transformCommand.str(""); diff --git a/modules/frontend/caller.hpp b/modules/frontend/caller.hpp index b27d7693a..945ff3034 100644 --- a/modules/frontend/caller.hpp +++ b/modules/frontend/caller.hpp @@ -36,6 +36,31 @@ enum class Map2CheckMode { COVER_BRANCHES_MODE }; +/** Mode of a run given no mode flag (map2check.cpp). */ +inline constexpr Map2CheckMode kDefaultMode = Map2CheckMode::MEMTRACK_MODE; + +/** Value of opt's -m2c-analysis-mode for `mode`, i.e. the AnalysisMode of + * map2check-library that Map2CheckLibrary passes to map2check_set_mode: + * none=0, memtrack=1, memcleanup=2, overflow=3, assert=4, target=5. + * Cover-branches checks no property; reachability is Target. */ +inline const char* runtimeAnalysisMode(Map2CheckMode mode) { + switch (mode) { + case Map2CheckMode::MEMTRACK_MODE: + return "memtrack"; + case Map2CheckMode::MEMCLEANUP_MODE: + return "memcleanup"; + case Map2CheckMode::OVERFLOW_MODE: + return "overflow"; + case Map2CheckMode::ASSERT_MODE: + return "assert"; + case Map2CheckMode::REACHABILITY_MODE: + return "target"; + case Map2CheckMode::COVER_BRANCHES_MODE: + return "none"; + } + return "none"; +} + /** NonDet generators */ // TODO(hbgit): Add suport to other nondet like: klee, afl++, afl+klee enum class NonDetGenerator { @@ -54,8 +79,6 @@ class Caller { /** Get optimization flags for original C file * @return Flags for clang */ static std::string preOptimizationFlags(); - /** Value of opt's -m2c-analysis-mode for `mode` (map2check_set_mode). */ - static const char* runtimeAnalysisMode(Map2CheckMode mode); /** Get optimization flags for final bytecode * @return Flags for opt */ static std::string postOptimizationFlags(); diff --git a/modules/frontend/map2check.cpp b/modules/frontend/map2check.cpp index 00bb36320..a39aed7d7 100644 --- a/modules/frontend/map2check.cpp +++ b/modules/frontend/map2check.cpp @@ -806,7 +806,7 @@ z3 (Z3 is default), btor (Boolector), and yices2 (Yices))") map2check_args args; // Default mode - args.mode = Map2Check::Map2CheckMode::MEMTRACK_MODE; + args.mode = Map2Check::kDefaultMode; // Handling with the options if (vm.count("version")) { std::cout << Map2CheckVersion << "\n"; diff --git a/tests/unit/frontend/AnalysisModeTest.cpp b/tests/unit/frontend/AnalysisModeTest.cpp new file mode 100644 index 000000000..fb16878a2 --- /dev/null +++ b/tests/unit/frontend/AnalysisModeTest.cpp @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// The frontend's mode -> the -m2c-analysis-mode value it passes to opt, and +// from there the AnalysisMode number Map2CheckLibrary hands to +// map2check_set_mode. PassIRTest checks the same mapping through opt. + +#include + +#include +#include + +#include "../../../modules/frontend/caller.hpp" + +using Map2Check::Map2CheckMode; +using Map2Check::runtimeAnalysisMode; + +namespace { + +// map2check-library's AnalysisMode, by -m2c-analysis-mode value. +int analysisModeNumber(const std::string& option) { + static const std::map numbers = { + {"none", 0}, {"memtrack", 1}, {"memcleanup", 2}, + {"overflow", 3}, {"assert", 4}, {"target", 5}}; + auto it = numbers.find(option); + return it == numbers.end() ? -1 : it->second; +} + +int number(Map2CheckMode mode) { + return analysisModeNumber(runtimeAnalysisMode(mode)); +} + +} // namespace + +TEST(AnalysisMode, EveryFrontendModeMapsToItsNumber) { + EXPECT_EQ(number(Map2CheckMode::MEMTRACK_MODE), 1); + EXPECT_EQ(number(Map2CheckMode::MEMCLEANUP_MODE), 2); + EXPECT_EQ(number(Map2CheckMode::OVERFLOW_MODE), 3); + EXPECT_EQ(number(Map2CheckMode::ASSERT_MODE), 4); + EXPECT_EQ(number(Map2CheckMode::REACHABILITY_MODE), 5); + EXPECT_EQ(number(Map2CheckMode::COVER_BRANCHES_MODE), 0); +} + +TEST(AnalysisMode, OptionNames) { + EXPECT_STREQ(runtimeAnalysisMode(Map2CheckMode::MEMTRACK_MODE), "memtrack"); + EXPECT_STREQ(runtimeAnalysisMode(Map2CheckMode::MEMCLEANUP_MODE), "memcleanup"); + EXPECT_STREQ(runtimeAnalysisMode(Map2CheckMode::OVERFLOW_MODE), "overflow"); + EXPECT_STREQ(runtimeAnalysisMode(Map2CheckMode::ASSERT_MODE), "assert"); + EXPECT_STREQ(runtimeAnalysisMode(Map2CheckMode::REACHABILITY_MODE), "target"); + EXPECT_STREQ(runtimeAnalysisMode(Map2CheckMode::COVER_BRANCHES_MODE), "none"); +} + +// No mode flag on the command line: map2check.cpp starts from kDefaultMode. +TEST(AnalysisMode, DefaultModeIsMemtrack) { + EXPECT_EQ(Map2Check::kDefaultMode, Map2CheckMode::MEMTRACK_MODE); + EXPECT_EQ(number(Map2Check::kDefaultMode), 1); +} diff --git a/tests/unit/frontend/CMakeLists.txt b/tests/unit/frontend/CMakeLists.txt index 35d6a0390..6ea2e854e 100644 --- a/tests/unit/frontend/CMakeLists.txt +++ b/tests/unit/frontend/CMakeLists.txt @@ -20,3 +20,8 @@ add_executable(SlicerTest SlicerTest.cpp ) map2check_test(SlicerTest) + +add_executable(AnalysisModeTest + AnalysisModeTest.cpp +) +map2check_test(AnalysisModeTest) diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index d50d9a868..7867c970f 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -31,6 +31,7 @@ #include #include "../../../modules/backend/pass/RuntimeABI.hpp" +#include "../../../modules/frontend/caller.hpp" #include "../../../modules/frontend/utils/clang.hpp" using Map2Check::runtimeCall; @@ -319,6 +320,44 @@ INSTANTIATE_TEST_SUITE_P( return std::string(info.param.option); }); +// The option value the frontend passes for each of its modes reaches +// map2check_set_mode as the right AnalysisMode number. +struct FrontendModeCase { + Map2Check::Map2CheckMode mode; + const char* label; + int value; +}; + +void PrintTo(const FrontendModeCase& c, std::ostream* os) { *os << c.label; } + +class FrontendMode : public ::testing::TestWithParam {}; + +TEST_P(FrontendMode, SetModeGetsItsNumber) { + const FrontendModeCase& c = GetParam(); + auto m = runPassOn("Map2CheckLibrary", "map2check-library", "main.c", + std::string("-m2c-analysis-mode=") + + Map2Check::runtimeAnalysisMode(c.mode)); + ASSERT_VALID(m); + std::vector found = callsTo(*m, "map2check_set_mode"); + ASSERT_EQ(found.size(), 1u); + EXPECT_EQ(intArg(found[0]->getArgOperand(0)), c.value); +} + +using Map2Check::Map2CheckMode; +INSTANTIATE_TEST_SUITE_P( + PassIR, FrontendMode, + ::testing::Values( + FrontendModeCase{Map2CheckMode::MEMTRACK_MODE, "memtrack", 1}, + FrontendModeCase{Map2CheckMode::MEMCLEANUP_MODE, "memcleanup", 2}, + FrontendModeCase{Map2CheckMode::OVERFLOW_MODE, "overflow", 3}, + FrontendModeCase{Map2CheckMode::ASSERT_MODE, "assert", 4}, + FrontendModeCase{Map2CheckMode::REACHABILITY_MODE, "reachability", 5}, + FrontendModeCase{Map2CheckMode::COVER_BRANCHES_MODE, "cover_branches", 0}, + FrontendModeCase{Map2Check::kDefaultMode, "default", 1}), + [](const ::testing::TestParamInfo& info) { + return std::string(info.param.label); + }); + TEST(PassIR, LibraryInitTakesNoArgumentAndSuccessPrecedesExits) { auto m = runPassOn("Map2CheckLibrary", "map2check-library", "main.c", "-m2c-analysis-mode=memtrack"); From 1ff67fe4a0be30f81d00dd2785e24a0dab59232c Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 12:12:13 -0400 Subject: [PATCH 15/44] build(frontend): compile the Clam route's program with -fexceptions too clam.py compiles the C itself and cannot forward clang flags, so with --add-invariants (ENABLE_CLAM=ON, reachable by AFL++) the program bitcode was nounwind, against D1 condition 11. compileWithClam now compiles the preprocessed C with the flags clam.py would use (-disable-O0-optnone, -fdeclspec, -fno-discard-value-names, -m64, -g, its include dir) plus kProgramUnwindFlags, and hands clam.py the bitcode, for which it skips its own clang step. On a loop program the same 8 verifier.assume calls are injected, and main is no longer nounwind. --- modules/frontend/caller.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/frontend/caller.cpp b/modules/frontend/caller.cpp index 33ed6dac1..5958fb4dc 100644 --- a/modules/frontend/caller.cpp +++ b/modules/frontend/caller.cpp @@ -1218,12 +1218,34 @@ void Caller::compileWithClam() { // map2check_crab_assume, which the runtime forwards to klee_assume -- so // nothing downstream needs to change. // See docs/reports/2026-08-16-crabllvm-review.md. + // + // D1 condition 11: the program's bitcode must not be nounwind, and clam.py + // has no way to forward clang flags. So the C is compiled here, with the + // flags clam.py itself would use (-disable-O0-optnone, -fdeclspec, + // -fno-discard-value-names, -m64, -g, its include dir) plus + // kProgramUnwindFlags, and clam.py receives bitcode, for which it skips its + // own clang step. Measured on a loop program: the same 8 verifier.assume + // calls are injected as when clam.py compiles the C, and main loses + // nounwind. + const std::string clamInput = programHash + "-clam-input.bc"; + std::ostringstream compileForClam; + compileForClam << Map2Check::clangBinary << " -Wno-everything" + << " -c -emit-llvm -g -m64" + << " " << Map2Check::kProgramUnwindFlags + << " -Xclang -disable-O0-optnone -fdeclspec" + << " -fno-discard-value-names" + << " -I" << clamRoot << "/include" + << " -o " << clamInput << " " << programHash + << "-preprocessed.c"; + Map2Check::Log::Debug(compileForClam.str()); + system(compileForClam.str().c_str()); + command << Map2Check::clamBinary() << " -o " << compiledFile << " -m 64 -g" << " --crab-inter" << " --crab-track=num" << " --crab-opt=add-invariants" << " --crab-opt-invariants-loc=block-entry" - << " " << programHash << "-preprocessed.c "; + << " " << clamInput << " "; Map2Check::Log::Debug(command.str()); system(command.str().c_str()); From c1f4d562614def4887cf1865b5c0a8c8a8eafcd7 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 12:31:42 -0400 Subject: [PATCH 16/44] feat(pass): emit the signed binop checkers of map2check-library from OverflowPass OverflowPass now declares map2check_binop_{add,sub,mul,div,rem}_signed through RuntimeABI and calls them with the core order (a, b, bits, line, fn): operands sign-extended to i64, the operation's own width, no scope. The _uint variants (C no-ops) and the dead overflowError path are gone, and OperationsFunctions.hpp with them. The unsigned-nondet name check follows the core generator __VERIFIER_nondet_uint. PassIR tests cover every binop (callee, type, operands, bits, line, function) and the widths 8/16/32/64. --- modules/backend/pass/OperationsFunctions.hpp | 103 ------------------- modules/backend/pass/OverflowPass.cpp | 86 ++++++---------- modules/backend/pass/OverflowPass.hpp | 12 ++- tests/unit/pass/CMakeLists.txt | 3 +- tests/unit/pass/PassIRTest.cpp | 96 +++++++++++++++++ tests/unit/pass/inputs/overflow.c | 14 +++ tests/unit/pass/inputs/overflow_widths.ll | 40 +++++++ 7 files changed, 194 insertions(+), 160 deletions(-) delete mode 100644 modules/backend/pass/OperationsFunctions.hpp create mode 100644 tests/unit/pass/inputs/overflow.c create mode 100644 tests/unit/pass/inputs/overflow_widths.ll diff --git a/modules/backend/pass/OperationsFunctions.hpp b/modules/backend/pass/OperationsFunctions.hpp deleted file mode 100644 index 1e12bece1..000000000 --- a/modules/backend/pass/OperationsFunctions.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (C) 2014 - 2020 Map2Check tool - * This file is part of the Map2Check tool, and is made available under - * the terms of the GNU General Public License version 2. - * - * LLVM -> NCSA - * - * SPDX-License-Identifier: (GPL-2.0 AND NCSA) - **/ - -#ifndef MODULES_BACKEND_PASS_OPERATIONSFUNCTIONS_HPP_ -#define MODULES_BACKEND_PASS_OPERATIONSFUNCTIONS_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -// using namespace llvm; -using llvm::Function; -using llvm::FunctionCallee; -using llvm::LLVMContext; -using llvm::PointerType; -using llvm::Type; - -class OperationsFunctions { - FunctionCallee OverflowAdd; - FunctionCallee OverflowAddUint; - FunctionCallee OverflowSub; - FunctionCallee OverflowSubUint; - FunctionCallee OverflowMul; - FunctionCallee OverflowMulUint; - FunctionCallee OverflowSDiv; - FunctionCallee OverflowSRem; - FunctionCallee OverflowError; - - public: - FunctionCallee getOverflowAdd() { return this->OverflowAdd; } - FunctionCallee getOverflowAddUint() { return this->OverflowAddUint; } - FunctionCallee getOverflowSub() { return this->OverflowSub; } - FunctionCallee getOverflowSubUint() { return this->OverflowSubUint; } - FunctionCallee getOverflowMul() { return this->OverflowMul; } - FunctionCallee getOverflowMulUint() { return this->OverflowMulUint; } - FunctionCallee getOverflowSDiv() { return this->OverflowSDiv; } - FunctionCallee getOverflowSRem() { return this->OverflowSRem; } - FunctionCallee getOverflowError() { return this->OverflowError; } - - // Signed binop checkers share one ABI: - // (i64 lhs, i64 rhs, i32 width, i32 line, i32 scope, ptr functionName) - // - // The operands are sign-extended to i64 by the pass (lossless), and `width` - // carries the bit width of the *result type of the operation*. That is the - // quantity SV-COMP's no-overflow property is defined over, so the runtime - // must range-check against it rather than against a fixed width. Keeping a - // single 64-bit ABI (instead of one symbol per width) mirrors how UBSan's - // __ubsan_handle_*_overflow handlers take the type as a parameter. - OperationsFunctions(Function *F, LLVMContext *Ctx) { - // LLVM 16: opaque pointers — use PointerType::get(*Ctx, 0) instead of PointerType::get(, 0) - auto *PtrTy = PointerType::get(*Ctx, 0); - auto *I64 = Type::getInt64Ty(*Ctx); - auto *I32 = Type::getInt32Ty(*Ctx); - auto *VoidTy = Type::getVoidTy(*Ctx); - - this->OverflowAdd = F->getParent()->getOrInsertFunction( - "map2check_binop_add", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowAddUint = F->getParent()->getOrInsertFunction( - "map2check_binop_add_uint", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowSub = F->getParent()->getOrInsertFunction( - "map2check_binop_sub", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowSubUint = F->getParent()->getOrInsertFunction( - "map2check_binop_sub_uint", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowMul = F->getParent()->getOrInsertFunction( - "map2check_binop_mul", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowMulUint = F->getParent()->getOrInsertFunction( - "map2check_binop_mul_uint", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowSDiv = F->getParent()->getOrInsertFunction( - "map2check_binop_sdiv", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowSRem = F->getParent()->getOrInsertFunction( - "map2check_binop_srem", VoidTy, I64, I64, I32, I32, I32, PtrTy); - - this->OverflowError = - F->getParent()->getOrInsertFunction("overflowError", VoidTy, I32, PtrTy); - } -}; - -#endif // MODULES_BACKEND_PASS_OPERATIONSFUNCTIONS_HPP_ diff --git a/modules/backend/pass/OverflowPass.cpp b/modules/backend/pass/OverflowPass.cpp index 86f37bf39..59e415bc5 100644 --- a/modules/backend/pass/OverflowPass.cpp +++ b/modules/backend/pass/OverflowPass.cpp @@ -29,7 +29,6 @@ using llvm::IntegerType; using llvm::IRBuilder; using llvm::isa; using llvm::LoadInst; -using std::make_unique; using llvm::MDNode; using llvm::StoreInst; using llvm::Twine; @@ -55,9 +54,9 @@ void OverflowPass::listAllUintAssign(BasicBlock &B) { if (auto *cI = dyn_cast(&*i)) { Value *v = cI->getCalledOperand(); Function *calleeFunction = dyn_cast(v->stripPointerCasts()); + // NonDetPass keeps the core generator name (__VERIFIER_nondet_uint). if (calleeFunction && - (calleeFunction->getName() == "__VERIFIER_nondet_uint" || - calleeFunction->getName() == "map2check_non_det_uint")) { + calleeFunction->getName() == Map2Check::nonDetGenerator("uint")) { DebugInfo debugInfoCi(this->Ctx, cI); // errs() << debugInfoCi.getLineNumberInt() << "==================\n"; @@ -193,8 +192,17 @@ std::string OverflowPass::getValueNameOperator(Value *Vop) { PreservedAnalyses OverflowPass::run(Function &F, llvm::FunctionAnalysisManager &AM) { - this->operationsFunctions = - make_unique(&F, &F.getContext()); + llvm::Module &module = *F.getParent(); + this->binopAdd = Map2Check::getOrInsertRuntime( + module, Map2Check::RuntimeHook::BinopAdd); + this->binopSub = Map2Check::getOrInsertRuntime( + module, Map2Check::RuntimeHook::BinopSub); + this->binopMul = Map2Check::getOrInsertRuntime( + module, Map2Check::RuntimeHook::BinopMul); + this->binopSDiv = Map2Check::getOrInsertRuntime( + module, Map2Check::RuntimeHook::BinopSDiv); + this->binopSRem = Map2Check::getOrInsertRuntime( + module, Map2Check::RuntimeHook::BinopSRem); Function::iterator functionIterator = F.begin(); BasicBlock::iterator instructionIterator = functionIterator->begin(); @@ -212,24 +220,6 @@ PreservedAnalyses OverflowPass::run(Function &F, for (Function::iterator bb = F.begin(), e = F.end(); bb != e; ++bb) { for (BasicBlock::iterator i = bb->begin(), e = bb->end(); i != e; ++i) { - if (this->errorLines.size() != 0) { - Instruction *currentInstruction = BBIteratorToInst(i); - DebugInfo debugInfo(&F.getContext(), currentInstruction); - int line = debugInfo.getLineNumberInt(); - - std::vector::iterator it = - std::find(this->errorLines.begin(), this->errorLines.end(), line); - - if (it != this->errorLines.end()) { - IRBuilder<> builder(currentInstruction); - Value *args[] = {debugInfo.getLineNumberValue(), functionName}; - builder.CreateCall(this->operationsFunctions->getOverflowError(), - args); - - this->errorLines.erase(it); - } - } - if (StoreInst *storeInst = dyn_cast(&*i)) { Value *firstOperand = storeInst->getValueOperand(); Value *secondOperand = storeInst->getPointerOperand(); @@ -239,7 +229,7 @@ PreservedAnalyses OverflowPass::run(Function &F, std::vector::const_iterator iT; // checking for first operator - // TODO(hbgit): search by map2check_non_det_uint + // TODO(hbgit): search by the __VERIFIER_nondet_uint generator bool isUnsignedNonDet = false; iT = std::find(this->listUnsignedVars.begin(), @@ -280,12 +270,12 @@ PreservedAnalyses OverflowPass::run(Function &F, std::vector::const_iterator iT; // checking for first operator - // TODO(hbgit): search by map2check_non_det_uint + // TODO(hbgit): search by the __VERIFIER_nondet_uint generator bool isUnsigned = false; bool isUnsignedNonDet = false; iT = std::find(this->listUnsignedVars.begin(), this->listUnsignedVars.end(), lvaluep); - if (rvaluep == "map2check_non_det_uint") { + if (rvaluep == Map2Check::nonDetGenerator("uint")) { isUnsignedNonDet = true; } @@ -339,36 +329,30 @@ PreservedAnalyses OverflowPass::run(Function &F, switch (binOp->getOpcode()) { case (Instruction::Add): - if (this->isUnitAssignment) { - // instrumentedFunction = - // this->operationsFunctions->getOverflowAddUint(); - } else { - instrumentedFunction = - this->operationsFunctions->getOverflowAdd(); + // Without nsw the operation is unsigned: wraparound is not an + // overflow, and the C runtime's _uint checker was a no-op. + if (!this->isUnitAssignment) { + instrumentedFunction = this->binopAdd; } break; case (Instruction::FAdd): break; case (Instruction::Sub): - if (this->isUnitAssignment) { - // instrumentedFunction = - // this->operationsFunctions->getOverflowSubUint(); - } else { - instrumentedFunction = - this->operationsFunctions->getOverflowSub(); + // Without nsw the operation is unsigned: wraparound is not an + // overflow, and the C runtime's _uint checker was a no-op. + if (!this->isUnitAssignment) { + instrumentedFunction = this->binopSub; } break; case (Instruction::FSub): break; case (Instruction::Mul): - if (this->isUnitAssignment) { - // instrumentedFunction = - // this->operationsFunctions->getOverflowMulUint(); - } else { - instrumentedFunction = - this->operationsFunctions->getOverflowMul(); + // Without nsw the operation is unsigned: wraparound is not an + // overflow, and the C runtime's _uint checker was a no-op. + if (!this->isUnitAssignment) { + instrumentedFunction = this->binopMul; } break; case (Instruction::FMul): @@ -378,7 +362,7 @@ PreservedAnalyses OverflowPass::run(Function &F, break; case (Instruction::SDiv): - instrumentedFunction = this->operationsFunctions->getOverflowSDiv(); + instrumentedFunction = this->binopSDiv; break; case (Instruction::FDiv): @@ -387,7 +371,7 @@ PreservedAnalyses OverflowPass::run(Function &F, break; case (Instruction::SRem): - instrumentedFunction = this->operationsFunctions->getOverflowSRem(); + instrumentedFunction = this->binopSRem; break; case (Instruction::FRem): @@ -434,12 +418,10 @@ PreservedAnalyses OverflowPass::run(Function &F, Value *width = ConstantInt::get(Type::getInt32Ty(*Ctx), opType->getBitWidth()); - Value *args[] = {firstOperand64Ty, - secondOperand64Ty, - width, - debugInfo.getLineNumberValue(), - debugInfo.getScopeNumberValue(), - functionName}; + // Core order: (a, b, bits, line, function); the core takes no + // scope. + Value *args[] = {firstOperand64Ty, secondOperand64Ty, width, + debugInfo.getLineNumberValue(), functionName}; builder.CreateCall(instrumentedFunction, args); } else { diff --git a/modules/backend/pass/OverflowPass.hpp b/modules/backend/pass/OverflowPass.hpp index 652a0f193..5efdf6c08 100644 --- a/modules/backend/pass/OverflowPass.hpp +++ b/modules/backend/pass/OverflowPass.hpp @@ -30,7 +30,7 @@ #include #include "DebugInfo.hpp" -#include "OperationsFunctions.hpp" +#include "RuntimeABI.hpp" // using namespace llvm; using llvm::BasicBlock; @@ -39,11 +39,11 @@ using llvm::Function; using llvm::Instruction; using llvm::LLVMContext; using llvm::PreservedAnalyses; +using llvm::Type; using llvm::Value; struct OverflowPass : public llvm::PassInfoMixin { OverflowPass() = default; - explicit OverflowPass(std::vector lines) : errorLines(std::move(lines)) {} PreservedAnalyses run(Function &F, llvm::FunctionAnalysisManager &AM); static bool isRequired() { return true; } @@ -51,7 +51,12 @@ struct OverflowPass : public llvm::PassInfoMixin { Value *getFunctionNameValue() { return this->functionName; } private: - std::unique_ptr operationsFunctions; + // Signed binop checkers of map2check-library (RuntimeHook::Binop*). + llvm::FunctionCallee binopAdd; + llvm::FunctionCallee binopSub; + llvm::FunctionCallee binopMul; + llvm::FunctionCallee binopSDiv; + llvm::FunctionCallee binopSRem; Value *functionName = NULL; void hasNonDetUint(Instruction *I); void listAllUintAssign(BasicBlock &B); @@ -59,7 +64,6 @@ struct OverflowPass : public llvm::PassInfoMixin { std::string getValueNameOperator(Value *Vop); void listAllUnsignedVar(Function &F); - std::vector errorLines; std::vector valuesThatShouldBeUint; std::vector storeInstWithUint; std::vector loadInstWithUint; diff --git a/tests/unit/pass/CMakeLists.txt b/tests/unit/pass/CMakeLists.txt index a230cb53d..f67be5b96 100644 --- a/tests/unit/pass/CMakeLists.txt +++ b/tests/unit/pass/CMakeLists.txt @@ -58,5 +58,6 @@ else() m2c_pass_test(PassIRTest PassIRTest.cpp) # The plugins are loaded by opt at test time; build them before the test. add_dependencies(PassIRTest - TrackBasicBlockPass AssertPass TargetPass LoopPredAssumePass Map2CheckLibrary) + TrackBasicBlockPass AssertPass TargetPass LoopPredAssumePass Map2CheckLibrary + OverflowPass NonDetPass MemoryTrackPass) endif() diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 7867c970f..7bf6d0368 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -420,3 +420,99 @@ TEST(PassIR, ProgramUnwindFlagsNeverDisableUnwindTables) { EXPECT_EQ(flags.find("-fno-unwind-tables"), std::string::npos); EXPECT_EQ(flags.find("-fno-asynchronous-unwind-tables"), std::string::npos); } + +// --------------------------------------------------------------------------- +// OverflowPass -> BinopAdd/Sub/Mul/SDiv/SRem +// --------------------------------------------------------------------------- + +namespace { + +/// The value a binop operand had before the pass widened it to i64. +llvm::Value* beforeSExt(llvm::Value* v) { + if (auto* sext = llvm::dyn_cast(v)) return sext->getOperand(0); + return v; +} + +/// Checks one binop call: it sits right before the operation it guards, its +/// operands are that operation's operands sign-extended to i64, and it passes +/// the operation's width, the line and the enclosing function. +void expectBinopCall(llvm::CallInst* call, unsigned opcode, int bits, int line) { + auto* op = llvm::dyn_cast(call->getNextNode()); + ASSERT_NE(op, nullptr) << "the check must precede the operation"; + EXPECT_EQ(op->getOpcode(), opcode); + EXPECT_EQ(beforeSExt(call->getArgOperand(0)), op->getOperand(0)); + EXPECT_EQ(beforeSExt(call->getArgOperand(1)), op->getOperand(1)); + if (bits < 64) { + EXPECT_TRUE(llvm::isa(call->getArgOperand(0))); + EXPECT_TRUE(llvm::isa(call->getArgOperand(1))); + } + EXPECT_EQ(intArg(call->getArgOperand(2)), bits); + if (line >= 0) EXPECT_EQ(intArg(call->getArgOperand(3)), line); + EXPECT_EQ(stringArg(call->getArgOperand(4)), + call->getFunction()->getName().str()); +} + +} // namespace + +TEST(PassIR, OverflowEmitsSignedBinopsWithBitsLineAndFunction) { + auto m = runPassOn("OverflowPass", "overflow-pass", "overflow.c"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::BinopAdd); + expectCoreCalls(*m, RuntimeHook::BinopSub); + expectCoreCalls(*m, RuntimeHook::BinopMul); + expectCoreCalls(*m, RuntimeHook::BinopSDiv); + expectCoreCalls(*m, RuntimeHook::BinopSRem); + + // int a + b (line 6) and long + 1L (line 11); the unsigned add of line 12 + // has no nsw and is not checked. + std::vector add = callsTo(*m, "map2check_binop_add_signed"); + ASSERT_EQ(add.size(), 2u); + expectBinopCall(add[0], llvm::Instruction::Add, 32, 6); + expectBinopCall(add[1], llvm::Instruction::Add, 64, 11); + + std::vector sub = callsTo(*m, "map2check_binop_sub_signed"); + ASSERT_EQ(sub.size(), 1u); + expectBinopCall(sub[0], llvm::Instruction::Sub, 32, 7); + std::vector mul = callsTo(*m, "map2check_binop_mul_signed"); + ASSERT_EQ(mul.size(), 1u); + expectBinopCall(mul[0], llvm::Instruction::Mul, 32, 8); + std::vector div = callsTo(*m, "map2check_binop_div_signed"); + ASSERT_EQ(div.size(), 1u); + expectBinopCall(div[0], llvm::Instruction::SDiv, 32, 9); + std::vector rem = callsTo(*m, "map2check_binop_rem_signed"); + ASSERT_EQ(rem.size(), 1u); + expectBinopCall(rem[0], llvm::Instruction::SRem, 32, 10); + + // No C name, no _uint variant (a C no-op), no dead overflowError. + for (const char* legacy : + {"map2check_binop_add", "map2check_binop_sub", "map2check_binop_mul", + "map2check_binop_sdiv", "map2check_binop_srem", + "map2check_binop_add_uint", "map2check_binop_sub_uint", + "map2check_binop_mul_uint", "overflowError"}) { + EXPECT_EQ(m->getFunction(legacy), nullptr) << legacy; + } +} + +TEST(PassIR, OverflowPassesTheOperationWidth) { + auto m = runPassOn("OverflowPass", "overflow-pass", "overflow_widths.ll"); + ASSERT_VALID(m); + struct WidthCase { + const char* fn; + const char* hook; + unsigned opcode; + int bits; + }; + for (const WidthCase& c : + {WidthCase{"add8", "map2check_binop_add_signed", llvm::Instruction::Add, 8}, + WidthCase{"sub16", "map2check_binop_sub_signed", llvm::Instruction::Sub, 16}, + WidthCase{"mul32", "map2check_binop_mul_signed", llvm::Instruction::Mul, 32}, + WidthCase{"add64", "map2check_binop_add_signed", llvm::Instruction::Add, 64}}) { + SCOPED_TRACE(c.fn); + std::vector inFn; + for (llvm::CallInst* call : callsTo(*m, c.hook)) { + if (call->getFunction()->getName() == c.fn) inFn.push_back(call); + } + ASSERT_EQ(inFn.size(), 1u); + expectBinopCall(inFn[0], c.opcode, c.bits, /*line=*/-1); + } +} diff --git a/tests/unit/pass/inputs/overflow.c b/tests/unit/pass/inputs/overflow.c new file mode 100644 index 000000000..cbd454aed --- /dev/null +++ b/tests/unit/pass/inputs/overflow.c @@ -0,0 +1,14 @@ +extern int __VERIFIER_nondet_int(void); +extern long __VERIFIER_nondet_long(void); +int main(void) { + int a = __VERIFIER_nondet_int(); + int b = __VERIFIER_nondet_int(); + int s = a + b; + int d = a - b; + int m = a * b; + int q = b != 0 ? a / b : 0; + int r = b != 0 ? a % b : 0; + long w = __VERIFIER_nondet_long() + 1L; + unsigned u = (unsigned)a + 1u; + return (s ^ d ^ m ^ q ^ r ^ (int)w ^ (int)u) & 1; +} diff --git a/tests/unit/pass/inputs/overflow_widths.ll b/tests/unit/pass/inputs/overflow_widths.ll new file mode 100644 index 000000000..13570f471 --- /dev/null +++ b/tests/unit/pass/inputs/overflow_widths.ll @@ -0,0 +1,40 @@ +; Signed i8/i16/i32/i64 arithmetic as the optimiser leaves it (clang -O0 +; promotes char and short to int, so only IR reaches the narrow widths). +declare i32 @__VERIFIER_nondet_int() + +define i8 @add8(i8 %a, i8 %b) { +entry: + %r = add nsw i8 %a, %b + ret i8 %r +} + +define i16 @sub16(i16 %a, i16 %b) { +entry: + %r = sub nsw i16 %a, %b + ret i16 %r +} + +define i32 @mul32(i32 %a, i32 %b) { +entry: + %r = mul nsw i32 %a, %b + ret i32 %r +} + +define i64 @add64(i64 %a, i64 %b) { +entry: + %r = add nsw i64 %a, %b + ret i64 %r +} + +define i32 @main() { +entry: + %x = call i32 @__VERIFIER_nondet_int() + %x8 = trunc i32 %x to i8 + %x16 = trunc i32 %x to i16 + %x64 = sext i32 %x to i64 + %r8 = call i8 @add8(i8 %x8, i8 1) + %r16 = call i16 @sub16(i16 %x16, i16 1) + %r32 = call i32 @mul32(i32 %x, i32 3) + %r64 = call i64 @add64(i64 %x64, i64 1) + ret i32 0 +} From 59907e7cb46a9df417f1dbfe4d07846cef71e632 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:01:41 -0400 Subject: [PATCH 17/44] feat(pass): log nondet values through map2check_save_nondet_log_ from NonDetPass NonDetPass keeps the core generators __VERIFIER_nondet_ (retargeting __VERIFIER_nondet_unsigned to __VERIFIER_nondet_uint per call, so later calls are still logged as unsigned) and logs each value through map2check_save_nondet_log_(line, scope, type_var, slot, fn): the value is stored in an entry alloca of the C type of the library's api-deltas (bool widens to int) and type_var is the NONDET_TYPE number. The slot and its store carry map2check.runtime metadata. Assumes: __VERIFIER_assume keeps its name; Clam's nounwind verifier.assume(i1) is replaced by a zext call to __VERIFIER_assume; assume_abort_if_not and friends call it with cond != 0; a program's own __VERIFIER_assume loses its body so the library's is the only one. The library's assume unwinds, so nounwind is dropped from its declaration, from the rewritten functions and from all their call sites (RuntimeABI allowUnwind). NonDetFunctions.hpp is gone. RuntimeABI gains nonDetValueSlot, allowUnwind and kRuntimeMetadata, with RuntimeABITest coverage; PassIR tests cover the 16 types, the C names, the assume rewrites and nounwind. --- modules/backend/pass/NonDetFunctions.hpp | 96 ------- modules/backend/pass/NonDetPass.cpp | 347 +++++++++++------------ modules/backend/pass/NonDetPass.hpp | 64 +---- modules/backend/pass/RuntimeABI.cpp | 42 +++ modules/backend/pass/RuntimeABI.hpp | 23 ++ tests/unit/pass/PassIRTest.cpp | 200 +++++++++++++ tests/unit/pass/RuntimeABITest.cpp | 39 +++ tests/unit/pass/inputs/assume_defined.c | 14 + tests/unit/pass/inputs/crab_assume.ll | 16 ++ tests/unit/pass/inputs/nondet_types.c | 38 +++ 10 files changed, 546 insertions(+), 333 deletions(-) delete mode 100644 modules/backend/pass/NonDetFunctions.hpp create mode 100644 tests/unit/pass/inputs/assume_defined.c create mode 100644 tests/unit/pass/inputs/crab_assume.ll create mode 100644 tests/unit/pass/inputs/nondet_types.c diff --git a/modules/backend/pass/NonDetFunctions.hpp b/modules/backend/pass/NonDetFunctions.hpp deleted file mode 100644 index d22bb6745..000000000 --- a/modules/backend/pass/NonDetFunctions.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (C) 2014 - 2020 Map2Check tool - * This file is part of the Map2Check tool, and is made available under - * the terms of the GNU General Public License version 2. - * - * LLVM -> NCSA - * - * SPDX-License-Identifier: (GPL-2.0 AND NCSA) - **/ - -#ifndef MODULES_BACKEND_PASS_NONDETFUNCTIONS_HPP_ -#define MODULES_BACKEND_PASS_NONDETFUNCTIONS_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -// using namespace llvm; -using llvm::Constant; -using llvm::Function; -using llvm::FunctionCallee; -using llvm::LLVMContext; -using llvm::PointerType; -using llvm::Type; - -#define CONSTANT_GENERATOR(type) \ - private: \ - FunctionCallee NonDet##type; \ - \ - public: \ - FunctionCallee getNonDet##type##Function() { return this->NonDet##type; } - -#define NON_DET_FUNCTIONS_HELPER(type, c_type) \ - this->NonDet##type = F->getParent()->getOrInsertFunction( \ - "map2check_nondet_" #c_type, Type::getVoidTy(*Ctx), \ - Type::getInt32Ty(*Ctx), Type::getInt32Ty(*Ctx), Type::getInt32Ty(*Ctx), \ - PointerType::get(*Ctx, 0)); - -#define NON_DET_FUNCTIONS_HELPER_DOUBLE(type, c_type) \ - this->NonDet##type = F->getParent()->getOrInsertFunction( \ - "map2check_nondet_" #c_type, Type::getVoidTy(*Ctx), \ - Type::getInt32Ty(*Ctx), Type::getInt32Ty(*Ctx), Type::getDoubleTy(*Ctx), \ - PointerType::get(*Ctx, 0)); - -class NonDetFunctions { - CONSTANT_GENERATOR(Integer) - CONSTANT_GENERATOR(Unsigned) - CONSTANT_GENERATOR(Char) - CONSTANT_GENERATOR(Pointer) - CONSTANT_GENERATOR(Long) - CONSTANT_GENERATOR(Ushort) - CONSTANT_GENERATOR(Short) - CONSTANT_GENERATOR(Ulong) - CONSTANT_GENERATOR(Bool) - CONSTANT_GENERATOR(Uchar) - CONSTANT_GENERATOR(Pchar) - CONSTANT_GENERATOR(Size_t) - CONSTANT_GENERATOR(Loff_t) - CONSTANT_GENERATOR(Sector_t) - CONSTANT_GENERATOR(Uint) - CONSTANT_GENERATOR(Double) - // Constant* NonDetAssume = NULL; - - public: - NonDetFunctions(Function *F, LLVMContext *Ctx) { - NON_DET_FUNCTIONS_HELPER(Integer, int) - NON_DET_FUNCTIONS_HELPER(Unsigned, unsigned) - NON_DET_FUNCTIONS_HELPER(Pointer, pointer) - NON_DET_FUNCTIONS_HELPER(Ushort, ushort) - NON_DET_FUNCTIONS_HELPER(Short, short) - NON_DET_FUNCTIONS_HELPER(Char, char) - NON_DET_FUNCTIONS_HELPER(Long, long) - NON_DET_FUNCTIONS_HELPER(Ulong, ulong) - NON_DET_FUNCTIONS_HELPER(Bool, bool) - NON_DET_FUNCTIONS_HELPER(Uchar, uchar) - NON_DET_FUNCTIONS_HELPER(Pchar, pchar) - NON_DET_FUNCTIONS_HELPER(Size_t, size_t) - NON_DET_FUNCTIONS_HELPER(Loff_t, loff_t) - NON_DET_FUNCTIONS_HELPER(Sector_t, sector_t) - NON_DET_FUNCTIONS_HELPER(Uint, uint) - NON_DET_FUNCTIONS_HELPER_DOUBLE(Double, double) - } -}; - -#endif // MODULES_BACKEND_PASS_NONDETFUNCTIONS_HPP_ diff --git a/modules/backend/pass/NonDetPass.cpp b/modules/backend/pass/NonDetPass.cpp index 08dc2b6d0..0e80209da 100644 --- a/modules/backend/pass/NonDetPass.cpp +++ b/modules/backend/pass/NonDetPass.cpp @@ -10,23 +10,16 @@ #include "NonDetPass.hpp" -#include +#include +#include +#include #include #include -using llvm::CastInst; using llvm::dyn_cast; +using llvm::Instruction; using llvm::IRBuilder; -using std::make_unique; -using llvm::Twine; - -namespace { -inline Instruction *BBIteratorToInst(BasicBlock::iterator i) { - Instruction *pointer = reinterpret_cast(&*i); - return pointer; -} -} // namespace namespace { @@ -84,17 +77,34 @@ bool rewriteAssumeToPrune(Function &F) { if (F.arg_size() != 1 || !F.getArg(0)->getType()->isIntegerTy()) return false; if (!F.getReturnType()->isVoidTy()) return false; + // The program's own __VERIFIER_assume gives way to the library's: its + // body would otherwise call itself, and the link would see two + // definitions. + llvm::FunctionCallee assume = + Map2Check::getOrInsertRuntime(*F.getParent(), + Map2Check::RuntimeHook::Assume); + if (assume.getCallee() == &F) { + F.deleteBody(); + Map2Check::allowUnwind(F); + llvm::errs() << "[map2check] dropped the program's " << F.getName() + << " for the runtime's\n"; + return true; + } + LLVMContext &ctx = F.getContext(); - llvm::Type *int32 = llvm::Type::getInt32Ty(ctx); llvm::Value *condition = F.getArg(0); F.deleteBody(); BasicBlock *entry = BasicBlock::Create(ctx, "entry", &F); IRBuilder<> builder(entry); - llvm::FunctionCallee assume = F.getParent()->getOrInsertFunction( - "map2check_assume", llvm::Type::getVoidTy(ctx), int32); - builder.CreateCall(assume, {builder.CreateSExtOrTrunc(condition, int32)}); + // C reads the int condition as cond != 0. + llvm::Value *holds = builder.CreateICmpNE( + condition, llvm::Constant::getNullValue(condition->getType())); + builder.CreateCall(assume, {builder.CreateZExt(holds, builder.getInt32Ty())}); builder.CreateRetVoid(); + // The assume unwinds through this function now. + Map2Check::allowUnwind(F); + Map2Check::allowUnwind(*llvm::cast(assume.getCallee())); llvm::errs() << "[map2check] rewrote " << F.getName() << " to prune the path instead of aborting\n"; return true; @@ -102,195 +112,172 @@ bool rewriteAssumeToPrune(Function &F) { } // namespace +namespace { + +/// The C type suffixes of the __VERIFIER_nondet_ generators the pass logs +/// (abi-mapping.tsv, family map2check_nondet_). +const char *const kNonDetTypes[] = { + "int", "unsigned", "char", "pointer", "long", "ushort", + "short", "ulong", "bool", "uchar", "pchar", "size_t", + "loff_t", "sector_t", "uint", "double"}; + +/// The C type of a __VERIFIER_nondet_ callee, or "" when it is not one. +llvm::StringRef nonDetType(const Function &callee) { + llvm::StringRef name = callee.getName(); + if (!name.consume_front("__VERIFIER_nondet_")) return ""; + for (const char *type : kNonDetTypes) { + if (name == type) return type; + } + return ""; +} + +/// Converts the generator's value to the C type of the logger's slot, or +/// returns nullptr when the program declared the generator with a type that +/// cannot be converted. +Value *toSlotType(IRBuilder<> &builder, Value *value, + const Map2Check::NonDetValueSlot &slot) { + llvm::Type *from = value->getType(); + llvm::Type *to = slot.type; + if (from == to) return value; + if (from->isIntegerTy() && to->isIntegerTy()) { + // An i1 (_Bool) is 0 or 1 whatever the slot's signedness. + bool isSigned = slot.isSigned && !from->isIntegerTy(1); + return builder.CreateIntCast(value, to, isSigned); + } + if (from->isPointerTy() && to->isIntegerTy()) { + return builder.CreatePtrToInt(value, to); + } + if (from->isIntegerTy() && to->isPointerTy()) { + return builder.CreateIntToPtr(value, to); + } + if (from->isFloatingPointTy() && to->isFloatingPointTy()) { + return builder.CreateFPCast(value, to); + } + return nullptr; +} + +} // namespace + PreservedAnalyses NonDetPass::run(Function &F, llvm::FunctionAnalysisManager &AM) { + // The library's assume rejects an input by unwinding through its callers, + // so no declaration of it or call to it may be nounwind (D1 condition 11). + if (Function *assume = F.getParent()->getFunction( + Map2Check::runtimeCall(Map2Check::RuntimeHook::Assume, + F.getContext()) + .name)) { + Map2Check::allowUnwind(*assume); + } + // Before anything else: this replaces the whole body, so instrumenting the // old one first would be work thrown away. if (rewriteAssumeToPrune(F)) { return PreservedAnalyses::none(); } + if (F.isDeclaration()) return PreservedAnalyses::none(); - this->nonDetFunctions = make_unique(&F, &F.getContext()); - bool initializedFunctionName = false; - for (Function::iterator bb = F.begin(), e = F.end(); bb != e; ++bb) { - for (BasicBlock::iterator i = bb->begin(), e = bb->end(); i != e; ++i) { - if (!initializedFunctionName) { - IRBuilder<> builder(BBIteratorToInst(i)); - this->functionName = builder.CreateGlobalStringPtr(F.getName()); - initializedFunctionName = true; - } - if (CallInst *callInst = dyn_cast(&*i)) { - currentInstruction = i; - this->runOnCallInstruction(callInst, &F.getContext()); + // Collect first, instrument after: the instrumentation inserts and removes + // instructions. + std::vector> nonDetCalls; + std::vector crabAssumes; + for (BasicBlock &bb : F) { + for (Instruction &i : bb) { + auto *callInst = dyn_cast(&i); + if (callInst == nullptr) continue; + auto *callee = dyn_cast( + callInst->getCalledOperand()->stripPointerCasts()); + if (callee == nullptr) continue; + llvm::StringRef type = nonDetType(*callee); + if (!type.empty()) { + nonDetCalls.emplace_back(callInst, type); + } else if (callee->getName() == "verifier.assume") { + crabAssumes.push_back(callInst); } } } + if (nonDetCalls.empty() && crabAssumes.empty()) { + return PreservedAnalyses::all(); + } + + IRBuilder<> entryBuilder(&*F.getEntryBlock().getFirstInsertionPt()); + this->functionName = entryBuilder.CreateGlobalStringPtr(F.getName()); + for (auto &[callInst, type] : nonDetCalls) { + this->instrumentNonDet(callInst, type); + } + for (CallInst *callInst : crabAssumes) { + this->instrumentCrabAssume(callInst); + } return PreservedAnalyses::none(); } -namespace { -#define CALL_IF_HELPER(type, nondet_type, c_type) \ - if ((calleeFunction->getName() == ("__VERIFIER_nondet_" #c_type))) { \ - this->instrumentNonDet(NonDetType::nondet_type, calleeFunction); \ - this->instrumentNonDet##type(callInst, Ctx); \ - } else if ((calleeFunction->getName() == ("map2check_non_det_" #c_type))) { \ - this->instrumentNonDet##type(callInst, Ctx); \ +// abi-mapping: map2check_non_det_ -> __VERIFIER_nondet_, +// map2check_nondet_ -> map2check_save_nondet_log_. +void NonDetPass::instrumentNonDet(CallInst *callInst, llvm::StringRef type) { + Function &F = *callInst->getFunction(); + llvm::Module &module = *F.getParent(); + LLVMContext &ctx = F.getContext(); + + // The generator keeps its name, except __VERIFIER_nondet_unsigned, which + // the library spells __VERIFIER_nondet_uint. Only this call is retargeted: + // the other calls keep naming their own C type, so they are logged as it. + std::string generator = Map2Check::nonDetGenerator(type); + if (callInst->getCalledOperand()->stripPointerCasts()->getName() != + generator) { + llvm::FunctionCallee core = module.getOrInsertFunction( + generator, callInst->getFunctionType()); + callInst->setCalledFunction(callInst->getFunctionType(), core.getCallee()); } -} // namespace -void NonDetPass::runOnCallInstruction(CallInst *callInst, LLVMContext *Ctx) { - Function *calleeFunction = callInst->getCalledFunction(); + Map2Check::NonDetValueSlot slot = Map2Check::nonDetValueSlot(type, ctx); + if (slot.type == nullptr || callInst->getType()->isVoidTy()) return; - if (calleeFunction == NULL) { - Value *v = callInst->getCalledOperand(); - calleeFunction = dyn_cast(v->stripPointerCasts()); - if (calleeFunction == NULL) { - return; - } - } + // The logger takes the value by address, in its C type + // (docs/api-deltas.md of the library), so it lives in an entry alloca. + // map2check.runtime marks the slot as instrumentation, which + // MemoryTrackPass does not track as program memory. + llvm::MDNode *runtimeTag = llvm::MDNode::get(ctx, {}); + IRBuilder<> entryBuilder(&*F.getEntryBlock().getFirstInsertionPt()); + llvm::AllocaInst *valueSlot = entryBuilder.CreateAlloca( + slot.type, nullptr, "map2check.nondet." + type); + valueSlot->setMetadata(Map2Check::kRuntimeMetadata, runtimeTag); - // TODO(rafa.sa.xp@gmail.com): Should not rename __VERIFIER functions - // clang-format - if (true) { - CALL_IF_HELPER(Integer, INTEGER, int) - } - CALL_IF_HELPER(Unsigned, UNSIGNED, unsigned) - CALL_IF_HELPER(Char, CHAR, char) - CALL_IF_HELPER(Pointer, POINTER, pointer) - CALL_IF_HELPER(Long, LONG, long) - CALL_IF_HELPER(Ushort, USHORT, ushort) - CALL_IF_HELPER(Short, SHORT, short) - CALL_IF_HELPER(Ulong, ULONG, ulong) - CALL_IF_HELPER(Bool, BOOL, bool) - CALL_IF_HELPER(Uchar, UCHAR, uchar) - CALL_IF_HELPER(Pchar, PCHAR, pchar) - CALL_IF_HELPER(Size_t, SIZE_T, size_t) - CALL_IF_HELPER(Loff_t, LOFF_T, loff_t) - CALL_IF_HELPER(Sector_t, SECTOR_T, sector_t) - CALL_IF_HELPER(Uint, UINT, uint) - CALL_IF_HELPER(Double, DOUBLE, double) + IRBuilder<> builder(callInst->getNextNode()); + Value *value = toSlotType(builder, callInst, slot); + if (value == nullptr) return; + llvm::StoreInst *store = builder.CreateStore(value, valueSlot); + store->setMetadata(Map2Check::kRuntimeMetadata, runtimeTag); - if ((calleeFunction->getName() == "__VERIFIER_assume")) { - this->instrumentNonDet(NonDetType::ASSUME, calleeFunction); - } else if ((calleeFunction->getName() == "verifier.assume")) { - this->instrumentNonDet(NonDetType::CRAB_ASSUME, calleeFunction); - } else if ((calleeFunction->getName() == "map2check_assume")) { - // TODO(rafa.sa.xp@gmail.com): Implement method - } - // clang-format on + DebugInfo debugInfo(&ctx, callInst); + llvm::FunctionCallee logger = module.getOrInsertFunction( + Map2Check::nonDetLogger(type), Map2Check::nonDetLoggerType(ctx)); + Value *args[] = {debugInfo.getLineNumberValue(), + debugInfo.getScopeNumberValue(), + llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), + slot.typeVar), + valueSlot, this->functionName}; + builder.CreateCall(logger, args); } -namespace { -#define INSTRUMENT_CASE_HELPER(nondet_type, c_type) \ - case (NonDetType::nondet_type): { \ - Twine non_det("map2check_non_det_" #c_type); \ - calleeFunction->setName(non_det); \ - break; \ - } -} // namespace -void NonDetPass::instrumentNonDet(NonDetType nonDetType, - Function *calleeFunction) { - switch (nonDetType) { - INSTRUMENT_CASE_HELPER(INTEGER, int) - INSTRUMENT_CASE_HELPER(UNSIGNED, unsigned) - INSTRUMENT_CASE_HELPER(CHAR, char) - INSTRUMENT_CASE_HELPER(POINTER, pointer) - INSTRUMENT_CASE_HELPER(LONG, long) - INSTRUMENT_CASE_HELPER(USHORT, ushort) - INSTRUMENT_CASE_HELPER(SHORT, short) - INSTRUMENT_CASE_HELPER(ULONG, ulong) - INSTRUMENT_CASE_HELPER(BOOL, bool) - INSTRUMENT_CASE_HELPER(UCHAR, uchar) - INSTRUMENT_CASE_HELPER(PCHAR, pchar) - INSTRUMENT_CASE_HELPER(SIZE_T, size_t) - INSTRUMENT_CASE_HELPER(LOFF_T, loff_t) - INSTRUMENT_CASE_HELPER(SECTOR_T, sector_t) - INSTRUMENT_CASE_HELPER(UINT, uint) - INSTRUMENT_CASE_HELPER(DOUBLE, double) - case (NonDetType::ASSUME): { - Twine assume("map2check_assume"); - calleeFunction->setName(assume); - break; - } - case (NonDetType::CRAB_ASSUME): { - Twine assume("map2check_crab_assume"); - calleeFunction->setName(assume); - break; - } +// abi-mapping: map2check_crab_assume -> __VERIFIER_assume. Clam's +// verifier.assume(i1) is nounwind; the core assume takes an i32 and unwinds, +// so the call is replaced instead of renamed. +void NonDetPass::instrumentCrabAssume(CallInst *callInst) { + llvm::Module &module = *callInst->getModule(); + llvm::FunctionCallee assume = + Map2Check::getOrInsertRuntime(module, Map2Check::RuntimeHook::Assume); + IRBuilder<> builder(callInst); + Value *condition = callInst->getArgOperand(0); + if (!condition->getType()->isIntegerTy(1)) { + condition = builder.CreateICmpNE( + condition, llvm::Constant::getNullValue(condition->getType())); } + CallInst *replacement = builder.CreateCall( + assume, {builder.CreateZExt(condition, builder.getInt32Ty())}); + replacement->setDebugLoc(callInst->getDebugLoc()); + callInst->eraseFromParent(); + Map2Check::allowUnwind(*llvm::cast(assume.getCallee())); } -namespace { -#define NONDET_IMPL_HELPER_POINTER(type) \ - void NonDetPass::instrumentNonDet##type(CallInst *callInst, \ - LLVMContext *Ctx) { \ - auto j = this->currentInstruction; \ - j++; \ - IRBuilder<> builder(BBIteratorToInst(j)); \ - Value *function_llvm = this->getFunctionNameValue(); \ - Value *cast = builder.CreatePtrToInt(callInst, Type::getInt32Ty(*Ctx)); \ - DebugInfo debugInfo(Ctx, callInst); \ - Value *args[] = {debugInfo.getLineNumberValue(), \ - debugInfo.getScopeNumberValue(), cast, function_llvm}; \ - FunctionCallee NonDetFunction = \ - this->nonDetFunctions->getNonDet##type##Function(); \ - builder.CreateCall(NonDetFunction, args); \ - } - -#define NONDET_IMPL_HELPER_CAST(type) \ - void NonDetPass::instrumentNonDet##type(CallInst *callInst, \ - LLVMContext *Ctx) { \ - auto j = this->currentInstruction; \ - j++; \ - IRBuilder<> builder(BBIteratorToInst(j)); \ - Value *function_llvm = this->getFunctionNameValue(); \ - Twine bitcast("map2check_nondet_cast_" #type); \ - Value *castInteger = \ - CastInst::CreateIntegerCast(callInst, Type::getInt32Ty(*Ctx), false, \ - bitcast, BBIteratorToInst(j)); \ - DebugInfo debugInfo(Ctx, callInst); \ - Value *args[] = {debugInfo.getLineNumberValue(), \ - debugInfo.getScopeNumberValue(), castInteger, \ - function_llvm}; \ - FunctionCallee NonDetFunction = \ - this->nonDetFunctions->getNonDet##type##Function(); \ - builder.CreateCall(NonDetFunction, args); \ - } - -#define NONDET_IMPL_HELPER(type) \ - void NonDetPass::instrumentNonDet##type(CallInst *callInst, \ - LLVMContext *Ctx) { \ - auto j = this->currentInstruction; \ - j++; \ - IRBuilder<> builder(BBIteratorToInst(j)); \ - Value *function_llvm = this->getFunctionNameValue(); \ - DebugInfo debugInfo(Ctx, callInst); \ - Value *args[] = {debugInfo.getLineNumberValue(), \ - debugInfo.getScopeNumberValue(), callInst, \ - function_llvm}; \ - FunctionCallee NonDetFunction = \ - this->nonDetFunctions->getNonDet##type##Function(); \ - builder.CreateCall(NonDetFunction, args); \ - } -} // namespace - -NONDET_IMPL_HELPER(Integer) -NONDET_IMPL_HELPER(Unsigned) -NONDET_IMPL_HELPER(Uint) -NONDET_IMPL_HELPER(Double) -NONDET_IMPL_HELPER_CAST(Char) -NONDET_IMPL_HELPER_CAST(Ushort) -NONDET_IMPL_HELPER_CAST(Short) -NONDET_IMPL_HELPER_CAST(Long) -NONDET_IMPL_HELPER_CAST(Ulong) -NONDET_IMPL_HELPER_CAST(Bool) -NONDET_IMPL_HELPER_CAST(Uchar) -NONDET_IMPL_HELPER_CAST(Size_t) -NONDET_IMPL_HELPER_CAST(Loff_t) -NONDET_IMPL_HELPER_CAST(Sector_t) -NONDET_IMPL_HELPER_POINTER(Pchar) -NONDET_IMPL_HELPER_POINTER(Pointer) - // --- New Pass Manager plugin registration --- extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo() { diff --git a/modules/backend/pass/NonDetPass.hpp b/modules/backend/pass/NonDetPass.hpp index bbe5bd86a..b4bf77938 100644 --- a/modules/backend/pass/NonDetPass.hpp +++ b/modules/backend/pass/NonDetPass.hpp @@ -29,7 +29,7 @@ #include #include "DebugInfo.hpp" -#include "NonDetFunctions.hpp" +#include "RuntimeABI.hpp" using llvm::BasicBlock; using llvm::CallInst; @@ -38,67 +38,17 @@ using llvm::LLVMContext; using llvm::PreservedAnalyses; using llvm::Value; -enum class NonDetType { - INTEGER, - UNSIGNED, - POINTER, - // STRING, - LONG, - ASSUME, - USHORT, - SHORT, - ULONG, - CHAR, - BOOL, - UCHAR, - PCHAR, - SIZE_T, - LOFF_T, - SECTOR_T, - UINT, - CRAB_ASSUME, - DOUBLE -}; - -namespace InstrumentNonDetS { -#define INSTRUMENT_HEADER_HELPER(type) \ - void instrumentNonDet##type(CallInst *callInst, LLVMContext *Ctx); -} // namespace InstrumentNonDetS - +/// Logs every __VERIFIER_nondet_ value through the core +/// map2check_save_nondet_log_ of map2check-library, and turns the +/// program's assume idioms into the library's __VERIFIER_assume. struct NonDetPass : public llvm::PassInfoMixin { PreservedAnalyses run(Function &F, llvm::FunctionAnalysisManager &AM); static bool isRequired() { return true; } - protected: - void instrumentInstruction(); - /** - * @brief Checks if current function is a non det call and instruments it - */ - void runOnCallInstruction(CallInst *callInst, LLVMContext *Ctx); - Value *getFunctionNameValue() { return this->functionName; } - private: - void instrumentNonDet(NonDetType type, Function *calleeFunction); - INSTRUMENT_HEADER_HELPER(Integer) - INSTRUMENT_HEADER_HELPER(Unsigned) - INSTRUMENT_HEADER_HELPER(Char) - INSTRUMENT_HEADER_HELPER(Pointer) - INSTRUMENT_HEADER_HELPER(Long) - INSTRUMENT_HEADER_HELPER(Ushort) - INSTRUMENT_HEADER_HELPER(Short) - INSTRUMENT_HEADER_HELPER(Ulong) - INSTRUMENT_HEADER_HELPER(Bool) - INSTRUMENT_HEADER_HELPER(Uchar) - INSTRUMENT_HEADER_HELPER(Pchar) - INSTRUMENT_HEADER_HELPER(Size_t) - INSTRUMENT_HEADER_HELPER(Loff_t) - INSTRUMENT_HEADER_HELPER(Sector_t) - INSTRUMENT_HEADER_HELPER(Uint) - INSTRUMENT_HEADER_HELPER(Double) - void instrumentCrabAssume(CallInst *callInst, LLVMContext *Ctx); - std::unique_ptr nonDetFunctions; - Value *functionName = NULL; - BasicBlock::iterator currentInstruction; + void instrumentNonDet(CallInst *callInst, llvm::StringRef type); + void instrumentCrabAssume(CallInst *callInst); + Value *functionName = nullptr; }; class NonDetPassException : public std::runtime_error { diff --git a/modules/backend/pass/RuntimeABI.cpp b/modules/backend/pass/RuntimeABI.cpp index e34c69d0e..23002b9da 100644 --- a/modules/backend/pass/RuntimeABI.cpp +++ b/modules/backend/pass/RuntimeABI.cpp @@ -11,6 +11,7 @@ #include "RuntimeABI.hpp" #include +#include #include namespace Map2Check { @@ -153,4 +154,45 @@ llvm::FunctionType* nonDetLoggerType(llvm::LLVMContext& ctx) { return fn(p, {i32, i32, i32, p, p}); } +NonDetValueSlot nonDetValueSlot(llvm::StringRef cType, + llvm::LLVMContext& ctx) { + llvm::Type* i8 = llvm::Type::getInt8Ty(ctx); + llvm::Type* i16 = llvm::Type::getInt16Ty(ctx); + llvm::Type* i32 = llvm::Type::getInt32Ty(ctx); + llvm::Type* i64 = llvm::Type::getInt64Ty(ctx); + llvm::Type* p = llvm::PointerType::get(ctx, 0); + llvm::Type* dbl = llvm::Type::getDoubleTy(ctx); + // enum NONDET_TYPE: INTEGER 0, CHAR 1, POINTER 2, USHORT 3, LONG 4, + // UNSIGNED 5, ULONG 6, BOOL 7, UCHAR 8, PCHAR 9, SIZE_T 10, LOFF_T 11, + // SECTOR_T 12, UINT 13, SHORT 14, DOUBLE 15. + return llvm::StringSwitch(cType) + .Case("int", {i32, true, 0}) + .Case("char", {i8, true, 1}) + .Case("pointer", {p, false, 2}) + .Case("ushort", {i16, false, 3}) + .Case("long", {i64, true, 4}) + .Case("unsigned", {i32, false, 5}) + .Case("ulong", {i64, false, 6}) + .Case("bool", {i32, false, 7}) // typedef int bool; _Bool widens + .Case("uchar", {i8, false, 8}) + .Case("pchar", {p, false, 9}) + .Case("size_t", {i64, false, 10}) + .Case("loff_t", {i64, true, 11}) // long long + .Case("sector_t", {i64, false, 12}) // unsigned long + .Case("uint", {i32, false, 13}) + .Case("short", {i16, true, 14}) + .Case("double", {dbl, true, 15}) + .Default({nullptr, false, -1}); +} + +void allowUnwind(llvm::Function& fn) { + fn.removeFnAttr(llvm::Attribute::NoUnwind); + for (llvm::User* user : fn.users()) { + auto* call = llvm::dyn_cast(user); + if (call != nullptr && call->getCalledOperand() == &fn) { + call->removeFnAttr(llvm::Attribute::NoUnwind); + } + } +} + } // namespace Map2Check diff --git a/modules/backend/pass/RuntimeABI.hpp b/modules/backend/pass/RuntimeABI.hpp index d0fd2e2e9..9355a660b 100644 --- a/modules/backend/pass/RuntimeABI.hpp +++ b/modules/backend/pass/RuntimeABI.hpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -87,6 +88,28 @@ std::string nonDetLogger(llvm::StringRef cType); /// (i32 line, i32 scope, i32 type_var, ptr value, ptr fn) -> ptr. llvm::FunctionType* nonDetLoggerType(llvm::LLVMContext& ctx); +/// Metadata kind on the instructions a pass adds for the runtime's own use +/// (the nondet value slots), which are not program memory to track. +inline constexpr char kRuntimeMetadata[] = "map2check.runtime"; + +/// How a nondet value reaches map2check_save_nondet_log_: the pass stores +/// it in an alloca of `type` (the C type of docs/api-deltas.md of the +/// library: bool widens to int, pointer/pchar are addresses) and passes +/// `typeVar`, the enum NONDET_TYPE number of the type +/// (Map2CheckTypes.h:41-58). `isSigned` says how an integer of another +/// width is converted to `type`. +struct NonDetValueSlot { + llvm::Type* type; // nullptr when the type is not in the mapping + bool isSigned; + int typeVar; +}; +NonDetValueSlot nonDetValueSlot(llvm::StringRef cType, llvm::LLVMContext& ctx); + +/// Removes `nounwind` from `fn` and from every call to it. An assume of the +/// library rejects an input by unwinding through its caller (D1 condition +/// 11), so a nounwind declaration or call site of it is undefined behaviour. +void allowUnwind(llvm::Function& fn); + } // namespace Map2Check #endif // MODULES_BACKEND_PASS_RUNTIMEABI_HPP_ diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 7bf6d0368..0971d9435 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -516,3 +516,203 @@ TEST(PassIR, OverflowPassesTheOperationWidth) { expectBinopCall(inFn[0], c.opcode, c.bits, /*line=*/-1); } } + +// --------------------------------------------------------------------------- +// NonDetPass -> __VERIFIER_nondet_, map2check_save_nondet_log_, Assume +// --------------------------------------------------------------------------- + +namespace { + +struct NonDetCase { + const char* cType; + int line; // of the call in inputs/nondet_types.c +}; + +void PrintTo(const NonDetCase& c, std::ostream* os) { *os << c.cType; } + +int callLine(llvm::Instruction* i) { + const llvm::DebugLoc& loc = i->getDebugLoc(); + return loc ? static_cast(loc.getLine()) : -1; +} + +/// The value stored in `slot` by a store that precedes `before` in its block. +llvm::Value* storedBefore(llvm::Value* slot, llvm::Instruction* before) { + llvm::Value* stored = nullptr; + for (llvm::Instruction& i : *before->getParent()) { + if (&i == before) break; + if (auto* store = llvm::dyn_cast(&i)) { + if (store->getPointerOperand() == slot) stored = store->getValueOperand(); + } + } + return stored; +} + +llvm::Value* stripCasts(llvm::Value* v) { + while (auto* cast = llvm::dyn_cast(v)) v = cast->getOperand(0); + return v; +} + +std::unique_ptr& nonDetModule() { + static std::unique_ptr m = + runPassOn("NonDetPass", "nondet-pass", "nondet_types.c"); + return m; +} + +} // namespace + +class NonDetType : public ::testing::TestWithParam {}; + +// Each __VERIFIER_nondet_ call keeps (or gets) its core generator, and its +// value reaches map2check_save_nondet_log_ through an alloca of the C type +// with the NONDET_TYPE number as type_var. +TEST_P(NonDetType, LogsTheValueThroughATypedSlot) { + const NonDetCase& c = GetParam(); + std::unique_ptr& m = nonDetModule(); + ASSERT_VALID(m); + llvm::LLVMContext& ctx = m->getContext(); + Map2Check::NonDetValueSlot slot = Map2Check::nonDetValueSlot(c.cType, ctx); + ASSERT_NE(slot.type, nullptr); + + // The generator call of this line. + std::string generator = Map2Check::nonDetGenerator(c.cType); + llvm::CallInst* gen = nullptr; + for (llvm::CallInst* call : callsTo(*m, generator)) { + if (callLine(call) == c.line) gen = call; + } + ASSERT_NE(gen, nullptr) << "no call to " << generator << " on line " << c.line; + + // Its logger: core name and type, (line, scope, type_var, slot, fn). + std::string logger = Map2Check::nonDetLogger(c.cType); + llvm::Function* decl = m->getFunction(logger); + ASSERT_NE(decl, nullptr) << logger; + EXPECT_EQ(decl->getFunctionType(), Map2Check::nonDetLoggerType(ctx)); + llvm::CallInst* log = nullptr; + for (llvm::CallInst* call : callsTo(*m, logger)) { + if (intArg(call->getArgOperand(0)) == c.line) log = call; + } + ASSERT_NE(log, nullptr) << "no " << logger << " for line " << c.line; + EXPECT_EQ(log->getFunctionType(), Map2Check::nonDetLoggerType(ctx)); + ASSERT_EQ(log->arg_size(), 5u); + EXPECT_TRUE(llvm::isa(log->getArgOperand(1))); // scope + EXPECT_EQ(intArg(log->getArgOperand(2)), slot.typeVar); + auto* alloca = llvm::dyn_cast(log->getArgOperand(3)); + ASSERT_NE(alloca, nullptr) << "the value is passed through an alloca"; + EXPECT_EQ(alloca->getAllocatedType(), slot.type); + EXPECT_EQ(stringArg(log->getArgOperand(4)), "main"); + // The slot holds the generator's value, converted to the C type. + llvm::Value* stored = storedBefore(alloca, log); + ASSERT_NE(stored, nullptr) << "nothing stored in the slot before the log"; + EXPECT_EQ(stored->getType(), slot.type); + EXPECT_EQ(stripCasts(stored), gen); + // The log follows the generator call in the same block. + EXPECT_EQ(gen->getParent(), log->getParent()); + EXPECT_TRUE(gen->comesBefore(log)); +} + +INSTANTIATE_TEST_SUITE_P( + PassIR, NonDetType, + ::testing::Values(NonDetCase{"int", 18}, NonDetCase{"unsigned", 19}, + NonDetCase{"uint", 20}, NonDetCase{"char", 21}, + NonDetCase{"uchar", 22}, NonDetCase{"short", 23}, + NonDetCase{"ushort", 24}, NonDetCase{"long", 25}, + NonDetCase{"ulong", 26}, NonDetCase{"bool", 27}, + NonDetCase{"pointer", 28}, NonDetCase{"pchar", 29}, + NonDetCase{"size_t", 30}, NonDetCase{"loff_t", 31}, + NonDetCase{"sector_t", 32}, NonDetCase{"double", 33}), + [](const ::testing::TestParamInfo& info) { + return std::string(info.param.cType); + }); + +TEST(PassIR, NonDetEmitsNoCRuntimeName) { + std::unique_ptr& m = nonDetModule(); + ASSERT_VALID(m); + for (llvm::Function& f : *m) { + EXPECT_FALSE(f.getName().starts_with("map2check_non_det_")) << f.getName().str(); + EXPECT_FALSE(f.getName().starts_with("map2check_nondet_")) << f.getName().str(); + } + // The library has no __VERIFIER_nondet_unsigned: that call now goes to + // __VERIFIER_nondet_uint and is still logged as unsigned. + llvm::Function* unsignedDecl = m->getFunction("__VERIFIER_nondet_unsigned"); + if (unsignedDecl != nullptr) EXPECT_TRUE(unsignedDecl->use_empty()); + EXPECT_EQ(callsTo(*m, "__VERIFIER_nondet_uint").size(), 2u); + EXPECT_EQ(callsTo(*m, "map2check_save_nondet_log_unsigned").size(), 1u); + EXPECT_EQ(callsTo(*m, "map2check_save_nondet_log_uint").size(), 1u); +} + +namespace { + +void expectNoNounwind(llvm::Module& m, llvm::StringRef name) { + llvm::Function* f = m.getFunction(name); + ASSERT_NE(f, nullptr) << name.str(); + EXPECT_FALSE(f->hasFnAttribute(llvm::Attribute::NoUnwind)) << name.str(); + std::vector found = callsTo(m, name); + EXPECT_FALSE(found.empty()) << name.str(); + for (llvm::CallInst* call : found) { + EXPECT_FALSE(call->hasFnAttr(llvm::Attribute::NoUnwind)) + << "nounwind call to " << name.str() << " in " + << call->getFunction()->getName().str(); + } +} + +} // namespace + +// Compiled without -fexceptions every call is nounwind; the assume of the +// library unwinds, so the pass clears it on the declaration and the calls. +TEST(PassIR, NonDetKeepsVerifierAssumeAndDropsNounwind) { + auto m = runPassOn("NonDetPass", "nondet-pass", "assume.c"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Assume); + EXPECT_EQ(m->getFunction("map2check_assume"), nullptr); + expectNoNounwind(*m, "__VERIFIER_assume"); +} + +TEST(PassIR, NonDetTurnsCrabAssumeIntoVerifierAssume) { + auto m = runPassOn("NonDetPass", "nondet-pass", "crab_assume.ll"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Assume); + EXPECT_FALSE(calls(*m, "verifier.assume")); + EXPECT_EQ(m->getFunction("map2check_crab_assume"), nullptr); + std::vector found = callsTo(*m, "__VERIFIER_assume"); + ASSERT_EQ(found.size(), 2u); + for (llvm::CallInst* call : found) { + // The i1 invariant is widened to the i32 the core takes. + auto* zext = llvm::dyn_cast(call->getArgOperand(0)); + ASSERT_NE(zext, nullptr); + EXPECT_TRUE(zext->getSrcTy()->isIntegerTy(1)); + EXPECT_TRUE(llvm::isa(zext->getOperand(0))); + } + expectNoNounwind(*m, "__VERIFIER_assume"); +} + +// assume_abort_if_not aborts on a false condition; its body becomes a call to +// the library's assume. A program's own __VERIFIER_assume loses its body, so +// the library's definition is the only one (no recursion, no duplicate). +TEST(PassIR, NonDetRewritesAbortingAssumes) { + auto m = runPassOn("NonDetPass", "nondet-pass", "assume_defined.c"); + ASSERT_VALID(m); + llvm::Function* verifierAssume = m->getFunction("__VERIFIER_assume"); + ASSERT_NE(verifierAssume, nullptr); + EXPECT_TRUE(verifierAssume->isDeclaration()); + EXPECT_EQ(verifierAssume->getFunctionType(), + runtimeCall(RuntimeHook::Assume, m->getContext()).type); + + llvm::Function* abortIfNot = m->getFunction("assume_abort_if_not"); + ASSERT_NE(abortIfNot, nullptr); + ASSERT_FALSE(abortIfNot->isDeclaration()); + std::vector inBody; + for (llvm::CallInst* call : callsTo(*m, "__VERIFIER_assume")) { + if (call->getFunction() == abortIfNot) inBody.push_back(call); + } + ASSERT_EQ(inBody.size(), 1u); + EXPECT_FALSE(calls(*m, "abort")); + // cond != 0, as C reads the int condition. + auto* zext = llvm::dyn_cast(inBody[0]->getArgOperand(0)); + ASSERT_NE(zext, nullptr); + auto* cmp = llvm::dyn_cast(zext->getOperand(0)); + ASSERT_NE(cmp, nullptr); + EXPECT_EQ(cmp->getPredicate(), llvm::ICmpInst::ICMP_NE); + EXPECT_EQ(cmp->getOperand(0), abortIfNot->getArg(0)); + + expectNoNounwind(*m, "__VERIFIER_assume"); + expectNoNounwind(*m, "assume_abort_if_not"); +} diff --git a/tests/unit/pass/RuntimeABITest.cpp b/tests/unit/pass/RuntimeABITest.cpp index 6b9446f23..2077ea813 100644 --- a/tests/unit/pass/RuntimeABITest.cpp +++ b/tests/unit/pass/RuntimeABITest.cpp @@ -178,3 +178,42 @@ TEST(RuntimeABI, NonDetLoggerTypeIsUniform) { EXPECT_EQ(Map2Check::nonDetLoggerType(ctx), llvm::FunctionType::get(p, {i32, i32, i32, p, p}, false)); } + +// The alloca type of each nondet logger is the C type of docs/api-deltas.md +// of the library (pointer: void **, pchar: char **, bool: int), and type_var +// is develop's enum NONDET_TYPE (Map2CheckTypes.h:41-58). +TEST(RuntimeABI, NonDetValueSlotsFollowApiDeltas) { + llvm::LLVMContext ctx; + llvm::Type* i8 = llvm::Type::getInt8Ty(ctx); + llvm::Type* i16 = llvm::Type::getInt16Ty(ctx); + llvm::Type* i32 = llvm::Type::getInt32Ty(ctx); + llvm::Type* i64 = llvm::Type::getInt64Ty(ctx); + llvm::Type* p = llvm::PointerType::get(ctx, 0); + llvm::Type* dbl = llvm::Type::getDoubleTy(ctx); + struct Expected { + const char* cType; + llvm::Type* type; + bool isSigned; + int typeVar; + }; + const std::vector expected = { + {"int", i32, true, 0}, {"char", i8, true, 1}, + {"pointer", p, false, 2}, {"ushort", i16, false, 3}, + {"long", i64, true, 4}, {"unsigned", i32, false, 5}, + {"ulong", i64, false, 6}, {"bool", i32, false, 7}, + {"uchar", i8, false, 8}, {"pchar", p, false, 9}, + {"size_t", i64, false, 10}, {"loff_t", i64, true, 11}, + {"sector_t", i64, false, 12}, {"uint", i32, false, 13}, + {"short", i16, true, 14}, {"double", dbl, true, 15}, + }; + for (const Expected& e : expected) { + Map2Check::NonDetValueSlot slot = Map2Check::nonDetValueSlot(e.cType, ctx); + EXPECT_EQ(slot.type, e.type) << e.cType; + EXPECT_EQ(slot.isSigned, e.isSigned) << e.cType; + EXPECT_EQ(slot.typeVar, e.typeVar) << e.cType; + // Every type with a slot has a logger and a generator in the mapping. + EXPECT_FALSE(nonDetLogger(e.cType).empty()) << e.cType; + EXPECT_FALSE(nonDetGenerator(e.cType).empty()) << e.cType; + } + EXPECT_EQ(Map2Check::nonDetValueSlot("float", ctx).type, nullptr); +} diff --git a/tests/unit/pass/inputs/assume_defined.c b/tests/unit/pass/inputs/assume_defined.c new file mode 100644 index 000000000..46749c531 --- /dev/null +++ b/tests/unit/pass/inputs/assume_defined.c @@ -0,0 +1,14 @@ +#include +extern int __VERIFIER_nondet_int(void); +void assume_abort_if_not(int cond) { + if (!cond) abort(); +} +void __VERIFIER_assume(int cond) { + if (!cond) abort(); +} +int main(void) { + int x = __VERIFIER_nondet_int(); + assume_abort_if_not(x > 0); + __VERIFIER_assume(x < 100); + return 0; +} diff --git a/tests/unit/pass/inputs/crab_assume.ll b/tests/unit/pass/inputs/crab_assume.ll new file mode 100644 index 000000000..e3f796411 --- /dev/null +++ b/tests/unit/pass/inputs/crab_assume.ll @@ -0,0 +1,16 @@ +; What Clam leaves in the bitcode: invariants as calls to a nounwind +; verifier.assume(i1) (clam.py --crab-opt=add-invariants). +declare i32 @__VERIFIER_nondet_int() +declare void @verifier.assume(i1) #0 + +define i32 @main() { +entry: + %x = call i32 @__VERIFIER_nondet_int() + %c = icmp sgt i32 %x, 0 + call void @verifier.assume(i1 %c) #0 + %d = icmp slt i32 %x, 100 + call void @verifier.assume(i1 %d) #0 + ret i32 0 +} + +attributes #0 = { nounwind } diff --git a/tests/unit/pass/inputs/nondet_types.c b/tests/unit/pass/inputs/nondet_types.c new file mode 100644 index 000000000..54ad15249 --- /dev/null +++ b/tests/unit/pass/inputs/nondet_types.c @@ -0,0 +1,38 @@ +extern int __VERIFIER_nondet_int(void); +extern unsigned __VERIFIER_nondet_unsigned(void); +extern unsigned __VERIFIER_nondet_uint(void); +extern char __VERIFIER_nondet_char(void); +extern unsigned char __VERIFIER_nondet_uchar(void); +extern short __VERIFIER_nondet_short(void); +extern unsigned short __VERIFIER_nondet_ushort(void); +extern long __VERIFIER_nondet_long(void); +extern unsigned long __VERIFIER_nondet_ulong(void); +extern _Bool __VERIFIER_nondet_bool(void); +extern void *__VERIFIER_nondet_pointer(void); +extern char *__VERIFIER_nondet_pchar(void); +extern unsigned long __VERIFIER_nondet_size_t(void); +extern long long __VERIFIER_nondet_loff_t(void); +extern unsigned long __VERIFIER_nondet_sector_t(void); +extern double __VERIFIER_nondet_double(void); +int main(void) { + int v_int = __VERIFIER_nondet_int(); + unsigned v_unsigned = __VERIFIER_nondet_unsigned(); + unsigned v_uint = __VERIFIER_nondet_uint(); + char v_char = __VERIFIER_nondet_char(); + unsigned char v_uchar = __VERIFIER_nondet_uchar(); + short v_short = __VERIFIER_nondet_short(); + unsigned short v_ushort = __VERIFIER_nondet_ushort(); + long v_long = __VERIFIER_nondet_long(); + unsigned long v_ulong = __VERIFIER_nondet_ulong(); + _Bool v_bool = __VERIFIER_nondet_bool(); + void *v_pointer = __VERIFIER_nondet_pointer(); + char *v_pchar = __VERIFIER_nondet_pchar(); + unsigned long v_size_t = __VERIFIER_nondet_size_t(); + long long v_loff_t = __VERIFIER_nondet_loff_t(); + unsigned long v_sector_t = __VERIFIER_nondet_sector_t(); + double v_double = __VERIFIER_nondet_double(); + return (v_int + (int)v_unsigned + (int)v_uint + v_char + v_uchar + v_short + + v_ushort + (int)v_long + (int)v_ulong + v_bool + (v_pointer != 0) + + (v_pchar != 0) + (int)v_size_t + (int)v_loff_t + (int)v_sector_t + + (int)v_double) & 1; +} From fcfd4e104f8ca94f3c6de1996f623d25a15883b7 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:02:58 -0400 Subject: [PATCH 18/44] fix(pass): drop nounwind from __VERIFIER_assume in LoopPredAssumePass When the program already declares __VERIFIER_assume nounwind, the loop predicate calls reuse that declaration. The library's assume unwinds through them, so the pass now clears nounwind on the declaration and every call (RuntimeABI allowUnwind). loop_assume.ll carries such a declaration; it also backs the NonDetPass nounwind test, since clang -O0 leaves external declarations without nounwind and assume.c could not show the fix. --- modules/backend/pass/LoopPredAssumePass.cpp | 4 +++ tests/unit/pass/PassIRTest.cpp | 17 ++++++++++--- tests/unit/pass/inputs/loop_assume.ll | 27 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 tests/unit/pass/inputs/loop_assume.ll diff --git a/modules/backend/pass/LoopPredAssumePass.cpp b/modules/backend/pass/LoopPredAssumePass.cpp index 6291f1eb3..e1d7bc0e1 100644 --- a/modules/backend/pass/LoopPredAssumePass.cpp +++ b/modules/backend/pass/LoopPredAssumePass.cpp @@ -28,6 +28,10 @@ void LoopPredAssumePass::getConditionInLoop(Loop* L) { BasicBlock* header = L->getHeader(); this->map2check_assume = Map2Check::getOrInsertRuntime( *header->getParent()->getParent(), Map2Check::RuntimeHook::Assume); + // The program may already declare __VERIFIER_assume nounwind; the + // library's assume unwinds through every call to it. + Map2Check::allowUnwind( + *llvm::cast(this->map2check_assume.getCallee())); if (BranchInst* bi = dyn_cast(header->getTerminator())) { if (bi->isConditional()) { Value* loopCond = bi->getCondition(); diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 0971d9435..013572dcf 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -656,10 +656,10 @@ void expectNoNounwind(llvm::Module& m, llvm::StringRef name) { } // namespace -// Compiled without -fexceptions every call is nounwind; the assume of the -// library unwinds, so the pass clears it on the declaration and the calls. +// A nounwind declaration of __VERIFIER_assume (and calls to it): the assume +// of the library unwinds, so the pass clears nounwind on both. TEST(PassIR, NonDetKeepsVerifierAssumeAndDropsNounwind) { - auto m = runPassOn("NonDetPass", "nondet-pass", "assume.c"); + auto m = runPassOn("NonDetPass", "nondet-pass", "loop_assume.ll"); ASSERT_VALID(m); expectCoreCalls(*m, RuntimeHook::Assume); EXPECT_EQ(m->getFunction("map2check_assume"), nullptr); @@ -716,3 +716,14 @@ TEST(PassIR, NonDetRewritesAbortingAssumes) { expectNoNounwind(*m, "__VERIFIER_assume"); expectNoNounwind(*m, "assume_abort_if_not"); } + +// The loop predicate goes to the program's own __VERIFIER_assume declaration +// when there is one; without -fexceptions that declaration and its calls are +// nounwind, and the library's assume unwinds through them. +TEST(PassIR, LoopPredAssumeDropsNounwind) { + auto m = runPassOn("LoopPredAssumePass", "loop-pred-assume", "loop_assume.ll"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::Assume); + EXPECT_EQ(callsTo(*m, "__VERIFIER_assume").size(), 2u); + expectNoNounwind(*m, "__VERIFIER_assume"); +} diff --git a/tests/unit/pass/inputs/loop_assume.ll b/tests/unit/pass/inputs/loop_assume.ll new file mode 100644 index 000000000..5ce49c323 --- /dev/null +++ b/tests/unit/pass/inputs/loop_assume.ll @@ -0,0 +1,27 @@ +; A loop in a program that already calls a nounwind __VERIFIER_assume (as a +; frontend, or clang on a definition without -fexceptions, can leave it). +declare i32 @__VERIFIER_nondet_int() +declare void @__VERIFIER_assume(i32) #0 + +define i32 @main() { +entry: + %n = call i32 @__VERIFIER_nondet_int() + %c = icmp slt i32 %n, 10 + %cz = zext i1 %c to i32 + call void @__VERIFIER_assume(i32 %cz) #0 + br label %loop + +loop: + %i = phi i32 [ 0, %entry ], [ %inc, %body ] + %cmp = icmp slt i32 %i, %n + br i1 %cmp, label %body, label %exit + +body: + %inc = add nsw i32 %i, 1 + br label %loop + +exit: + ret i32 %i +} + +attributes #0 = { nounwind } From 113734de927e96e9be1273e486f26744af58fdf8 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:08:02 -0400 Subject: [PATCH 19/44] feat(pass): emit the memory API of map2check-library from MemoryTrackPass Every runtime call of MemoryTrackPass goes through RuntimeABI with the core order and widths (sizes, lines and scopes are i32): - malloc/valloc/calloc/realloc/posix_memalign -> map_malloc, map_calloc, map_posix_memalign; realloc checks its old block with check_free_resolved_address (is_null_valid i16 1); - globals, allocas and alloca() -> map_alloca; a VLA -> map_non_static_alloca with its element count; - loads, stores, memset, memcpy -> check_load(ptr, line, scope, size, fn), which records the violation itself, so check_deref is gone; - stores of pointers -> map_store_pointer; - free(var) -> load *slot, skip NULL, then check_free and map_free, both (name, slot, *slot, scope, line, fn), guarded after the walk; free(expr) -> check_free_resolved_address (is_null_valid 0); - the wasm2c hooks keep their names (wasm_free takes an i64 line). Instructions tagged map2check.runtime (NonDetPass's value slots) are not tracked. The dead, type-unsafe instrumentFunctionArgumentAddress is gone. PassIR tests cover each hook's callee, type and arguments, the free guard, and the wasm mode. --- modules/backend/pass/MemoryTrackPass.cpp | 741 ++++++++--------------- modules/backend/pass/MemoryTrackPass.hpp | 41 +- tests/unit/pass/PassIRTest.cpp | 315 +++++++++- tests/unit/pass/inputs/memtrack.c | 20 + tests/unit/pass/inputs/wasm.ll | 17 + 5 files changed, 636 insertions(+), 498 deletions(-) create mode 100644 tests/unit/pass/inputs/memtrack.c create mode 100644 tests/unit/pass/inputs/wasm.ll diff --git a/modules/backend/pass/MemoryTrackPass.cpp b/modules/backend/pass/MemoryTrackPass.cpp index a35477a80..488b031dc 100644 --- a/modules/backend/pass/MemoryTrackPass.cpp +++ b/modules/backend/pass/MemoryTrackPass.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2014 - 2020 Map2Check tool + * Copyright (C) 2014 - 2026 Map2Check tool * This file is part of the Map2Check tool, and is made available under * the terms of the GNU General Public License version 2. * @@ -8,6 +8,10 @@ * SPDX-License-Identifier: (GPL-2.0 AND NCSA) **/ +// Memory tracking against the core API of map2check-library: every runtime +// call is a RuntimeHook (RuntimeABI.hpp), with the argument order and widths +// of docs/cutover/abi-mapping.tsv. + #include "MemoryTrackPass.hpp" #include @@ -15,6 +19,9 @@ #include #include #include +#include + +#include "RuntimeABI.hpp" static llvm::cl::opt MemTrackEntryFunction( "m2c-entry-function", @@ -28,11 +35,8 @@ static llvm::cl::opt WasmMode( // using namespace llvm; using llvm::AllocaInst; -using llvm::APInt; -using llvm::Argument; using llvm::BasicBlock; using llvm::CallInst; -using llvm::CastInst; using llvm::ConstantInt; using llvm::DataLayout; using llvm::DebugLoc; @@ -44,67 +48,30 @@ using llvm::IRBuilder; using llvm::LoadInst; using llvm::Module; using llvm::StoreInst; -using llvm::StructType; -using llvm::Twine; using llvm::Type; using llvm::Value; - -// std::string infoFile = "witnessInfo"; -// std::string echoCommand = "echo"; -// TODO(hbgit): Work with other types -// FIX: It it not current function - -/** - void MemoryTrackPass::addWitnessInfo(std::string info) { -// int result = system(info.c_str()); -// If result != 0 means that something gone wrong -}**/ +using Map2Check::RuntimeHook; namespace { inline Instruction *BBIteratorToInst(BasicBlock::iterator i) { Instruction *pointer = reinterpret_cast(&*i); return pointer; } -} // namespace - -// TODO(hbgit): make dynCast only one time -void MemoryTrackPass::instrumentPointer() { - StoreInst *storeInst = dyn_cast(&*this->currentInstruction); - Value *var_address = storeInst->getPointerOperand(); - Value *receives = storeInst->getValueOperand(); - - auto j = this->currentInstruction; - - Twine bitcast("bitcast"); - - Value *varPointerCast = - CastInst::CreatePointerCast(var_address, PointerType::get(*this->Ctx, 0), - bitcast, BBIteratorToInst(j)); - - Value *receivesPointerCast = CastInst::CreatePointerCast( - receives, PointerType::get(*this->Ctx, 0), bitcast, BBIteratorToInst(j)); - - ++j; - IRBuilder<> builder(BBIteratorToInst(j)); - Value *name_llvm = builder.CreateGlobalStringPtr(var_address->getName()); - - Value *function_llvm = - builder.CreateGlobalStringPtr(currentFunction->getName()); - - Value *args[] = {varPointerCast, receivesPointerCast, this->scope_value, - name_llvm, this->line_value, function_llvm}; - - builder.CreateCall(this->map2check_pointer, args); +/// True for what a pass added for the runtime's own use (NonDetPass's value +/// slots): not program memory, so neither tracked nor checked. +bool isRuntimeOwned(const Value *value) { + auto *inst = dyn_cast(value->stripPointerCasts()); + return inst != nullptr && inst->hasMetadata(Map2Check::kRuntimeMetadata); } +} // namespace -/** Widens or narrows a size operand to the type the runtime call declares. +/** Widens or narrows an integer operand to the type the runtime call declares. * * The allocation size is taken straight from the program's own call, and its - * type is whatever that program declared. The runtime helpers are registered - * with an i64 size, so any program allocating with a narrower integer produced - * a call whose argument type did not match its signature -- and LLVM rejects - * the module outright: + * type is whatever that program declared, while the core API takes int32_t + * sizes. A call whose argument type did not match its signature made LLVM + * reject the module outright: * * Call parameter type does not match function signature! * LLVM ERROR: Broken module found, compilation aborted! @@ -124,157 +91,130 @@ static Value *coerceToParamType(IRBuilder<> &builder, Value *value, // value back is what preserves it either way. return builder.CreateSExtOrTrunc(value, wanted); } + if (value->getType()->isPointerTy() && wanted->isPointerTy()) { + return builder.CreatePointerCast(value, wanted); + } return value; } -void MemoryTrackPass::instrumentPosixMemAllign() { - CallInst *callInst = dyn_cast(&*this->currentInstruction); +static ConstantInt *i32Constant(LLVMContext *ctx, uint64_t value) { + return ConstantInt::get(Type::getInt32Ty(*ctx), value); +} - this->calleeFunction = callInst->getCalledFunction(); +Value *MemoryTrackPass::functionName() { + if (this->functionNameValue == nullptr) { + IRBuilder<> builder( + &*this->currentFunction->getEntryBlock().getFirstInsertionPt()); + this->functionNameValue = + builder.CreateGlobalStringPtr(this->currentFunction->getName()); + } + return this->functionNameValue; +} - auto j = this->currentInstruction; - ++j; +// abi-mapping: map2check_add_store_pointer -> map2check_map_store_pointer +// (var, value, scope, name, line, fn), after the store. +void MemoryTrackPass::instrumentPointer() { + StoreInst *storeInst = dyn_cast(&*this->currentInstruction); + Value *var_address = storeInst->getPointerOperand(); + Value *receives = storeInst->getValueOperand(); - // Adds map2check_malloc with allocated address and size - IRBuilder<> builder(BBIteratorToInst(j)); - auto size = callInst->getArgOperand(2); - auto pointer = callInst->getOperand(0); + IRBuilder<> builder(storeInst->getNextNode()); + Value *name_llvm = builder.CreateGlobalStringPtr(var_address->getName()); - Twine bitcast("bitcast"); + Value *args[] = {coerceToParamType(builder, var_address, storePointer, 0), + coerceToParamType(builder, receives, storePointer, 1), + this->scope_value, + name_llvm, + this->line_value, + this->functionName()}; + builder.CreateCall(this->storePointer, args); +} - Value *varPointerCast = CastInst::CreatePointerCast( - pointer, PointerType::get(*this->Ctx, 0), bitcast, BBIteratorToInst(j)); +// abi-mapping: map2check_posix -> map2check_map_posix_memalign(memptr, i32). +void MemoryTrackPass::instrumentPosixMemAllign() { + CallInst *callInst = dyn_cast(&*this->currentInstruction); - Value *args[] = {varPointerCast, - coerceToParamType(builder, size, map2check_posix, 1)}; - builder.CreateCall(map2check_posix, args); + IRBuilder<> builder(callInst->getNextNode()); + Value *size = callInst->getArgOperand(2); + Value *pointer = callInst->getArgOperand(0); + + Value *args[] = {coerceToParamType(builder, pointer, mapPosixMemalign, 0), + coerceToParamType(builder, size, mapPosixMemalign, 1)}; + builder.CreateCall(mapPosixMemalign, args); } -// TODO(hbgit): make dynCast only one time +// abi-mapping: map2check_malloc -> map2check_map_malloc(block, i32 size). void MemoryTrackPass::instrumentMalloc() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - ++j; - - // Adds map2check_malloc with allocated address and size - IRBuilder<> builder(BBIteratorToInst(j)); + IRBuilder<> builder(callInst->getNextNode()); Value *size = callInst->getArgOperand(0); - Twine bitcast("bitcast"); - // if (size == NULL) { - // } - Value *args[] = {callInst, - coerceToParamType(builder, size, map2check_malloc, 1)}; - builder.CreateCall(map2check_malloc, args); + Value *args[] = {callInst, coerceToParamType(builder, size, mapMalloc, 1)}; + builder.CreateCall(mapMalloc, args); } +// realloc(old, n): the old block goes through the resolved-address free check +// (NULL is valid here, is_null_valid 1), which records the release when it +// passes; the new block is mapped as a malloc. void MemoryTrackPass::instrumentRealloc() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - IRBuilder<> freeBuilder(BBIteratorToInst(j)); - auto function_name = this->currentFunction->getName(); - Value *function_llvm = freeBuilder.CreateGlobalStringPtr(function_name); - - Value *nullValid = ConstantInt::getSigned(Type::getInt1Ty(*this->Ctx), 1); - - Value *freeArgs[] = {callInst->getArgOperand(0), this->line_value, - function_llvm, nullValid}; - - freeBuilder.CreateCall(map2check_free_resolved_address, freeArgs); + IRBuilder<> freeBuilder(callInst); - ++j; + Value *nullValid = ConstantInt::get(Type::getInt16Ty(*this->Ctx), 1); + Value *freeArgs[] = { + coerceToParamType(freeBuilder, callInst->getArgOperand(0), + checkFreeResolved, 0), + this->line_value, this->functionName(), nullValid}; + freeBuilder.CreateCall(checkFreeResolved, freeArgs); - // Adds map2check_malloc with allocated address and size - IRBuilder<> builder(BBIteratorToInst(j)); - auto size = callInst->getArgOperand(1); - Value *args[] = {callInst, - coerceToParamType(builder, size, map2check_malloc, 1)}; - builder.CreateCall(map2check_malloc, args); + IRBuilder<> builder(callInst->getNextNode()); + Value *size = callInst->getArgOperand(1); + Value *args[] = {callInst, coerceToParamType(builder, size, mapMalloc, 1)}; + builder.CreateCall(mapMalloc, args); } +// abi-mapping: map2check_load + map2check_check_deref -> map2check_check_load +// (ptr, line, scope, size, fn); check_load records the violation itself. // BUG on map2check_load void MemoryTrackPass::instrumentMemset() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; + IRBuilder<> builder(callInst); - auto function_name = this->currentFunction->getName(); + Value *size = callInst->getArgOperand(2); + Value *pointer = callInst->getArgOperand(0); - auto size = callInst->getArgOperand(2); - auto pointer = callInst->getOperand(0); - - Twine bitcast("bitcast"); - - Value *varPointerCast = CastInst::CreatePointerCast( - pointer, PointerType::get(*this->Ctx, 0), bitcast, BBIteratorToInst(j)); - - IRBuilder<> builder(BBIteratorToInst(j)); - Value *function_llvm = builder.CreateGlobalStringPtr(function_name); - - // Value *args[] = {varPointerCast, size}; - Value *args[] = {pointer, size}; - builder.CreateCall(map2check_load, args); - - Value *args2[] = {this->line_value, function_llvm}; - builder.CreateCall(map2check_check_deref, args2); + Value *args[] = {coerceToParamType(builder, pointer, checkLoad, 0), + this->line_value, this->scope_value, + coerceToParamType(builder, size, checkLoad, 3), + this->functionName()}; + builder.CreateCall(checkLoad, args); } void MemoryTrackPass::instrumentMemcpy() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - - auto function_name = this->currentFunction->getName(); - - auto size = callInst->getArgOperand(2); - auto pointer_destiny = callInst->getOperand(0); - auto pointer_origin = callInst->getArgOperand(1); - - Twine bitcast("bitcast_memcpy"); - - Value *varPointerCast = CastInst::CreatePointerCast( - pointer_destiny, PointerType::get(*this->Ctx, 0), bitcast, - BBIteratorToInst(j)); - - Value *sizeCast = CastInst::CreateIntegerCast( - size, Type::getInt64Ty(*this->Ctx), true, bitcast, BBIteratorToInst(j)); - - Value *varPointerCastOrigin = CastInst::CreatePointerCast( - pointer_origin, PointerType::get(*this->Ctx, 0), bitcast, - BBIteratorToInst(j)); - - IRBuilder<> builder(BBIteratorToInst(j)); - Value *function_llvm = builder.CreateGlobalStringPtr(function_name); - - Value *args2[] = {varPointerCastOrigin, sizeCast}; - builder.CreateCall(map2check_load, args2); - - Value *args3[] = {this->line_value, function_llvm}; - // builder.CreateCall(map2check_check_deref, args3); - - Value *args[] = {varPointerCast, sizeCast}; - builder.CreateCall(map2check_load, args); - builder.CreateCall(map2check_load, args2); - builder.CreateCall(map2check_check_deref, args3); + IRBuilder<> builder(callInst); + + Value *size = coerceToParamType(builder, callInst->getArgOperand(2), + checkLoad, 3); + for (Value *pointer : + {callInst->getArgOperand(1), callInst->getArgOperand(0)}) { + Value *args[] = {coerceToParamType(builder, pointer, checkLoad, 0), + this->line_value, this->scope_value, size, + this->functionName()}; + builder.CreateCall(checkLoad, args); + } } +// alloca(n) called as a function: a static block of n bytes. void MemoryTrackPass::instrumentAlloca() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - ++j; + IRBuilder<> builder(callInst->getNextNode()); + Value *size = coerceToParamType(builder, callInst->getArgOperand(0), + mapAlloca, 2); - // Adds map2check_malloc with allocated address and size - IRBuilder<> builder(BBIteratorToInst(j)); - auto size = callInst->getArgOperand(0); - - Twine non_det("bitcast_map2check_alloca"); - Value *pointerCast = CastInst::CreatePointerCast( - callInst, PointerType::get(*this->Ctx, 0), non_det, BBIteratorToInst(j)); - - auto function_name = ""; - Value *function_llvm = builder.CreateGlobalStringPtr(function_name); - - Value *args[] = {function_llvm, pointerCast, size, + Value *function_llvm = builder.CreateGlobalStringPtr(""); + Value *args[] = {function_llvm, callInst, size, size, this->line_value, this->scope_value}; - - builder.CreateCall(map2check_alloca, args); + builder.CreateCall(mapAlloca, args); } /* For the purpose of memory checking calloc is basically @@ -283,64 +223,59 @@ void MemoryTrackPass::instrumentAlloca() { */ void MemoryTrackPass::instrumentCalloc() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - ++j; - - IRBuilder<> builder(BBIteratorToInst(j)); - auto quantityOfElements = callInst->getArgOperand(0); - auto sizeOfElements = callInst->getArgOperand(1); - Value *args[] = {callInst, quantityOfElements, sizeOfElements}; - builder.CreateCall(map2check_calloc, args); + IRBuilder<> builder(callInst->getNextNode()); + Value *args[] = { + callInst, + coerceToParamType(builder, callInst->getArgOperand(0), mapCalloc, 1), + coerceToParamType(builder, callInst->getArgOperand(1), mapCalloc, 2)}; + builder.CreateCall(mapCalloc, args); } -// TODO(hbgit): make dynCast only one time +// abi-mapping: map2check_free -> map2check_check_free + map2check_map_free. +// free(var) is recorded here and instrumented after the walk; free of any +// other address is one resolved-address check (is_null_valid 0). void MemoryTrackPass::instrumentFree() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - // ++j; - - this->calleeFunction = callInst->getCalledFunction(); - this->getDebugInfo(); - LoadInst *li; - IRBuilder<> builder(BBIteratorToInst(j)); + auto *li = + dyn_cast(callInst->getArgOperand(0)->stripPointerCasts()); - auto function_name = this->currentFunction->getName(); - Value *function_llvm = builder.CreateGlobalStringPtr(function_name); - - if (this->calleeFunction == NULL) { - Value *v = callInst->getCalledOperand(); - this->calleeFunction = dyn_cast(v->stripPointerCasts()); - li = dyn_cast(callInst->getArgOperand(0)); - - } else { - // Value* addr = callInst->getArgOperand(0)->stripPointerCasts(); - - li = dyn_cast(callInst->getArgOperand(0)->stripPointerCasts()); + if (li != nullptr && li->getType()->isPointerTy()) { + this->pendingFrees.push_back( + {callInst, li->getPointerOperand(), this->line_value, + this->scope_value}); + return; } - if (li == NULL) { - Value *nullNotValid = - ConstantInt::getSigned(Type::getInt1Ty(*this->Ctx), 0); - - Value *args[] = {callInst->getArgOperand(0), this->line_value, - function_llvm, nullNotValid}; - builder.CreateCall(map2check_free_resolved_address, args); - } else { - auto name = li->getPointerOperand()->getName(); - Value *name_llvm = builder.CreateGlobalStringPtr(name); - - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - li->getPointerOperand(), PointerType::get(*this->Ctx, 0), non_det, - BBIteratorToInst(j)); - - Value *args[] = { - name_llvm, pointerCast, this->scope_value, - this->line_value, function_llvm, - }; - - builder.CreateCall(map2check_free, args); + IRBuilder<> builder(callInst); + Value *nullNotValid = ConstantInt::get(Type::getInt16Ty(*this->Ctx), 0); + Value *args[] = {coerceToParamType(builder, callInst->getArgOperand(0), + checkFreeResolved, 0), + this->line_value, this->functionName(), nullNotValid}; + builder.CreateCall(checkFreeResolved, args); +} + +// The core keys the release on the heap address, and the C runtime read it +// from the pointer variable's slot: load *slot right before the free, skip +// both calls for NULL as the C runtime did, else check_free then map_free, +// both (name, slot, *slot, scope, line, fn). +void MemoryTrackPass::instrumentPendingFrees() { + for (const PendingFree &pending : this->pendingFrees) { + IRBuilder<> builder(pending.call); + Value *name_llvm = + builder.CreateGlobalStringPtr(pending.slot->getName()); + Value *slot = coerceToParamType(builder, pending.slot, checkFree, 1); + LoadInst *block = builder.CreateLoad(PointerType::get(*this->Ctx, 0), slot, + "map2check.freed"); + Value *nonNull = builder.CreateIsNotNull(block); + Instruction *then = llvm::SplitBlockAndInsertIfThen( + nonNull, pending.call, /*Unreachable=*/false); + IRBuilder<> guarded(then); + Value *args[] = {name_llvm, slot, block, + pending.scope, pending.line, this->functionName()}; + guarded.CreateCall(checkFree, args)->setDebugLoc(pending.call->getDebugLoc()); + guarded.CreateCall(mapFree, args)->setDebugLoc(pending.call->getDebugLoc()); } + this->pendingFrees.clear(); } void MemoryTrackPass::getDebugInfo() { @@ -356,10 +291,8 @@ void MemoryTrackPass::getDebugInfo() { line_number = 0; } - this->scope_value = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), scope_number); - this->line_value = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), line_number); + this->scope_value = i32Constant(this->Ctx, scope_number); + this->line_value = i32Constant(this->Ctx, line_number); } int MemoryTrackPass::getLineNumber() { @@ -373,6 +306,7 @@ int MemoryTrackPass::getLineNumber() { return line_number; } +// Globals are mapped as static blocks at the start of the entry function. void MemoryTrackPass::instrumentInit() { Function::iterator bb = this->currentFunction->begin(); BasicBlock::iterator i = bb->begin(); @@ -389,7 +323,6 @@ void MemoryTrackPass::instrumentInit() { for (unsigned pos = 0; pos < globals.size(); pos++) { GlobalVariable *variable = globals[pos]; - // errs () << "VAR: " << variable->getName() << "\n"; const DataLayout dataLayout = currentModule->getDataLayout(); auto type = variable->getValueType(); unsigned typeSize = dataLayout.getTypeSizeInBits(type) / 8; @@ -407,33 +340,18 @@ void MemoryTrackPass::instrumentInit() { Value *name_llvm = builder.CreateGlobalStringPtr(variable->getName()); - ConstantInt *typeSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), typeSize); - ConstantInt *primitiveSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), primitiveSize); - - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - variable, PointerType::get(*this->Ctx, 0), non_det, BBIteratorToInst(i)); - // TODO(hbgit): this->currentInstruction = i; this->getDebugInfo(); - /** - errs() << *name_llvm << " (1) \n"; - errs() << *pointerCast << " (2) \n"; - errs() << *typeSizeValue << " (3) \n"; - errs() << *primitiveSizeValue << " (4) \n"; - errs() << *this->line_value << " (5) \n"; - errs() << *this->scope_value << " (6) \n"; - errs() << "----------------- \n"; - **/ - - // const char* name, void* ptr, int size, int size_of_primitive, int line, - // int scope) - Value *args[] = {name_llvm, pointerCast, typeSizeValue, - primitiveSizeValue, this->line_value, this->scope_value}; - builder.CreateCall(map2check_alloca, args); + + // (name, addr, size, size_of_primitive, line, scope) + Value *args[] = {name_llvm, + variable, + i32Constant(this->Ctx, typeSize), + i32Constant(this->Ctx, primitiveSize), + this->line_value, + this->scope_value}; + builder.CreateCall(mapAlloca, args); } } @@ -450,11 +368,10 @@ bool MemoryTrackPass::isWasmDeallocator(llvm::StringRef name) { return name.endswith("_dlfree") || name.endswith("_free"); } +// abi-mapping: map2check_wasm_malloc(u64 offset, u64 size). void MemoryTrackPass::instrumentWasmMalloc() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - ++j; - IRBuilder<> builder(BBIteratorToInst(j)); + IRBuilder<> builder(callInst->getNextNode()); // Arg 1 = size (i32) Value *size32 = callInst->getArgOperand(1); @@ -464,20 +381,22 @@ void MemoryTrackPass::instrumentWasmMalloc() { Value *offset64 = builder.CreateZExt(callInst, Type::getInt64Ty(*this->Ctx)); Value *args[] = {offset64, size64}; - builder.CreateCall(map2check_wasm_malloc, args); + builder.CreateCall(wasmMalloc, args); } +// abi-mapping: map2check_wasm_free(u64 offset, i64 line). void MemoryTrackPass::instrumentWasmFree() { CallInst *callInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - IRBuilder<> builder(BBIteratorToInst(j)); + IRBuilder<> builder(callInst); // Arg 1 = offset (i32) → i64 Value *offset32 = callInst->getArgOperand(1); Value *offset64 = builder.CreateZExt(offset32, Type::getInt64Ty(*this->Ctx)); + Value *line64 = + builder.CreateSExt(this->line_value, Type::getInt64Ty(*this->Ctx)); - Value *args[] = {offset64, this->line_value}; - builder.CreateCall(map2check_wasm_free, args); + Value *args[] = {offset64, line64}; + builder.CreateCall(wasmFree, args); } void MemoryTrackPass::switchCallInstruction() { @@ -525,6 +444,8 @@ void MemoryTrackPass::switchCallInstruction() { } } +// abi-mapping: map2check_function -> map2check_map_funct_address(name, addr). +// Not called from run() (as before the cutover). void MemoryTrackPass::instrumentFunctionAddress() { if (!this->mainFunctionInitialized) { this->functionsValues.push_back(this->currentFunction); @@ -532,8 +453,6 @@ void MemoryTrackPass::instrumentFunctionAddress() { } Function::iterator bb = this->mainFunction->begin(); - // // bb--; - BasicBlock::iterator i = bb->begin(); i++; @@ -542,14 +461,9 @@ void MemoryTrackPass::instrumentFunctionAddress() { iterator++) { Value *name_llvm = builder.CreateGlobalStringPtr( this->functionsValues[iterator]->getName()); - - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - this->functionsValues[iterator], PointerType::get(*this->Ctx, 0), - non_det, BBIteratorToInst(i)); - - Value *instrumentationArgs[] = {name_llvm, pointerCast}; - builder.CreateCall(map2check_function, instrumentationArgs); + Value *instrumentationArgs[] = {name_llvm, + this->functionsValues[iterator]}; + builder.CreateCall(mapFunctAddress, instrumentationArgs); } this->functionsValues.clear(); @@ -558,9 +472,6 @@ void MemoryTrackPass::instrumentFunctionAddress() { void MemoryTrackPass::instrumentAllocation() { AllocaInst *allocaInst = dyn_cast(&*this->currentInstruction); - auto j = this->currentInstruction; - j++; - Module *M = this->currentFunction->getParent(); const DataLayout dataLayout = M->getDataLayout(); @@ -579,21 +490,16 @@ void MemoryTrackPass::instrumentAllocation() { } primitiveSize = dataLayout.getTypeSizeInBits(type) / 8; - IRBuilder<> builder(BBIteratorToInst(j)); + IRBuilder<> builder(allocaInst->getNextNode()); Value *name_llvm = builder.CreateGlobalStringPtr(allocaInst->getName()); - ConstantInt *typeSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), typeSize); - ConstantInt *primitiveSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), primitiveSize); - - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - allocaInst, PointerType::get(*this->Ctx, 0), non_det, BBIteratorToInst(j)); - - Value *args[] = {name_llvm, pointerCast, typeSizeValue, - primitiveSizeValue, this->line_value, this->scope_value}; - builder.CreateCall(map2check_alloca, args); + Value *args[] = {name_llvm, + allocaInst, + i32Constant(this->Ctx, typeSize), + i32Constant(this->Ctx, primitiveSize), + this->line_value, + this->scope_value}; + builder.CreateCall(mapAlloca, args); } // TODO(hbgit): make dynCast only one time @@ -616,7 +522,7 @@ void MemoryTrackPass::runOnCallInstruction() { this->calleeFunction = NULL; } -// TODO(hbgit): make dynCast only one time +// A store is checked like a load of the stored size, before it happens. void MemoryTrackPass::runOnStoreInstruction() { StoreInst *storeInst = dyn_cast(&*this->currentInstruction); if (storeInst->getValueOperand()->getType()->isPointerTy()) { @@ -629,94 +535,57 @@ void MemoryTrackPass::runOnStoreInstruction() { Module *M = this->currentFunction->getParent(); const DataLayout dataLayout = M->getDataLayout(); - auto type = receives->getType(); - unsigned typeSize = dataLayout.getTypeSizeInBits(type) / 8; - ConstantInt *typeSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), typeSize); - - auto j = this->currentInstruction; - // j--; + unsigned typeSize = dataLayout.getTypeSizeInBits(receives->getType()) / 8; - Twine non_det("bitcast_map2check_store"); - Value *pointerCast = - CastInst::CreatePointerCast(var_address, PointerType::get(*this->Ctx, 0), - non_det, BBIteratorToInst(j)); - // j++; - IRBuilder<> builder(BBIteratorToInst(j)); - Value *args[] = {pointerCast, typeSizeValue}; - builder.CreateCall(map2check_load, args); - - Value *function_name_llvm = - builder.CreateGlobalStringPtr(this->currentFunction->getName()); - Value *args2[] = {this->line_value, function_name_llvm}; - builder.CreateCall(map2check_check_deref, args2); + IRBuilder<> builder(storeInst); + Value *args[] = {coerceToParamType(builder, var_address, checkLoad, 0), + this->line_value, this->scope_value, + i32Constant(this->Ctx, typeSize), this->functionName()}; + builder.CreateCall(checkLoad, args); } +// abi-mapping: map2check_non_static_alloca: the size is the element count; +// the core records count * size_primitive bytes. void MemoryTrackPass::instrumentNotStaticArrayAlloca() { AllocaInst *allocaInst = dyn_cast(&*this->currentInstruction); Value *v = allocaInst->getArraySize(); - // Value* v = allocaInst->getOperand(0); - - auto j = this->currentInstruction; - j++; Module *M = this->currentFunction->getParent(); const DataLayout dataLayout = M->getDataLayout(); auto type = allocaInst->getAllocatedType(); - unsigned primitiveSize = 0; - // type->get - - primitiveSize = dataLayout.getTypeSizeInBits(type) / 8; - IRBuilder<> builder(BBIteratorToInst(j)); + unsigned primitiveSize = dataLayout.getTypeSizeInBits(type) / 8; + IRBuilder<> builder(allocaInst->getNextNode()); Value *name_llvm = builder.CreateGlobalStringPtr(allocaInst->getName()); - ConstantInt *primitiveSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), primitiveSize); - - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - allocaInst, PointerType::get(*this->Ctx, 0), non_det, BBIteratorToInst(j)); - - Value *sizeCast = CastInst::CreateIntegerCast( - v, Type::getInt64Ty(*this->Ctx), true, non_det, BBIteratorToInst(j)); - - Value *args[] = {name_llvm, pointerCast, sizeCast, - primitiveSizeValue, this->line_value, this->scope_value}; - builder.CreateCall(map2check_non_static_alloca, args); + Value *args[] = {name_llvm, + allocaInst, + coerceToParamType(builder, v, mapNonStaticAlloca, 2), + i32Constant(this->Ctx, primitiveSize), + this->line_value, + this->scope_value}; + builder.CreateCall(mapNonStaticAlloca, args); } void MemoryTrackPass::instrumentArrayAlloca() { AllocaInst *allocaInst = dyn_cast(&*this->currentInstruction); Value *v = allocaInst->getArraySize(); - // Value* v = allocaInst->getOperand(0); - - auto j = this->currentInstruction; - j++; Module *M = this->currentFunction->getParent(); const DataLayout dataLayout = M->getDataLayout(); auto type = v->getType(); - unsigned primitiveSize = 0; - - primitiveSize = dataLayout.getTypeSizeInBits(type) / 8; - IRBuilder<> builder(BBIteratorToInst(j)); + unsigned primitiveSize = dataLayout.getTypeSizeInBits(type) / 8; + IRBuilder<> builder(allocaInst->getNextNode()); Value *name_llvm = builder.CreateGlobalStringPtr(allocaInst->getName()); - ConstantInt *primitiveSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), primitiveSize); - - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - allocaInst, PointerType::get(*this->Ctx, 0), non_det, BBIteratorToInst(j)); - - Value *sizeCast = CastInst::CreateIntegerCast( - v, Type::getInt64Ty(*this->Ctx), true, non_det, BBIteratorToInst(j)); - - Value *args[] = {name_llvm, pointerCast, sizeCast, - primitiveSizeValue, this->line_value, this->scope_value}; - builder.CreateCall(map2check_alloca, args); + Value *args[] = {name_llvm, + allocaInst, + coerceToParamType(builder, v, mapAlloca, 2), + i32Constant(this->Ctx, primitiveSize), + this->line_value, + this->scope_value}; + builder.CreateCall(mapAlloca, args); } void MemoryTrackPass::runOnAllocaInstruction() { @@ -734,6 +603,8 @@ void MemoryTrackPass::runOnAllocaInstruction() { } } +// abi-mapping: map2check_load (+ check_deref) -> map2check_check_load +// (ptr, line, scope, size, fn), before the load. void MemoryTrackPass::runOnLoadInstruction() { LoadInst *loadInst = dyn_cast(&*this->currentInstruction); @@ -742,142 +613,42 @@ void MemoryTrackPass::runOnLoadInstruction() { Module *M = this->currentFunction->getParent(); const DataLayout dataLayout = M->getDataLayout(); - auto type = loadInst->getType(); - unsigned typeSize = dataLayout.getTypeSizeInBits(type) / 8; - ConstantInt *typeSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), typeSize); - - auto j = this->currentInstruction; - // j--; + unsigned typeSize = dataLayout.getTypeSizeInBits(loadInst->getType()) / 8; - Twine non_det("bitcast_map2check"); - Value *pointerCast = CastInst::CreatePointerCast( - v, PointerType::get(*this->Ctx, 0), non_det, BBIteratorToInst(j)); - // j++; - IRBuilder<> builder(BBIteratorToInst(j)); - Value *args[] = {pointerCast, typeSizeValue}; - builder.CreateCall(map2check_load, args); - - Value *function_name_llvm = - builder.CreateGlobalStringPtr(this->currentFunction->getName()); - Value *args2[] = {this->line_value, function_name_llvm}; - builder.CreateCall(map2check_check_deref, args2); + IRBuilder<> builder(loadInst); + Value *args[] = {coerceToParamType(builder, v, checkLoad, 0), + this->line_value, this->scope_value, + i32Constant(this->Ctx, typeSize), this->functionName()}; + builder.CreateCall(checkLoad, args); } void MemoryTrackPass::prepareMap2CheckInstructions() { - Function &F = *this->currentFunction; - - this->map2check_load = F.getParent()->getOrInsertFunction( - "map2check_load", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), Type::getInt64Ty(*this->Ctx)); - - this->map2check_free_resolved_address = F.getParent()->getOrInsertFunction( - "map2check_free_resolved_address", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), Type::getInt64Ty(*this->Ctx), - PointerType::get(*this->Ctx, 0), Type::getInt1Ty(*this->Ctx)); - - this->map2check_pointer = F.getParent()->getOrInsertFunction( - "map2check_add_store_pointer", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), PointerType::get(*this->Ctx, 0), - Type::getInt64Ty(*this->Ctx), PointerType::get(*this->Ctx, 0), - Type::getInt64Ty(*this->Ctx), PointerType::get(*this->Ctx, 0)); - - this->map2check_check_deref = F.getParent()->getOrInsertFunction( - "map2check_check_deref", Type::getVoidTy(*this->Ctx), - Type::getInt64Ty(*this->Ctx), PointerType::get(*this->Ctx, 0)); - - this->map2check_malloc = F.getParent()->getOrInsertFunction( - "map2check_malloc", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), Type::getInt64Ty(*this->Ctx)); - - this->map2check_posix = F.getParent()->getOrInsertFunction( - "map2check_posix", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), Type::getInt64Ty(*this->Ctx)); - - this->map2check_calloc = F.getParent()->getOrInsertFunction( - "map2check_calloc", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), Type::getInt64Ty(*this->Ctx), - Type::getInt64Ty(*this->Ctx)); - - this->map2check_alloca = F.getParent()->getOrInsertFunction( - "map2check_alloca", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), PointerType::get(*this->Ctx, 0), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx)); - - this->map2check_non_static_alloca = F.getParent()->getOrInsertFunction( - "map2check_non_static_alloca", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), PointerType::get(*this->Ctx, 0), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx)); - - this->map2check_function = F.getParent()->getOrInsertFunction( - "map2check_function", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), PointerType::get(*this->Ctx, 0)); - - this->map2check_free = F.getParent()->getOrInsertFunction( - "map2check_free", Type::getVoidTy(*this->Ctx), - PointerType::get(*this->Ctx, 0), PointerType::get(*this->Ctx, 0), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx), - PointerType::get(*this->Ctx, 0)); + Module &module = *this->currentFunction->getParent(); + + this->checkLoad = Map2Check::getOrInsertRuntime(module, RuntimeHook::Load); + this->checkFreeResolved = + Map2Check::getOrInsertRuntime(module, RuntimeHook::FreeResolved); + this->storePointer = + Map2Check::getOrInsertRuntime(module, RuntimeHook::StorePointer); + this->mapMalloc = Map2Check::getOrInsertRuntime(module, RuntimeHook::Malloc); + this->mapPosixMemalign = + Map2Check::getOrInsertRuntime(module, RuntimeHook::PosixMemalign); + this->mapCalloc = Map2Check::getOrInsertRuntime(module, RuntimeHook::Calloc); + this->mapAlloca = Map2Check::getOrInsertRuntime(module, RuntimeHook::Alloca); + this->mapNonStaticAlloca = + Map2Check::getOrInsertRuntime(module, RuntimeHook::NonStaticAlloca); + this->mapFunctAddress = + Map2Check::getOrInsertRuntime(module, RuntimeHook::FunctionAddr); + this->checkFree = + Map2Check::getOrInsertRuntime(module, RuntimeHook::CheckFree); + this->mapFree = Map2Check::getOrInsertRuntime(module, RuntimeHook::MapFree); if (WasmModeActive) { - this->map2check_wasm_malloc = F.getParent()->getOrInsertFunction( - "map2check_wasm_malloc", Type::getVoidTy(*this->Ctx), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx)); - - this->map2check_wasm_free = F.getParent()->getOrInsertFunction( - "map2check_wasm_free", Type::getVoidTy(*this->Ctx), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx)); - - this->map2check_wasm_check_access = F.getParent()->getOrInsertFunction( - "map2check_wasm_check_access", Type::getVoidTy(*this->Ctx), - Type::getInt64Ty(*this->Ctx), Type::getInt64Ty(*this->Ctx)); - } -} - -void MemoryTrackPass::instrumentFunctionArgumentAddress() { - Function *F = this->currentFunction; - Module *M = this->currentFunction->getParent(); - const DataLayout dataLayout = M->getDataLayout(); - - Function::iterator bb = this->currentFunction->begin(); - // // bb--; - - BasicBlock::iterator i = bb->begin(); - i++; - // i++; - - for (auto arg = F->arg_begin(); arg != F->arg_end(); arg++) { - Argument *functionArg = &(*arg); - - // functionArg-> - auto type = functionArg->getType(); - unsigned typeSize = dataLayout.getTypeSizeInBits(type) / 8; - IRBuilder<> builder(BBIteratorToInst(i)); - Value *name_llvm = builder.CreateGlobalStringPtr(functionArg->getName()); - - ConstantInt *typeSizeValue = - ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), typeSize); - Value *argCast; - - if (type->isPointerTy()) { - Twine mapcheck_bitcast_argument("mapcheck_bitcast_argument"); - argCast = CastInst::CreatePointerCast( - functionArg, PointerType::get(*this->Ctx, 0), - mapcheck_bitcast_argument, BBIteratorToInst(i)); - - } else { - argCast = functionArg; - } - - // ConstantInt* primitiveSizeValue = - // ConstantInt::getSigned(Type::getInt64Ty(*this->Ctx), - // primitiveSize); - - Value *args[] = {name_llvm, argCast, typeSizeValue, - typeSizeValue, this->line_value, this->scope_value}; - builder.CreateCall(map2check_alloca, args); + this->wasmMalloc = + Map2Check::getOrInsertRuntime(module, RuntimeHook::WasmMalloc); + this->wasmFree = Map2Check::getOrInsertRuntime(module, RuntimeHook::WasmFree); + this->wasmCheckAccess = + Map2Check::getOrInsertRuntime(module, RuntimeHook::WasmCheckAccess); } } @@ -885,6 +656,9 @@ PreservedAnalyses MemoryTrackPass::run(Function &F, llvm::FunctionAnalysisManager &AM) { this->Ctx = &F.getContext(); this->currentFunction = &F; + this->functionNameValue = nullptr; + this->pendingFrees.clear(); + if (F.isDeclaration()) return PreservedAnalyses::all(); this->prepareMap2CheckInstructions(); // this->instrumentInit(); //overhead BUG @@ -898,34 +672,41 @@ PreservedAnalyses MemoryTrackPass::run(Function &F, for (Function::iterator bb = F.begin(), e = F.end(); bb != e; ++bb) { for (BasicBlock::iterator i = bb->begin(), e = bb->end(); i != e; ++i) { this->currentInstruction = i; + if (i->hasMetadata(Map2Check::kRuntimeMetadata)) continue; if (dyn_cast(&*i) != NULL) { this->getDebugInfo(); this->runOnCallInstruction(); - } else if (dyn_cast(&*this->currentInstruction) != NULL) { + } else if (auto *SI = dyn_cast(&*this->currentInstruction)) { + if (isRuntimeOwned(SI->getPointerOperand())) continue; this->getDebugInfo(); this->runOnStoreInstruction(); if (WasmModeActive) { - auto* SI = cast(&*i); - instrumentWasmBoundsCheck(&*i, SI->getPointerOperand(), SI->getValueOperand()->getType()); + instrumentWasmBoundsCheck(&*i, SI->getPointerOperand(), + SI->getValueOperand()->getType()); } } else if (dyn_cast(&*this->currentInstruction) != NULL) { this->getDebugInfo(); this->runOnAllocaInstruction(); - } else if (dyn_cast(&*this->currentInstruction) != NULL) { + } else if (auto *LI = dyn_cast(&*this->currentInstruction)) { + if (isRuntimeOwned(LI->getPointerOperand())) continue; this->getDebugInfo(); this->runOnLoadInstruction(); if (WasmModeActive) { - auto* LI = cast(&*i); - instrumentWasmBoundsCheck(&*i, LI->getPointerOperand(), LI->getType()); + instrumentWasmBoundsCheck(&*i, LI->getPointerOperand(), + LI->getType()); } } } } + // After the walk: guarding a free splits its block. + this->instrumentPendingFrees(); + return PreservedAnalyses::none(); } +// abi-mapping: map2check_wasm_check_access(u64 offset, u64 access_size). void MemoryTrackPass::instrumentWasmBoundsCheck(llvm::Instruction* I, llvm::Value* ptr, llvm::Type* accessType) { @@ -949,7 +730,7 @@ void MemoryTrackPass::instrumentWasmBoundsCheck(llvm::Instruction* I, Value* sizeVal = ConstantInt::get(int64Ty, accessSize); Value* args[] = {offset64, sizeVal}; - builder.CreateCall(map2check_wasm_check_access, args); + builder.CreateCall(wasmCheckAccess, args); } // --- New Pass Manager plugin registration --- diff --git a/modules/backend/pass/MemoryTrackPass.hpp b/modules/backend/pass/MemoryTrackPass.hpp index 2d404a9d2..dee6ca68c 100644 --- a/modules/backend/pass/MemoryTrackPass.hpp +++ b/modules/backend/pass/MemoryTrackPass.hpp @@ -57,7 +57,6 @@ struct MemoryTrackPass : public llvm::PassInfoMixin { void instrumentNotStaticArrayAlloca(); void instrumentAllocation(); void instrumentFunctionAddress(); - void instrumentFunctionArgumentAddress(); void runOnAllocaInstruction(); void runOnCallInstruction(); void runOnStoreInstruction(); @@ -84,20 +83,32 @@ struct MemoryTrackPass : public llvm::PassInfoMixin { Function* calleeFunction; BasicBlock::iterator currentInstruction; BasicBlock::iterator lastInstructionMain; - FunctionCallee map2check_pointer; - FunctionCallee map2check_malloc; - FunctionCallee map2check_calloc; - FunctionCallee map2check_free; - FunctionCallee map2check_alloca; - FunctionCallee map2check_non_static_alloca; - FunctionCallee map2check_posix; - FunctionCallee map2check_load; - FunctionCallee map2check_check_deref; - FunctionCallee map2check_function; - FunctionCallee map2check_free_resolved_address; - FunctionCallee map2check_wasm_malloc; - FunctionCallee map2check_wasm_free; - FunctionCallee map2check_wasm_check_access; + // Core API of map2check-library (RuntimeABI.hpp), declared per function. + FunctionCallee storePointer; // StorePointer + FunctionCallee mapMalloc; // Malloc + FunctionCallee mapCalloc; // Calloc + FunctionCallee checkFree; // CheckFree + FunctionCallee mapFree; // MapFree + FunctionCallee mapAlloca; // Alloca + FunctionCallee mapNonStaticAlloca; // NonStaticAlloca + FunctionCallee mapPosixMemalign; // PosixMemalign + FunctionCallee checkLoad; // Load + FunctionCallee mapFunctAddress; // FunctionAddr + FunctionCallee checkFreeResolved; // FreeResolved + FunctionCallee wasmMalloc; // WasmMalloc + FunctionCallee wasmFree; // WasmFree + FunctionCallee wasmCheckAccess; // WasmCheckAccess + // free(var) calls, guarded after the walk: the NULL check splits blocks. + struct PendingFree { + llvm::CallInst* call; + llvm::Value* slot; + ConstantInt* line; + ConstantInt* scope; + }; + std::vector pendingFrees; + llvm::Value* functionNameValue = nullptr; + llvm::Value* functionName(); + void instrumentPendingFrees(); ConstantInt* scope_value; ConstantInt* line_value; LLVMContext* Ctx; diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 013572dcf..4c4a84354 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,7 @@ std::string compileInput(const std::string& dir, const std::string& input, return run(cmd.str()) == 0 ? bc : ""; } -/// Runs plugin lib with -passes='' (plus `optFlags`) on +/// Runs plugin lib (or several, comma-separated) with -passes='' (plus `optFlags`) on /// inputs/ and parses the result. std::unique_ptr runPassOn(const std::string& plugin, const std::string& pipeline, @@ -83,8 +84,14 @@ std::unique_ptr runPassOn(const std::string& plugin, if (bc.empty()) return nullptr; std::string out = dir + "/output.bc"; std::ostringstream cmd; - cmd << M2C_TEST_OPT << " -load-pass-plugin=" << M2C_PASS_PLUGIN_DIR << "/lib" - << plugin << M2C_PASS_PLUGIN_SUFFIX << " " << optFlags << " -passes='" + cmd << M2C_TEST_OPT; + // `plugin` may list several plugins, separated by commas. + std::stringstream plugins(plugin); + for (std::string one; std::getline(plugins, one, ',');) { + cmd << " -load-pass-plugin=" << M2C_PASS_PLUGIN_DIR << "/lib" << one + << M2C_PASS_PLUGIN_SUFFIX; + } + cmd << " " << optFlags << " -passes='" << pipeline << "' " << bc << " -o " << out << " 2> " << dir << "/opt.err"; if (run(cmd.str()) != 0) return nullptr; @@ -727,3 +734,305 @@ TEST(PassIR, LoopPredAssumeDropsNounwind) { EXPECT_EQ(callsTo(*m, "__VERIFIER_assume").size(), 2u); expectNoNounwind(*m, "__VERIFIER_assume"); } + +// --------------------------------------------------------------------------- +// MemoryTrackPass -> Malloc, Calloc, Alloca, NonStaticAlloca, StorePointer, +// Load, CheckFree, MapFree, FreeResolved, PosixMemalign, Wasm* +// --------------------------------------------------------------------------- + +namespace { + +std::unique_ptr& memTrackModule() { + static std::unique_ptr m = + runPassOn("MemoryTrackPass", "memory-track", "memtrack.c"); + return m; +} + +/// Calls to `name` whose argument `lineArg` is `line`. +std::vector callsOnLine(llvm::Module& m, llvm::StringRef name, + unsigned lineArg, int line) { + std::vector found; + for (llvm::CallInst* call : callsTo(m, name)) { + if (intArg(call->getArgOperand(lineArg)) == line) found.push_back(call); + } + return found; +} + +/// The program's call to `name` on source line `line`. +llvm::CallInst* programCall(llvm::Module& m, llvm::StringRef name, int line) { + for (llvm::CallInst* call : callsTo(m, name)) { + if (callLine(call) == line) return call; + } + return nullptr; +} + +} // namespace + +TEST(PassIR, MemoryTrackEmitsOnlyCoreNames) { + std::unique_ptr& m = memTrackModule(); + ASSERT_VALID(m); + for (RuntimeHook hook : + {RuntimeHook::Malloc, RuntimeHook::Calloc, RuntimeHook::Alloca, + RuntimeHook::NonStaticAlloca, RuntimeHook::StorePointer, + RuntimeHook::Load, RuntimeHook::CheckFree, RuntimeHook::MapFree, + RuntimeHook::FreeResolved, RuntimeHook::PosixMemalign}) { + SCOPED_TRACE(runtimeCall(hook, m->getContext()).name); + expectCoreCalls(*m, hook); + } + for (const char* legacy : + {"map2check_malloc", "map2check_calloc", "map2check_free", + "map2check_load", "map2check_check_deref", "map2check_alloca", + "map2check_non_static_alloca", "map2check_add_store_pointer", + "map2check_free_resolved_address", "map2check_posix", + "map2check_function"}) { + EXPECT_EQ(m->getFunction(legacy), nullptr) << legacy; + } +} + +// free(p) of a pointer variable: load *slot, skip NULL, then check_free and +// map_free, both (name, slot, *slot, scope, line, fn), before the free. +TEST(PassIR, MemoryTrackFreeOfAVariableChecksThenMapsTheLoadedBlock) { + std::unique_ptr& m = memTrackModule(); + ASSERT_VALID(m); + EXPECT_EQ(callsTo(*m, "map2check_check_free").size(), 3u); + EXPECT_EQ(callsTo(*m, "map2check_map_free").size(), 3u); + for (int line : {15, 17, 18}) { + SCOPED_TRACE(line); + llvm::CallInst* freeCall = programCall(*m, "free", line); + ASSERT_NE(freeCall, nullptr); + auto* programLoad = llvm::dyn_cast(freeCall->getArgOperand(0)); + ASSERT_NE(programLoad, nullptr); + llvm::Value* slot = programLoad->getPointerOperand(); + + std::vector check = + callsOnLine(*m, "map2check_check_free", 4, line); + std::vector map = + callsOnLine(*m, "map2check_map_free", 4, line); + ASSERT_EQ(check.size(), 1u); + ASSERT_EQ(map.size(), 1u); + // Same arguments, check first, in the same guarded block. + for (unsigned a = 0; a < 6; ++a) { + EXPECT_EQ(check[0]->getArgOperand(a), map[0]->getArgOperand(a)) << a; + } + ASSERT_EQ(check[0]->getParent(), map[0]->getParent()); + EXPECT_TRUE(check[0]->comesBefore(map[0])); + EXPECT_EQ(check[0]->getArgOperand(1), slot); + auto* loaded = llvm::dyn_cast(check[0]->getArgOperand(2)); + ASSERT_NE(loaded, nullptr) << "the block address is *slot"; + EXPECT_EQ(loaded->getPointerOperand(), slot); + EXPECT_TRUE(loaded->getType()->isPointerTy()); + EXPECT_TRUE(llvm::isa(check[0]->getArgOperand(3))); + EXPECT_EQ(stringArg(check[0]->getArgOperand(5)), "main"); + + // The guard: the block runs only when *slot is not NULL, and both paths + // reach the free. + llvm::BasicBlock* guarded = check[0]->getParent(); + llvm::BasicBlock* pred = guarded->getSinglePredecessor(); + ASSERT_NE(pred, nullptr); + auto* br = llvm::dyn_cast(pred->getTerminator()); + ASSERT_NE(br, nullptr); + ASSERT_TRUE(br->isConditional()); + auto* cmp = llvm::dyn_cast(br->getCondition()); + ASSERT_NE(cmp, nullptr); + EXPECT_EQ(cmp->getOperand(0), loaded); + EXPECT_TRUE(llvm::isa(cmp->getOperand(1))); + llvm::BasicBlock* nonNull = + cmp->getPredicate() == llvm::ICmpInst::ICMP_NE ? br->getSuccessor(0) + : br->getSuccessor(1); + llvm::BasicBlock* isNull = + nonNull == br->getSuccessor(0) ? br->getSuccessor(1) : br->getSuccessor(0); + EXPECT_EQ(nonNull, guarded); + EXPECT_EQ(isNull, freeCall->getParent()); + EXPECT_EQ(guarded->getSingleSuccessor(), freeCall->getParent()); + } +} + +// free(make()) frees an address with no variable: one resolved-address check +// with is_null_valid 0. realloc(p, n) checks its old block with +// is_null_valid 1, then maps the new block as a malloc. +TEST(PassIR, MemoryTrackFreeOfAnAddressAndReallocUseFreeResolved) { + std::unique_ptr& m = memTrackModule(); + ASSERT_VALID(m); + std::vector resolved = + callsTo(*m, "map2check_check_free_resolved_address"); + ASSERT_EQ(resolved.size(), 2u); + + llvm::CallInst* freeCall = programCall(*m, "free", 16); + ASSERT_NE(freeCall, nullptr); + std::vector onFree = + callsOnLine(*m, "map2check_check_free_resolved_address", 1, 16); + ASSERT_EQ(onFree.size(), 1u); + EXPECT_EQ(onFree[0]->getArgOperand(0), freeCall->getArgOperand(0)); + EXPECT_EQ(stringArg(onFree[0]->getArgOperand(2)), "main"); + EXPECT_TRUE(onFree[0]->getArgOperand(3)->getType()->isIntegerTy(16)); + EXPECT_EQ(intArg(onFree[0]->getArgOperand(3)), 0); + EXPECT_TRUE(onFree[0]->comesBefore(freeCall)); + + llvm::CallInst* reallocCall = programCall(*m, "realloc", 8); + ASSERT_NE(reallocCall, nullptr); + std::vector onRealloc = + callsOnLine(*m, "map2check_check_free_resolved_address", 1, 8); + ASSERT_EQ(onRealloc.size(), 1u); + EXPECT_EQ(onRealloc[0]->getArgOperand(0), reallocCall->getArgOperand(0)); + EXPECT_EQ(intArg(onRealloc[0]->getArgOperand(3)), 1); + EXPECT_TRUE(onRealloc[0]->comesBefore(reallocCall)); + bool mapped = false; + for (llvm::CallInst* call : callsTo(*m, "map2check_map_malloc")) { + if (call->getArgOperand(0) == reallocCall) { + mapped = true; + EXPECT_EQ(intArg(call->getArgOperand(1)), 32); + } + } + EXPECT_TRUE(mapped); +} + +TEST(PassIR, MemoryTrackMapsMallocCallocAndPosixMemalign) { + std::unique_ptr& m = memTrackModule(); + ASSERT_VALID(m); + // (block, i32 size): malloc in make() and main(). + for (int line : {3, 6}) { + llvm::CallInst* mallocCall = programCall(*m, "malloc", line); + ASSERT_NE(mallocCall, nullptr) << line; + bool mapped = false; + for (llvm::CallInst* call : callsTo(*m, "map2check_map_malloc")) { + if (call->getArgOperand(0) != mallocCall) continue; + mapped = true; + EXPECT_EQ(intArg(call->getArgOperand(1)), line == 3 ? 4 : 16); + EXPECT_TRUE(mallocCall->comesBefore(call)); + } + EXPECT_TRUE(mapped) << line; + } + // (block, i32 qty, i32 size) + llvm::CallInst* callocCall = programCall(*m, "calloc", 7); + ASSERT_NE(callocCall, nullptr); + std::vector calloc = callsTo(*m, "map2check_map_calloc"); + ASSERT_EQ(calloc.size(), 1u); + EXPECT_EQ(calloc[0]->getArgOperand(0), callocCall); + EXPECT_EQ(intArg(calloc[0]->getArgOperand(1)), 2); + EXPECT_EQ(intArg(calloc[0]->getArgOperand(2)), 4); + // (memptr, i32 size) + llvm::CallInst* posix = programCall(*m, "posix_memalign", 12); + ASSERT_NE(posix, nullptr); + std::vector mapped = callsTo(*m, "map2check_map_posix_memalign"); + ASSERT_EQ(mapped.size(), 1u); + EXPECT_EQ(mapped[0]->getArgOperand(0), posix->getArgOperand(0)); + EXPECT_EQ(intArg(mapped[0]->getArgOperand(1)), 64); + EXPECT_TRUE(posix->comesBefore(mapped[0])); +} + +// map_alloca(name, addr, i32 size, i32 size_primitive, i32 line, i32 scope) +// for the static array and the global; map_non_static_alloca takes the VLA's +// element count. +TEST(PassIR, MemoryTrackMapsAllocasGlobalsAndVlas) { + std::unique_ptr& m = memTrackModule(); + ASSERT_VALID(m); + bool array = false; + bool global = false; + for (llvm::CallInst* call : callsTo(*m, "map2check_map_alloca")) { + llvm::Value* addr = call->getArgOperand(1); + if (auto* alloca = llvm::dyn_cast(addr)) { + if (alloca->getAllocatedType()->isArrayTy()) { + array = true; + EXPECT_EQ(intArg(call->getArgOperand(2)), 20); + EXPECT_EQ(intArg(call->getArgOperand(3)), 4); + EXPECT_TRUE(llvm::isa(call->getArgOperand(4))); + EXPECT_TRUE(llvm::isa(call->getArgOperand(5))); + } + } else if (addr == m->getNamedGlobal("g")) { + global = true; + EXPECT_EQ(stringArg(call->getArgOperand(0)), "g"); + EXPECT_EQ(intArg(call->getArgOperand(2)), 4); + EXPECT_EQ(intArg(call->getArgOperand(3)), 4); + } + } + EXPECT_TRUE(array); + EXPECT_TRUE(global); + + std::vector vla = callsTo(*m, "map2check_map_non_static_alloca"); + ASSERT_EQ(vla.size(), 1u); + auto* alloca = llvm::dyn_cast(vla[0]->getArgOperand(1)); + ASSERT_NE(alloca, nullptr); + EXPECT_TRUE(alloca->isArrayAllocation()); + // The element count, narrowed to i32; the element size. + EXPECT_EQ(stripCasts(vla[0]->getArgOperand(2)), + stripCasts(alloca->getArraySize())); + EXPECT_EQ(intArg(vla[0]->getArgOperand(3)), 4); + EXPECT_EQ(intArg(vla[0]->getArgOperand(4)), 10); +} + +// check_load(ptr, i32 line, i32 scope, i32 size, fn) before each load and +// store; map_store_pointer(var, value, scope, name, line, fn) after a store +// of a pointer. +TEST(PassIR, MemoryTrackChecksLoadsAndStoresAndMapsStoredPointers) { + std::unique_ptr& m = memTrackModule(); + ASSERT_VALID(m); + // arr[0] = *q on line 13: the load of q (8 bytes), of *q and the store (4). + std::vector line13 = callsOnLine(*m, "map2check_check_load", 1, 13); + ASSERT_GE(line13.size(), 3u); + std::multiset sizes; + for (llvm::CallInst* call : line13) { + sizes.insert(intArg(call->getArgOperand(3))); + EXPECT_TRUE(llvm::isa(call->getArgOperand(2))); + EXPECT_EQ(stringArg(call->getArgOperand(4)), "main"); + // Right before the access it checks. + llvm::Instruction* next = call->getNextNode(); + ASSERT_TRUE(llvm::isa(next) || llvm::isa(next)); + llvm::Value* accessed = llvm::isa(next) + ? llvm::cast(next)->getPointerOperand() + : llvm::cast(next)->getPointerOperand(); + EXPECT_EQ(call->getArgOperand(0)->stripPointerCasts(), + accessed->stripPointerCasts()); + } + EXPECT_GE(sizes.count(8), 1u); + EXPECT_GE(sizes.count(4), 2u); + + // p = malloc(...) on line 6. + std::vector stored = callsOnLine(*m, "map2check_map_store_pointer", 4, 6); + ASSERT_EQ(stored.size(), 1u); + auto* store = llvm::dyn_cast(stored[0]->getPrevNode()); + ASSERT_NE(store, nullptr); + EXPECT_EQ(stored[0]->getArgOperand(0), store->getPointerOperand()); + EXPECT_EQ(stored[0]->getArgOperand(1), store->getValueOperand()); + EXPECT_TRUE(llvm::isa(stored[0]->getArgOperand(2))); + EXPECT_EQ(stringArg(stored[0]->getArgOperand(5)), "main"); +} + +// The nondet value slots NonDetPass adds are not program memory. +TEST(PassIR, MemoryTrackSkipsTheNonDetSlots) { + auto m = runPassOn("NonDetPass,MemoryTrackPass", "nondet-pass,memory-track", + "nondet_types.c"); + ASSERT_VALID(m); + EXPECT_TRUE(calls(*m, "map2check_check_load")); + for (const char* hook : {"map2check_check_load", "map2check_map_alloca", + "map2check_map_store_pointer"}) { + for (llvm::CallInst* call : callsTo(*m, hook)) { + llvm::Value* addr = + call->getArgOperand(llvm::StringRef(hook) == "map2check_map_alloca" ? 1 : 0); + auto* alloca = llvm::dyn_cast(addr->stripPointerCasts()); + if (alloca == nullptr) continue; + EXPECT_FALSE(alloca->hasMetadata(Map2Check::kRuntimeMetadata)) + << hook << " on " << alloca->getName().str(); + } + } +} + +TEST(PassIR, MemoryTrackWasmModeEmitsWasmHooks) { + auto m = runPassOn("MemoryTrackPass", "memory-track", "wasm.ll", "-wasm-mode"); + ASSERT_VALID(m); + expectCoreCalls(*m, RuntimeHook::WasmMalloc); + expectCoreCalls(*m, RuntimeHook::WasmFree); + expectCoreCalls(*m, RuntimeHook::WasmCheckAccess); + llvm::CallInst* alloc = programCall(*m, "w2c_m_dlmalloc", -1); + ASSERT_NE(alloc, nullptr); + std::vector malloc = callsTo(*m, "map2check_wasm_malloc"); + ASSERT_EQ(malloc.size(), 1u); + EXPECT_EQ(stripCasts(malloc[0]->getArgOperand(0)), alloc); + EXPECT_EQ(intArg(malloc[0]->getArgOperand(1)), 16); // zext of the i32 size + std::vector access = callsTo(*m, "map2check_wasm_check_access"); + ASSERT_EQ(access.size(), 2u); // the store and the load + for (llvm::CallInst* call : access) EXPECT_EQ(intArg(call->getArgOperand(1)), 4); + std::vector freed = callsTo(*m, "map2check_wasm_free"); + ASSERT_EQ(freed.size(), 1u); + EXPECT_EQ(stripCasts(freed[0]->getArgOperand(0)), alloc); + EXPECT_TRUE(freed[0]->getArgOperand(1)->getType()->isIntegerTy(64)); +} diff --git a/tests/unit/pass/inputs/memtrack.c b/tests/unit/pass/inputs/memtrack.c new file mode 100644 index 000000000..3fa932a95 --- /dev/null +++ b/tests/unit/pass/inputs/memtrack.c @@ -0,0 +1,20 @@ +#include +int g = 7; +int *make(void) { return malloc(sizeof(int)); } +int main(void) { + int n = 3; + int *p = malloc(4 * sizeof(int)); + int *q = calloc(2, sizeof(int)); + p = realloc(p, 8 * sizeof(int)); + int arr[5]; + int vla[n]; + void *al = NULL; + posix_memalign(&al, 16, 64); + arr[0] = *q; + vla[0] = g; + free(p); + free(make()); + free(al); + free(q); + return arr[0] + vla[0]; +} diff --git a/tests/unit/pass/inputs/wasm.ll b/tests/unit/pass/inputs/wasm.ll new file mode 100644 index 000000000..19f47d3cf --- /dev/null +++ b/tests/unit/pass/inputs/wasm.ll @@ -0,0 +1,17 @@ +; The shape wasm2c gives a lifted module: an allocator returning an i32 +; linear-memory offset, and accesses through a GEP into the memory's data. +declare i32 @w2c_m_dlmalloc(ptr, i32) +declare void @w2c_m_dlfree(ptr, i32) + +define i32 @main() { +entry: + %inst = alloca [64 x i8] + %mem = alloca [1024 x i8] + %off = call i32 @w2c_m_dlmalloc(ptr %inst, i32 16) + %idx = zext i32 %off to i64 + %addr = getelementptr inbounds [1024 x i8], ptr %mem, i64 0, i64 %idx + store i32 5, ptr %addr + %v = load i32, ptr %addr + call void @w2c_m_dlfree(ptr %inst, i32 %off) + ret i32 %v +} From 072afa6f0a15b8d066371d076db577dc5d2ea41f Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:14:53 -0400 Subject: [PATCH 20/44] fix(pass): keep a body for the program's own __VERIFIER_assume Deleting its body left an empty function to the passes that run after nondet-pass in the same pipeline, and Map2CheckLibrary crashed opt on it (found by the end-to-end link). NonDetPass now renames the program's definition to an internal, unused __map2check_program_assume and sends every use to the core __VERIFIER_assume declaration, so the library's definition is still the only one. The PassIR test runs nondet-pass,map2check-library to cover the crash. --- modules/backend/pass/NonDetPass.cpp | 26 +++++++++++++++++--------- tests/unit/pass/PassIRTest.cpp | 23 +++++++++++++++++++---- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/modules/backend/pass/NonDetPass.cpp b/modules/backend/pass/NonDetPass.cpp index 0e80209da..30139c53f 100644 --- a/modules/backend/pass/NonDetPass.cpp +++ b/modules/backend/pass/NonDetPass.cpp @@ -79,17 +79,25 @@ bool rewriteAssumeToPrune(Function &F) { // The program's own __VERIFIER_assume gives way to the library's: its // body would otherwise call itself, and the link would see two - // definitions. - llvm::FunctionCallee assume = - Map2Check::getOrInsertRuntime(*F.getParent(), - Map2Check::RuntimeHook::Assume); - if (assume.getCallee() == &F) { - F.deleteBody(); - Map2Check::allowUnwind(F); - llvm::errs() << "[map2check] dropped the program's " << F.getName() - << " for the runtime's\n"; + // definitions. It is renamed, made internal and left unused (the passes + // after this one in the pipeline still run on it, so it keeps a body); + // every use goes to the core declaration. + const char *coreAssume = + Map2Check::runtimeCall(Map2Check::RuntimeHook::Assume, F.getContext()) + .name; + if (F.getName() == coreAssume) { + F.setName("__map2check_program_assume"); + F.setLinkage(llvm::GlobalValue::InternalLinkage); + llvm::FunctionCallee core = Map2Check::getOrInsertRuntime( + *F.getParent(), Map2Check::RuntimeHook::Assume); + F.replaceAllUsesWith(core.getCallee()); + Map2Check::allowUnwind(*llvm::cast(core.getCallee())); + llvm::errs() << "[map2check] replaced the program's " << coreAssume + << " with the runtime's\n"; return true; } + llvm::FunctionCallee assume = Map2Check::getOrInsertRuntime( + *F.getParent(), Map2Check::RuntimeHook::Assume); LLVMContext &ctx = F.getContext(); llvm::Value *condition = F.getArg(0); diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 4c4a84354..76e2c81d7 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -692,14 +692,27 @@ TEST(PassIR, NonDetTurnsCrabAssumeIntoVerifierAssume) { } // assume_abort_if_not aborts on a false condition; its body becomes a call to -// the library's assume. A program's own __VERIFIER_assume loses its body, so -// the library's definition is the only one (no recursion, no duplicate). +// the library's assume. A program's own __VERIFIER_assume is renamed and left +// unused, so the library's definition is the only one (no recursion, no +// duplicate); it keeps its body for the passes that run after this one. TEST(PassIR, NonDetRewritesAbortingAssumes) { - auto m = runPassOn("NonDetPass", "nondet-pass", "assume_defined.c"); + // map2check-library runs after nondet-pass on the same functions. + auto m = runPassOn("NonDetPass,Map2CheckLibrary", "nondet-pass,map2check-library", + "assume_defined.c"); ASSERT_VALID(m); llvm::Function* verifierAssume = m->getFunction("__VERIFIER_assume"); ASSERT_NE(verifierAssume, nullptr); EXPECT_TRUE(verifierAssume->isDeclaration()); + llvm::Function* programAssume = m->getFunction("__map2check_program_assume"); + ASSERT_NE(programAssume, nullptr); + EXPECT_TRUE(programAssume->hasInternalLinkage()); + EXPECT_TRUE(programAssume->use_empty()); + // main's call now reaches the library's assume. + bool fromMain = false; + for (llvm::CallInst* call : callsTo(*m, "__VERIFIER_assume")) { + fromMain |= call->getFunction()->getName() == "__map2check_main__"; + } + EXPECT_TRUE(fromMain); EXPECT_EQ(verifierAssume->getFunctionType(), runtimeCall(RuntimeHook::Assume, m->getContext()).type); @@ -711,7 +724,9 @@ TEST(PassIR, NonDetRewritesAbortingAssumes) { if (call->getFunction() == abortIfNot) inBody.push_back(call); } ASSERT_EQ(inBody.size(), 1u); - EXPECT_FALSE(calls(*m, "abort")); + for (llvm::CallInst* call : callsTo(*m, "abort")) { + EXPECT_NE(call->getFunction(), abortIfNot) << "the abort is gone"; + } // cond != 0, as C reads the int condition. auto* zext = llvm::dyn_cast(inBody[0]->getArgOperand(0)); ASSERT_NE(zext, nullptr); From 06eb3704b04dd43aa9fa1b2840f5b8b28d32aeae Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:15:04 -0400 Subject: [PATCH 21/44] test(pass): link every instrumented input against libmap2check.a EndToEndLinkTest (Task 3.2 Steps 5 and 5b), one ctest entry per mode and input. Each input of tests/unit/pass/inputs is compiled as the frontend compiles the program (-c -emit-llvm -g -fexceptions -O0), instrumented with every pass of the mode as Caller::callPass chains them (nondet-pass, the mode's pass, map2check-library with -m2c-analysis-mode), and linked with clang-16 -fexceptions -fsanitize=fuzzer against the Rust runtime; the link must succeed with no undefined reference and no multiple definition. The modes are memtrack, memcleanup, overflow, assert, target and none. EndToEndRun.AssumeRejectionsUnwindAtO2UnderLibFuzzer builds assume_runs.c at -O2, checks that no frame the unwind crosses is nounwind, and runs 100 rejected inputs and then one accepted input through the libFuzzer driver: exit 0, 101 executions, only the accepted input prints, and no abort or panic message. target.c now defines reach_error and wasm.ll defines its allocators, so both inputs are whole programs. The library path comes from MAP2CHECK_RUST_LIB_DIR (or MAP2CHECK_RUST_SRC); without either the test is skipped. --- tests/unit/pass/CMakeLists.txt | 21 +++ tests/unit/pass/EndToEndLinkTest.cpp | 267 +++++++++++++++++++++++++++ tests/unit/pass/inputs/assume_runs.c | 14 ++ tests/unit/pass/inputs/target.c | 1 + tests/unit/pass/inputs/wasm.ll | 12 +- 5 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 tests/unit/pass/EndToEndLinkTest.cpp create mode 100644 tests/unit/pass/inputs/assume_runs.c diff --git a/tests/unit/pass/CMakeLists.txt b/tests/unit/pass/CMakeLists.txt index f67be5b96..2948b38f3 100644 --- a/tests/unit/pass/CMakeLists.txt +++ b/tests/unit/pass/CMakeLists.txt @@ -60,4 +60,25 @@ else() add_dependencies(PassIRTest TrackBasicBlockPass AssertPass TargetPass LoopPredAssumePass Map2CheckLibrary OverflowPass NonDetPass MemoryTrackPass) + + # Steps 5 and 5b of Task 3.2: every input, instrumented with all passes of + # each analysis mode, links against the Rust runtime; an assume rejection + # unwinds at -O2 under the libFuzzer driver. + if(MAP2CHECK_RUST_LIB_DIR) + set(M2C_E2E_RUST_LIB "${MAP2CHECK_RUST_LIB_DIR}/libmap2check.a") + elseif(MAP2CHECK_RUST_SRC) + set(M2C_E2E_RUST_LIB "${MAP2CHECK_RUST_SRC}/target/runtime/libmap2check.a") + endif() + if(M2C_E2E_RUST_LIB) + m2c_pass_test(EndToEndLinkTest EndToEndLinkTest.cpp) + target_compile_definitions(EndToEndLinkTest PRIVATE + M2C_RUST_LIB="${M2C_E2E_RUST_LIB}") + add_dependencies(EndToEndLinkTest + NonDetPass MemoryTrackPass OverflowPass AssertPass TargetPass Map2CheckLibrary) + if(NOT MAP2CHECK_RUST_LIB_DIR) + add_dependencies(EndToEndLinkTest Map2CheckRustRuntime) + endif() + else() + message(STATUS "EndToEndLinkTest skipped: no Rust runtime configured") + endif() endif() diff --git a/tests/unit/pass/EndToEndLinkTest.cpp b/tests/unit/pass/EndToEndLinkTest.cpp new file mode 100644 index 000000000..3ac753cfb --- /dev/null +++ b/tests/unit/pass/EndToEndLinkTest.cpp @@ -0,0 +1,267 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// Task 3.2, Steps 5 and 5b: the instrumented program links against the Rust +// runtime (libmap2check.a) with nothing left undefined or defined twice, in +// every analysis mode, and an assume rejection unwinds through it at -O2 +// under the libFuzzer driver. +// +// Each input of inputs/ is compiled as the frontend compiles the program +// (Caller::compileFile: -c -emit-llvm -g -fexceptions -O0), instrumented with +// every pass of the mode as Caller::callPass chains them, and linked with +// clang-16 -fexceptions -fsanitize=fuzzer. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../../modules/frontend/utils/clang.hpp" + +namespace { + +namespace fs = std::filesystem; + +/// The pipeline Caller::callPass builds for each mode: nondet-pass, the +/// mode's pass, then map2check-library with the mode's runtime number. +struct ModePipeline { + const char* mode; // -m2c-analysis-mode= (runtimeAnalysisMode) + std::vector plugins; + std::string passes; + std::string extraFlags; +}; + +const std::vector& pipelines() { + static const std::vector all = { + {"memtrack", {"NonDetPass", "MemoryTrackPass"}, "nondet-pass,memory-track", + "-m2c-entry-function=main"}, + {"memcleanup", {"NonDetPass", "MemoryTrackPass"}, + "nondet-pass,memory-track", "-m2c-entry-function=main"}, + {"overflow", {"NonDetPass", "OverflowPass"}, "nondet-pass,overflow-pass", ""}, + {"assert", {"NonDetPass", "AssertPass"}, "nondet-pass,assert-pass", ""}, + {"target", {"NonDetPass", "TargetPass"}, "nondet-pass,target-pass", + "-function-name=reach_error"}, + {"none", {"NonDetPass"}, "nondet-pass", ""}, + }; + return all; +} + +const ModePipeline& pipeline(const std::string& mode) { + for (const ModePipeline& p : pipelines()) { + if (mode == p.mode) return p; + } + return pipelines().front(); +} + +std::vector inputs() { + std::vector names; + for (const fs::directory_entry& entry : fs::directory_iterator(M2C_TEST_INPUTS)) { + std::string ext = entry.path().extension().string(); + if (ext == ".c" || ext == ".ll") names.push_back(entry.path().filename().string()); + } + std::sort(names.begin(), names.end()); + return names; +} + +std::string freshWorkDir(const std::string& name) { + fs::path dir = fs::path(M2C_TEST_WORKDIR) / name; + fs::remove_all(dir); + fs::create_directories(dir); + return dir.string(); +} + +int run(const std::string& command) { + int rc = std::system(command.c_str()); + if (rc != 0) llvm::errs() << "command failed (" << rc << "): " << command << "\n"; + return rc; +} + +std::string readFile(const std::string& path) { + std::ifstream in(path); + return std::string(std::istreambuf_iterator(in), {}); +} + +/// Compiles inputs/ as the frontend does and instruments it with the +/// mode's pipeline. Returns the instrumented bitcode, or "" on error. +std::string instrument(const std::string& dir, const std::string& input, + const ModePipeline& p) { + std::string compiled = dir + "/compiled.bc"; + std::ostringstream cc; + cc << M2C_TEST_CLANG << " -Wno-everything -Winteger-overflow -c -emit-llvm -g " + << Map2Check::kProgramUnwindFlags << " -O0 -o " << compiled << " " + << M2C_TEST_INPUTS << "/" << input << " 2> " << dir << "/clang.err"; + if (run(cc.str()) != 0) return ""; + + std::string output = dir + "/output.bc"; + std::ostringstream opt; + opt << M2C_TEST_OPT << " -tailcallopt"; + for (const std::string& plugin : p.plugins) { + opt << " -load-pass-plugin=" << M2C_PASS_PLUGIN_DIR << "/lib" << plugin + << M2C_PASS_PLUGIN_SUFFIX; + } + opt << " -load-pass-plugin=" << M2C_PASS_PLUGIN_DIR << "/libMap2CheckLibrary" + << M2C_PASS_PLUGIN_SUFFIX << " -entry-function=main" + << " -m2c-analysis-mode=" << p.mode << " " << p.extraFlags << " -passes='" + << p.passes << ",map2check-library' < " << compiled << " > " << output + << " 2> " << dir << "/opt.err"; + if (run(opt.str()) != 0) return ""; + return output; +} + +/// Links `bitcode` against the Rust runtime under the libFuzzer driver. +/// Returns clang's exit code; the link output goes to /link.txt. +int link(const std::string& dir, const std::string& bitcode, + const std::string& optLevel) { + std::ostringstream ld; + ld << M2C_TEST_CLANG << " " << optLevel << " " << Map2Check::kProgramUnwindFlags + << " -fsanitize=fuzzer " << bitcode << " " << M2C_RUST_LIB + << " -ldl -lpthread -lm -o " << dir << "/program > " << dir + << "/link.txt 2>&1"; + return std::system(ld.str().c_str()); +} + +/// Every distinct "undefined reference to `x'" / "multiple definition of +/// `x'" in the linker output. +std::set linkerErrors(const std::string& log) { + std::set found; + static const std::regex error( + "(undefined reference to|multiple definition of) `[^']*'"); + for (std::sregex_iterator it(log.begin(), log.end(), error), end; it != end; + ++it) { + found.insert(it->str()); + } + return found; +} + +struct LinkCase { + std::string mode; + std::string input; +}; + +void PrintTo(const LinkCase& c, std::ostream* os) { *os << c.mode << "/" << c.input; } + +std::vector linkCases() { + std::vector cases; + for (const ModePipeline& p : pipelines()) { + for (const std::string& input : inputs()) cases.push_back({p.mode, input}); + } + return cases; +} + +} // namespace + +class EndToEndLink : public ::testing::TestWithParam {}; + +TEST_P(EndToEndLink, NoUndefinedOrDuplicateSymbol) { + const LinkCase& c = GetParam(); + std::string name = c.mode + "-" + c.input; + std::replace(name.begin(), name.end(), '.', '_'); + std::string dir = freshWorkDir(name); + std::string bitcode = instrument(dir, c.input, pipeline(c.mode)); + ASSERT_FALSE(bitcode.empty()) << readFile(dir + "/clang.err") + << readFile(dir + "/opt.err"); + int rc = link(dir, bitcode, "-O0"); + std::string log = readFile(dir + "/link.txt"); + std::set errors = linkerErrors(log); + for (const std::string& e : errors) ADD_FAILURE() << e; + EXPECT_EQ(rc, 0) << log; + EXPECT_TRUE(fs::exists(dir + "/program")); +} + +INSTANTIATE_TEST_SUITE_P( + PassIR, EndToEndLink, ::testing::ValuesIn(linkCases()), + [](const ::testing::TestParamInfo& info) { + std::string name = info.param.mode + "_" + info.param.input; + for (char& ch : name) { + if (!std::isalnum(static_cast(ch))) ch = '_'; + } + return name; + }); + +// Step 5b (D1 condition 11): the program bitcode keeps a defined unwind, and +// the -O2 binary rejects 100 inputs through __VERIFIER_assume, unwinding +// through a C frame each time, then runs an accepted input to the end, with +// no abort. +TEST(EndToEndRun, AssumeRejectionsUnwindAtO2UnderLibFuzzer) { + std::string dir = freshWorkDir("assume-runs-O2"); + std::string bitcode = instrument(dir, "assume_runs.c", pipeline("assert")); + ASSERT_FALSE(bitcode.empty()) << readFile(dir + "/opt.err"); + + // The frames the unwind crosses are not nounwind. + static llvm::LLVMContext ctx; + llvm::SMDiagnostic err; + std::unique_ptr m = llvm::parseIRFile(bitcode, err, ctx); + ASSERT_NE(m, nullptr); + ASSERT_FALSE(llvm::verifyModule(*m, &llvm::errs())); + for (const char* fn : {"__map2check_main__", "step", "__VERIFIER_assume"}) { + llvm::Function* f = m->getFunction(fn); + ASSERT_NE(f, nullptr) << fn; + EXPECT_FALSE(f->hasFnAttribute(llvm::Attribute::NoUnwind)) << fn; + } + + ASSERT_EQ(link(dir, bitcode, "-O2"), 0) << readFile(dir + "/link.txt"); + + // x <= 0 is rejected by __VERIFIER_assume(x > 0); x = 5 is accepted. + fs::create_directories(dir + "/inputs"); + auto writeInt = [&](const std::string& path, int32_t value) { + std::ofstream out(path, std::ios::binary); + unsigned char bytes[4]; + for (int b = 0; b < 4; ++b) { + bytes[b] = static_cast((static_cast(value) >> (8 * b)) & 0xff); + } + out.write(reinterpret_cast(bytes), 4); + }; + std::ostringstream files; + for (int k = 0; k < 100; ++k) { + std::string path = dir + "/inputs/rejected" + std::to_string(k); + writeInt(path, -k); + files << " " << path; + } + writeInt(dir + "/inputs/accepted", 5); + files << " " << dir << "/inputs/accepted"; + + std::ostringstream cmd; + cmd << dir << "/program" << files.str() << " > " << dir << "/run.out 2> " + << dir << "/run.err"; + int rc = std::system(cmd.str().c_str()); + std::string out = readFile(dir + "/run.out"); + std::string errText = readFile(dir + "/run.err"); + EXPECT_EQ(rc, 0) << errText; + + // libFuzzer ran all 101 inputs, in order, in one process. + size_t executed = 0; + for (size_t pos = errText.find("Executed "); pos != std::string::npos; + pos = errText.find("Executed ", pos + 1)) { + ++executed; + } + EXPECT_EQ(executed, 101u) << errText; + // Only the accepted input got past the assume. + EXPECT_EQ(out, "accepted 4\n"); + for (const char* bad : {"deadly signal", "failed to initiate panic", "Aborted", + "panic in FFI boundary"}) { + EXPECT_EQ(errText.find(bad), std::string::npos) << bad << "\n" << errText; + } +} diff --git a/tests/unit/pass/inputs/assume_runs.c b/tests/unit/pass/inputs/assume_runs.c new file mode 100644 index 000000000..1f73f9c64 --- /dev/null +++ b/tests/unit/pass/inputs/assume_runs.c @@ -0,0 +1,14 @@ +#include +extern int __VERIFIER_nondet_int(void); +extern void __VERIFIER_assume(int cond); +/* noinline: at -O2 the rejection still unwinds through a C frame. */ +__attribute__((noinline)) static int step(int x) { + __VERIFIER_assume(x > 0); + return x - 1; +} +int main(void) { + int x = __VERIFIER_nondet_int(); + int y = step(x); + printf("accepted %d\n", y); + return 0; +} diff --git a/tests/unit/pass/inputs/target.c b/tests/unit/pass/inputs/target.c index ef269a475..6a8e32a79 100644 --- a/tests/unit/pass/inputs/target.c +++ b/tests/unit/pass/inputs/target.c @@ -7,3 +7,4 @@ int main(void) { } return 0; } +void reach_error(void) {} diff --git a/tests/unit/pass/inputs/wasm.ll b/tests/unit/pass/inputs/wasm.ll index 19f47d3cf..9080d008b 100644 --- a/tests/unit/pass/inputs/wasm.ll +++ b/tests/unit/pass/inputs/wasm.ll @@ -1,7 +1,15 @@ ; The shape wasm2c gives a lifted module: an allocator returning an i32 ; linear-memory offset, and accesses through a GEP into the memory's data. -declare i32 @w2c_m_dlmalloc(ptr, i32) -declare void @w2c_m_dlfree(ptr, i32) +; The allocator bodies are stand-ins, so the module links on its own. +define i32 @w2c_m_dlmalloc(ptr %instance, i32 %size) { +entry: + ret i32 64 +} + +define void @w2c_m_dlfree(ptr %instance, i32 %offset) { +entry: + ret void +} define i32 @main() { entry: From 9968a516414b93fc16d8e96374d8406a1d2cf413 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:34:14 -0400 Subject: [PATCH 22/44] fix(pass): free the program's own load of the pointer variable free(var) loaded *slot a second time (%map2check.freed) for the NULL guard, check_free and map_free. The block is now the program's load, the very value free receives; it dominates the call, so it also dominates the guarded block. One load per free, as in the C runtime; under KLEE a symbolic slot no longer costs a second resolution. The PassIR test requires check_free and map_free to get that same SSA value and finds no other load of the slot up to the free. --- modules/backend/pass/MemoryTrackPass.cpp | 12 ++++++------ modules/backend/pass/MemoryTrackPass.hpp | 1 + tests/unit/pass/PassIRTest.cpp | 21 +++++++++++++++++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/modules/backend/pass/MemoryTrackPass.cpp b/modules/backend/pass/MemoryTrackPass.cpp index 488b031dc..08be3a00c 100644 --- a/modules/backend/pass/MemoryTrackPass.cpp +++ b/modules/backend/pass/MemoryTrackPass.cpp @@ -241,7 +241,7 @@ void MemoryTrackPass::instrumentFree() { if (li != nullptr && li->getType()->isPointerTy()) { this->pendingFrees.push_back( - {callInst, li->getPointerOperand(), this->line_value, + {callInst, li->getPointerOperand(), li, this->line_value, this->scope_value}); return; } @@ -255,17 +255,17 @@ void MemoryTrackPass::instrumentFree() { } // The core keys the release on the heap address, and the C runtime read it -// from the pointer variable's slot: load *slot right before the free, skip -// both calls for NULL as the C runtime did, else check_free then map_free, -// both (name, slot, *slot, scope, line, fn). +// from the pointer variable's slot: the block is the program's own load of +// *slot (the value free receives; no second load), both calls are skipped +// for NULL as the C runtime did, else check_free then map_free, both +// (name, slot, *slot, scope, line, fn). void MemoryTrackPass::instrumentPendingFrees() { for (const PendingFree &pending : this->pendingFrees) { IRBuilder<> builder(pending.call); Value *name_llvm = builder.CreateGlobalStringPtr(pending.slot->getName()); Value *slot = coerceToParamType(builder, pending.slot, checkFree, 1); - LoadInst *block = builder.CreateLoad(PointerType::get(*this->Ctx, 0), slot, - "map2check.freed"); + LoadInst *block = pending.block; Value *nonNull = builder.CreateIsNotNull(block); Instruction *then = llvm::SplitBlockAndInsertIfThen( nonNull, pending.call, /*Unreachable=*/false); diff --git a/modules/backend/pass/MemoryTrackPass.hpp b/modules/backend/pass/MemoryTrackPass.hpp index dee6ca68c..b9bcc38d0 100644 --- a/modules/backend/pass/MemoryTrackPass.hpp +++ b/modules/backend/pass/MemoryTrackPass.hpp @@ -102,6 +102,7 @@ struct MemoryTrackPass : public llvm::PassInfoMixin { struct PendingFree { llvm::CallInst* call; llvm::Value* slot; + llvm::LoadInst* block; // the program's own load of *slot ConstantInt* line; ConstantInt* scope; }; diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 76e2c81d7..1cf4628d2 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -832,10 +832,11 @@ TEST(PassIR, MemoryTrackFreeOfAVariableChecksThenMapsTheLoadedBlock) { ASSERT_EQ(check[0]->getParent(), map[0]->getParent()); EXPECT_TRUE(check[0]->comesBefore(map[0])); EXPECT_EQ(check[0]->getArgOperand(1), slot); - auto* loaded = llvm::dyn_cast(check[0]->getArgOperand(2)); - ASSERT_NE(loaded, nullptr) << "the block address is *slot"; - EXPECT_EQ(loaded->getPointerOperand(), slot); - EXPECT_TRUE(loaded->getType()->isPointerTy()); + // The block is the program's own load of *slot, the very value free + // receives: no second load. + llvm::Value* loaded = check[0]->getArgOperand(2); + EXPECT_EQ(loaded, programLoad); + EXPECT_EQ(map[0]->getArgOperand(2), programLoad); EXPECT_TRUE(llvm::isa(check[0]->getArgOperand(3))); EXPECT_EQ(stringArg(check[0]->getArgOperand(5)), "main"); @@ -859,6 +860,18 @@ TEST(PassIR, MemoryTrackFreeOfAVariableChecksThenMapsTheLoadedBlock) { EXPECT_EQ(nonNull, guarded); EXPECT_EQ(isNull, freeCall->getParent()); EXPECT_EQ(guarded->getSingleSuccessor(), freeCall->getParent()); + + // No load of the slot other than the program's, from that load to the + // free (its block, the guarded block, the free's block). + for (llvm::BasicBlock* bb : {programLoad->getParent(), guarded, freeCall->getParent()}) { + for (llvm::Instruction& i : *bb) { + auto* load = llvm::dyn_cast(&i); + if (load == nullptr || load == programLoad) continue; + if (bb == programLoad->getParent() && load->comesBefore(programLoad)) continue; + if (bb == freeCall->getParent() && freeCall->comesBefore(load)) continue; + EXPECT_NE(load->getPointerOperand(), slot) << "extra load of the slot"; + } + } } } From 4c3578d32fd3984c4eb17b26a1375ee14c9c6756 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:34:25 -0400 Subject: [PATCH 23/44] feat(pass): resolve program definitions of library exports before instrumenting SV-COMP programs define library exports themselves, and the link saw two definitions (multiple definition of __VERIFIER_assert, ...). RuntimeABI now keeps the two lists and resolveProgramDefinitions(module) applies them, idempotently, as the first step of NonDetPass (first in every pipeline) and again in Map2CheckLibrary: - discarded (__VERIFIER_assume and the 16 exported __VERIFIER_nondet_*): every use goes to a declaration of the same name, so calls bind to the library (fuzzer/KLEE input, the pruning assume); the old body becomes an unused internal __map2check_program_ holding unreachable. This generalises 072afa6f, whose __VERIFIER_assume branch moves here; - internalized (__VERIFIER_assert, __VERIFIER_error, get_current_step, get_next_step, get_current_property, set_false_result, print_all_containers_as_json, vcc_reset_meta_data): the program keeps its body with internal linkage under the same name, so AssertPass still matches __VERIFIER_assert call sites by name. The DebugInfo and RuntimeABI object libraries are now built with position-independent code; the plugins are shared objects and the lists' std::vector code needs it. Tests: PassIR checks both treatments, with the definitions before and after main; RuntimeABITest checks the lists. svcomp_defs.c and svcomp_defs_late.c join the end-to-end matrix (every mode links, 0 undefined, 0 duplicate), and EndToEndRun.ProgramDefinedExportsGiveWay- ToTheLibrary shows at -O2 under libFuzzer that input 7 is pruned by the library's assume and input 123456 reaches a branch the program's return-0 generator never would, while the internalized get_current_step still runs its own body. --- modules/backend/pass/CMakeLists.txt | 2 + modules/backend/pass/Map2CheckLibrary.cpp | 2 + modules/backend/pass/NonDetPass.cpp | 30 +++------ modules/backend/pass/RuntimeABI.cpp | 64 ++++++++++++++++++ modules/backend/pass/RuntimeABI.hpp | 22 ++++++ tests/unit/pass/EndToEndLinkTest.cpp | 49 +++++++++++--- tests/unit/pass/PassIRTest.cpp | 81 ++++++++++++++++++++++- tests/unit/pass/RuntimeABITest.cpp | 27 ++++++++ tests/unit/pass/inputs/svcomp_defs.c | 25 +++++++ tests/unit/pass/inputs/svcomp_defs_late.c | 13 ++++ 10 files changed, 284 insertions(+), 31 deletions(-) create mode 100644 tests/unit/pass/inputs/svcomp_defs.c create mode 100644 tests/unit/pass/inputs/svcomp_defs_late.c diff --git a/modules/backend/pass/CMakeLists.txt b/modules/backend/pass/CMakeLists.txt index 1fbaabc04..3c94a8cc3 100755 --- a/modules/backend/pass/CMakeLists.txt +++ b/modules/backend/pass/CMakeLists.txt @@ -7,6 +7,8 @@ set(CXX_FLAGS "${CXX_FLAGS} -fno-rtti ") set_target_properties(DebugInfo PROPERTIES COMPILE_FLAGS ${CXX_FLAGS}) set_target_properties(RuntimeABI PROPERTIES COMPILE_FLAGS ${CXX_FLAGS}) +# Both are linked into every plugin (a shared object). +set_target_properties(DebugInfo RuntimeABI PROPERTIES POSITION_INDEPENDENT_CODE ON) list(APPEND MAP2CHECK_PASS_LIB "") list(APPEND MAP2CHECK_PASS_LIB "NonDetPass") diff --git a/modules/backend/pass/Map2CheckLibrary.cpp b/modules/backend/pass/Map2CheckLibrary.cpp index 6395bde44..9b9a66c4c 100644 --- a/modules/backend/pass/Map2CheckLibrary.cpp +++ b/modules/backend/pass/Map2CheckLibrary.cpp @@ -55,6 +55,8 @@ Map2CheckLibrary::Map2CheckLibrary() : mode(AnalysisModeOption) {} PreservedAnalyses Map2CheckLibrary::run(Function& F, llvm::FunctionAnalysisManager& AM) { llvm::Module& M = *F.getParent(); + // Normally done by NonDetPass already; idempotent. + Map2Check::resolveProgramDefinitions(M); this->setModeFunction = Map2Check::getOrInsertRuntime(M, Map2Check::RuntimeHook::SetMode); this->initFunction = diff --git a/modules/backend/pass/NonDetPass.cpp b/modules/backend/pass/NonDetPass.cpp index 30139c53f..bb069fef9 100644 --- a/modules/backend/pass/NonDetPass.cpp +++ b/modules/backend/pass/NonDetPass.cpp @@ -35,7 +35,9 @@ namespace { * is replaced instead, which reaches every call site at once. */ const char *const kAssumeByAbort[] = {"assume_abort_if_not", "assume_abort_if_not_", - "__VERIFIER_assume", + // A program's own __VERIFIER_assume is + // discarded for the library's instead + // (resolveProgramDefinitions). // The XCSP family spells it this way, // and spelling was the whole difference: // 59 of 59 XCSP tasks answered @@ -77,25 +79,6 @@ bool rewriteAssumeToPrune(Function &F) { if (F.arg_size() != 1 || !F.getArg(0)->getType()->isIntegerTy()) return false; if (!F.getReturnType()->isVoidTy()) return false; - // The program's own __VERIFIER_assume gives way to the library's: its - // body would otherwise call itself, and the link would see two - // definitions. It is renamed, made internal and left unused (the passes - // after this one in the pipeline still run on it, so it keeps a body); - // every use goes to the core declaration. - const char *coreAssume = - Map2Check::runtimeCall(Map2Check::RuntimeHook::Assume, F.getContext()) - .name; - if (F.getName() == coreAssume) { - F.setName("__map2check_program_assume"); - F.setLinkage(llvm::GlobalValue::InternalLinkage); - llvm::FunctionCallee core = Map2Check::getOrInsertRuntime( - *F.getParent(), Map2Check::RuntimeHook::Assume); - F.replaceAllUsesWith(core.getCallee()); - Map2Check::allowUnwind(*llvm::cast(core.getCallee())); - llvm::errs() << "[map2check] replaced the program's " << coreAssume - << " with the runtime's\n"; - return true; - } llvm::FunctionCallee assume = Map2Check::getOrInsertRuntime( *F.getParent(), Map2Check::RuntimeHook::Assume); @@ -168,6 +151,11 @@ Value *toSlotType(IRBuilder<> &builder, Value *value, PreservedAnalyses NonDetPass::run(Function &F, llvm::FunctionAnalysisManager &AM) { + // First thing of the first pass: program definitions of library exports + // give way to the library's or become internal (RuntimeABI), before any + // instrumentation looks at them. + bool resolved = Map2Check::resolveProgramDefinitions(*F.getParent()); + // The library's assume rejects an input by unwinding through its callers, // so no declaration of it or call to it may be nounwind (D1 condition 11). if (Function *assume = F.getParent()->getFunction( @@ -204,7 +192,7 @@ PreservedAnalyses NonDetPass::run(Function &F, } } if (nonDetCalls.empty() && crabAssumes.empty()) { - return PreservedAnalyses::all(); + return resolved ? PreservedAnalyses::none() : PreservedAnalyses::all(); } IRBuilder<> entryBuilder(&*F.getEntryBlock().getFirstInsertionPt()); diff --git a/modules/backend/pass/RuntimeABI.cpp b/modules/backend/pass/RuntimeABI.cpp index 23002b9da..3da318418 100644 --- a/modules/backend/pass/RuntimeABI.cpp +++ b/modules/backend/pass/RuntimeABI.cpp @@ -11,7 +11,9 @@ #include "RuntimeABI.hpp" #include +#include #include +#include #include namespace Map2Check { @@ -195,4 +197,66 @@ void allowUnwind(llvm::Function& fn) { } } +const std::vector& discardedProgramDefinitions() { + static const std::vector names = [] { + std::vector all = {"__VERIFIER_assume"}; + // The 16 generators the library exports (feature libfuzzer and klee). + for (const char* type : + {"bool", "char", "uchar", "short", "ushort", "int", "uint", "long", + "ulong", "float", "double", "size_t", "loff_t", "sector_t", + "pointer", "pchar"}) { + all.push_back(std::string("__VERIFIER_nondet_") + type); + } + return all; + }(); + return names; +} + +const std::vector& internalizedProgramDefinitions() { + static const std::vector names = { + "__VERIFIER_assert", "__VERIFIER_error", + "get_current_step", "get_next_step", + "get_current_property", "set_false_result", + "print_all_containers_as_json", "vcc_reset_meta_data"}; + return names; +} + +bool resolveProgramDefinitions(llvm::Module& module) { + bool changed = false; + llvm::LLVMContext& ctx = module.getContext(); + const char* coreAssume = runtimeCall(RuntimeHook::Assume, ctx).name; + + for (const std::string& name : discardedProgramDefinitions()) { + llvm::Function* program = module.getFunction(name); + if (program == nullptr || program->isDeclaration()) continue; + llvm::FunctionType* type = name == coreAssume + ? runtimeCall(RuntimeHook::Assume, ctx).type + : program->getFunctionType(); + program->setName("__map2check_program_" + name); + llvm::FunctionCallee library = module.getOrInsertFunction(name, type); + program->replaceAllUsesWith(library.getCallee()); + program->deleteBody(); + llvm::BasicBlock* entry = llvm::BasicBlock::Create(ctx, "entry", program); + new llvm::UnreachableInst(ctx, entry); + program->setLinkage(llvm::GlobalValue::InternalLinkage); + if (name == coreAssume) { + allowUnwind(*llvm::cast(library.getCallee())); + } + changed = true; + } + + for (const std::string& name : internalizedProgramDefinitions()) { + llvm::Function* program = module.getFunction(name); + if (program == nullptr || program->isDeclaration() || + program->hasLocalLinkage()) { + continue; + } + program->setComdat(nullptr); + program->setVisibility(llvm::GlobalValue::DefaultVisibility); + program->setLinkage(llvm::GlobalValue::InternalLinkage); + changed = true; + } + return changed; +} + } // namespace Map2Check diff --git a/modules/backend/pass/RuntimeABI.hpp b/modules/backend/pass/RuntimeABI.hpp index 9355a660b..5bf987983 100644 --- a/modules/backend/pass/RuntimeABI.hpp +++ b/modules/backend/pass/RuntimeABI.hpp @@ -28,6 +28,7 @@ #include #include +#include namespace Map2Check { @@ -110,6 +111,27 @@ NonDetValueSlot nonDetValueSlot(llvm::StringRef cType, llvm::LLVMContext& ctx); /// 11), so a nounwind declaration or call site of it is undefined behaviour. void allowUnwind(llvm::Function& fn); +/// Library exports a program may define itself (SV-COMP style); the link +/// would see two definitions. Two treatments, as develop had them: +/// +/// - Discarded: the program's definition gives way to the library's. A +/// program-defined nondet generator (`int __VERIFIER_nondet_int(void) +/// { return 0; }`) would feed constants instead of the fuzzer's or KLEE's +/// input, and the program's __VERIFIER_assume would abort where the +/// library prunes the path. Every use is sent to a declaration of the same +/// name; the old body is renamed __map2check_program_, made internal +/// and reduced to `unreachable` (passes later in the pipeline still visit +/// it, so it keeps a body). +/// - Internalized: the program keeps its own definition, with internal +/// linkage and the same name, so its calls use its body. +const std::vector& discardedProgramDefinitions(); +const std::vector& internalizedProgramDefinitions(); + +/// Applies both lists to `module`. Idempotent; true when it changed +/// anything. The first pass of every pipeline (NonDetPass) calls it before +/// any instrumentation. +bool resolveProgramDefinitions(llvm::Module& module); + } // namespace Map2Check #endif // MODULES_BACKEND_PASS_RUNTIMEABI_HPP_ diff --git a/tests/unit/pass/EndToEndLinkTest.cpp b/tests/unit/pass/EndToEndLinkTest.cpp index 3ac753cfb..5ed53b2c8 100644 --- a/tests/unit/pass/EndToEndLinkTest.cpp +++ b/tests/unit/pass/EndToEndLinkTest.cpp @@ -13,7 +13,9 @@ // // Each input of inputs/ is compiled as the frontend compiles the program // (Caller::compileFile: -c -emit-llvm -g -fexceptions -O0), instrumented with -// every pass of the mode as Caller::callPass chains them, and linked with +// every pass of the mode as Caller::callPass chains them (the table below +// mirrors modules/frontend/caller.cpp, Caller::callPass; keep them in step +// until Task 3.3 shares it), and linked with // clang-16 -fexceptions -fsanitize=fuzzer. #include @@ -156,6 +158,16 @@ std::set linkerErrors(const std::string& log) { return found; } +/// Writes `value` as the 4 little-endian bytes __VERIFIER_nondet_int reads. +void writeInt(const std::string& path, int32_t value) { + std::ofstream out(path, std::ios::binary); + unsigned char bytes[4]; + for (int b = 0; b < 4; ++b) { + bytes[b] = static_cast((static_cast(value) >> (8 * b)) & 0xff); + } + out.write(reinterpret_cast(bytes), 4); +} + struct LinkCase { std::string mode; std::string input; @@ -226,14 +238,6 @@ TEST(EndToEndRun, AssumeRejectionsUnwindAtO2UnderLibFuzzer) { // x <= 0 is rejected by __VERIFIER_assume(x > 0); x = 5 is accepted. fs::create_directories(dir + "/inputs"); - auto writeInt = [&](const std::string& path, int32_t value) { - std::ofstream out(path, std::ios::binary); - unsigned char bytes[4]; - for (int b = 0; b < 4; ++b) { - bytes[b] = static_cast((static_cast(value) >> (8 * b)) & 0xff); - } - out.write(reinterpret_cast(bytes), 4); - }; std::ostringstream files; for (int k = 0; k < 100; ++k) { std::string path = dir + "/inputs/rejected" + std::to_string(k); @@ -265,3 +269,30 @@ TEST(EndToEndRun, AssumeRejectionsUnwindAtO2UnderLibFuzzer) { EXPECT_EQ(errText.find(bad), std::string::npos) << bad << "\n" << errText; } } + +// SV-COMP programs define library exports themselves (inputs/svcomp_defs.c). +// At run time the nondet value comes from the fuzzer input, not from the +// program's `return 0;` generator, and the assume is the library's (it +// prunes, where the program's would abort); the program's internalized +// get_current_step keeps its own body. +TEST(EndToEndRun, ProgramDefinedExportsGiveWayToTheLibrary) { + std::string dir = freshWorkDir("svcomp-defs-O2"); + std::string bitcode = instrument(dir, "svcomp_defs.c", pipeline("assert")); + ASSERT_FALSE(bitcode.empty()) << readFile(dir + "/opt.err"); + ASSERT_EQ(link(dir, bitcode, "-O2"), 0) << readFile(dir + "/link.txt"); + + fs::create_directories(dir + "/inputs"); + writeInt(dir + "/inputs/rejected", 7); // __VERIFIER_assume(x != 7) + writeInt(dir + "/inputs/reached", 123456); // if (x == 123456) + std::ostringstream cmd; + cmd << dir << "/program " << dir << "/inputs/rejected " << dir + << "/inputs/reached > " << dir << "/run.out 2> " << dir << "/run.err"; + int rc = std::system(cmd.str().c_str()); + std::string out = readFile(dir + "/run.out"); + std::string errText = readFile(dir + "/run.err"); + EXPECT_EQ(rc, 0) << errText; + EXPECT_NE(out.find("from the input 42\n"), std::string::npos) << out; + for (const char* bad : {"deadly signal", "Aborted", "panic in FFI boundary"}) { + EXPECT_EQ(errText.find(bad), std::string::npos) << bad << "\n" << errText; + } +} diff --git a/tests/unit/pass/PassIRTest.cpp b/tests/unit/pass/PassIRTest.cpp index 1cf4628d2..5993464f1 100644 --- a/tests/unit/pass/PassIRTest.cpp +++ b/tests/unit/pass/PassIRTest.cpp @@ -703,7 +703,8 @@ TEST(PassIR, NonDetRewritesAbortingAssumes) { llvm::Function* verifierAssume = m->getFunction("__VERIFIER_assume"); ASSERT_NE(verifierAssume, nullptr); EXPECT_TRUE(verifierAssume->isDeclaration()); - llvm::Function* programAssume = m->getFunction("__map2check_program_assume"); + llvm::Function* programAssume = + m->getFunction("__map2check_program___VERIFIER_assume"); ASSERT_NE(programAssume, nullptr); EXPECT_TRUE(programAssume->hasInternalLinkage()); EXPECT_TRUE(programAssume->use_empty()); @@ -1064,3 +1065,81 @@ TEST(PassIR, MemoryTrackWasmModeEmitsWasmHooks) { EXPECT_EQ(stripCasts(freed[0]->getArgOperand(0)), alloc); EXPECT_TRUE(freed[0]->getArgOperand(1)->getType()->isIntegerTy(64)); } + +// --------------------------------------------------------------------------- +// Program definitions of library exports (RuntimeABI +// resolveProgramDefinitions, run first by NonDetPass) +// --------------------------------------------------------------------------- + +namespace { + +/// The program's definition of `name` gave way to the library's: `name` is a +/// declaration and its old body is an unused internal stub. +void expectDiscarded(llvm::Module& m, const std::string& name) { + SCOPED_TRACE(name); + llvm::Function* library = m.getFunction(name); + ASSERT_NE(library, nullptr); + EXPECT_TRUE(library->isDeclaration()); + llvm::Function* program = m.getFunction("__map2check_program_" + name); + ASSERT_NE(program, nullptr); + EXPECT_TRUE(program->hasInternalLinkage()); + EXPECT_TRUE(program->use_empty()); + ASSERT_EQ(program->size(), 1u); + EXPECT_TRUE(llvm::isa(program->getEntryBlock().front())); +} + +/// The program keeps its definition of `name`, internal and under the same +/// name, so the library's export does not clash with it. +void expectInternalized(llvm::Module& m, const std::string& name) { + SCOPED_TRACE(name); + llvm::Function* program = m.getFunction(name); + ASSERT_NE(program, nullptr); + EXPECT_FALSE(program->isDeclaration()); + EXPECT_TRUE(program->hasInternalLinkage()); + EXPECT_EQ(m.getFunction("__map2check_program_" + name), nullptr); +} + +} // namespace + +TEST(PassIR, ProgramDefinitionsOfLibraryExportsAreResolved) { + auto m = runPassOn("NonDetPass,AssertPass,Map2CheckLibrary", + "nondet-pass,assert-pass,map2check-library", + "svcomp_defs.c", "-m2c-analysis-mode=assert"); + ASSERT_VALID(m); + expectDiscarded(*m, "__VERIFIER_nondet_int"); + expectDiscarded(*m, "__VERIFIER_assume"); + expectNoNounwind(*m, "__VERIFIER_assume"); + expectInternalized(*m, "__VERIFIER_assert"); + expectInternalized(*m, "__VERIFIER_error"); + expectInternalized(*m, "get_current_step"); + + // The generator call now reaches the library and is still logged. + std::vector gen = callsTo(*m, "__VERIFIER_nondet_int"); + ASSERT_EQ(gen.size(), 1u); + EXPECT_EQ(gen[0]->getFunction()->getName(), "__map2check_main__"); + EXPECT_EQ(callsTo(*m, "map2check_save_nondet_log_int").size(), 1u); + + // The program's __VERIFIER_assert keeps its body, and AssertPass still + // instruments the call to it (matched by name). + llvm::Function* assertFn = m->getFunction("__VERIFIER_assert"); + bool callsReachError = false; + for (llvm::CallInst* call : callsTo(*m, "reach_error")) { + callsReachError |= call->getFunction() == assertFn; + } + EXPECT_TRUE(callsReachError); + std::vector asserts = callsTo(*m, "__VERIFIER_assert"); + ASSERT_EQ(asserts.size(), 1u); + std::vector checks = callsTo(*m, "map2check_is_valid_assert"); + ASSERT_EQ(checks.size(), 1u); + EXPECT_EQ(checks[0]->getArgOperand(2), asserts[0]->getArgOperand(0)); +} + +TEST(PassIR, ProgramDefinitionsAfterMainAreResolvedToo) { + auto m = runPassOn("NonDetPass,AssertPass", "nondet-pass,assert-pass", + "svcomp_defs_late.c"); + ASSERT_VALID(m); + expectDiscarded(*m, "__VERIFIER_nondet_int"); + expectInternalized(*m, "__VERIFIER_assert"); + EXPECT_EQ(callsTo(*m, "map2check_save_nondet_log_int").size(), 1u); + EXPECT_EQ(callsTo(*m, "map2check_is_valid_assert").size(), 1u); +} diff --git a/tests/unit/pass/RuntimeABITest.cpp b/tests/unit/pass/RuntimeABITest.cpp index 2077ea813..40036af6f 100644 --- a/tests/unit/pass/RuntimeABITest.cpp +++ b/tests/unit/pass/RuntimeABITest.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -217,3 +218,29 @@ TEST(RuntimeABI, NonDetValueSlotsFollowApiDeltas) { } EXPECT_EQ(Map2Check::nonDetValueSlot("float", ctx).type, nullptr); } + +// The lists of program definitions that give way or become internal: the +// assume and the 16 generators the library exports; the SV-COMP and +// unprefixed runtime names. No name is in both. +TEST(RuntimeABI, ProgramDefinitionLists) { + const std::vector& discarded = Map2Check::discardedProgramDefinitions(); + const std::vector& internalized = + Map2Check::internalizedProgramDefinitions(); + EXPECT_EQ(discarded.size(), 17u); + EXPECT_EQ(internalized.size(), 8u); + std::set all(discarded.begin(), discarded.end()); + all.insert(internalized.begin(), internalized.end()); + EXPECT_EQ(all.size(), discarded.size() + internalized.size()); + EXPECT_TRUE(all.count("__VERIFIER_assume")); + EXPECT_TRUE(all.count("__VERIFIER_nondet_pchar")); + EXPECT_TRUE(all.count("__VERIFIER_assert")); + EXPECT_TRUE(all.count("vcc_reset_meta_data")); + // Every generator the pass logs is discarded when the program defines it. + for (const char* type : {"int", "uint", "char", "uchar", "short", "ushort", + "long", "ulong", "bool", "pointer", "pchar", + "size_t", "loff_t", "sector_t", "double"}) { + EXPECT_TRUE(std::count(discarded.begin(), discarded.end(), + Map2Check::nonDetGenerator(type))) + << type; + } +} diff --git a/tests/unit/pass/inputs/svcomp_defs.c b/tests/unit/pass/inputs/svcomp_defs.c new file mode 100644 index 000000000..536b3a1f6 --- /dev/null +++ b/tests/unit/pass/inputs/svcomp_defs.c @@ -0,0 +1,25 @@ +/* SV-COMP style: the program defines library exports itself. */ +#include +#include +void reach_error(void) { abort(); } +void __VERIFIER_error(void) { abort(); } +void __VERIFIER_assert(int cond) { + if (!cond) { + reach_error(); + } +} +int __VERIFIER_nondet_int(void) { return 0; } +void __VERIFIER_assume(int cond) { + if (!cond) abort(); +} +int get_current_step(void) { return 42; } +int main(void) { + int x = __VERIFIER_nondet_int(); + __VERIFIER_assume(x != 7); + if (x == 123456) { + printf("from the input %d\n", get_current_step()); + } + __VERIFIER_assert(x != 99); + if (x == 98) __VERIFIER_error(); + return 0; +} diff --git a/tests/unit/pass/inputs/svcomp_defs_late.c b/tests/unit/pass/inputs/svcomp_defs_late.c new file mode 100644 index 000000000..c657e45d4 --- /dev/null +++ b/tests/unit/pass/inputs/svcomp_defs_late.c @@ -0,0 +1,13 @@ +/* The definitions come after main, so a pass meets main's calls first. */ +extern void abort(void); +int __VERIFIER_nondet_int(void); +void __VERIFIER_assert(int cond); +int main(void) { + int x = __VERIFIER_nondet_int(); + __VERIFIER_assert(x != 99); + return 0; +} +int __VERIFIER_nondet_int(void) { return 0; } +void __VERIFIER_assert(int cond) { + if (!cond) abort(); +} From b96b06a476406dccfff176c64b41c03465215f88 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 13:55:18 -0400 Subject: [PATCH 24/44] feat: link map2check-library instead of the C bitcode runtime The frontend links the Rust runtime (decision D1) and no bitcode of the C runtime, WasmRuntimeStubs.bc included (the library's wasm feature provides wasm_rt_*): - afl/none (route B1): the -fuzzed, -witness-fuzzed and -cmplog binaries are afl-clang-fast -fsanitize=fuzzer -result.bc ${MAP2CHECK_PATH}/lib/libmap2check.a -ldl -lpthread -lm, with the previous -g/-O2 flags; CmpLog runs under `env AFL_LLVM_CMPLOG=1`. The library's LLVMFuzzerTestOneInput drives __map2check_main__. - symex (route A'): llvm-link of -output.bc with ${MAP2CHECK_PATH}/lib/map2check-klee.bc. --nondet-generator symex on an install without that file exits with code 3 and says how to fix it; the hybrid default skips its KLEE phase with an error message. - Witness (Step 4b): the witness binary and the witness bitcode also link a generated constructor that calls map2check_enable_witness(), native for AFL++ and -emit-llvm for KLEE, both with -fexceptions. - Crashes are replayed on the witness binary with the file as an argument, not on stdin (D1 condition 2). - The afl-fuzz placeholder seed is 8 bytes, the widest nondet value, so CmpLog finds a whole operand in it (D1 condition 4); a seed directory that already holds seeds is left untouched. - --btree is a no-op that logs "--btree is ignored by the Rust runtime" (provisional, decision D3). The command builders are pure functions in caller_link.cpp, covered by CallerLinkTest over every mode and generator, wasm, witness and CmpLog. --- modules/frontend/CMakeLists.txt | 2 + modules/frontend/caller.cpp | 197 +++++++--------- modules/frontend/caller.hpp | 86 ++++++- modules/frontend/caller_link.cpp | 143 ++++++++++++ modules/frontend/map2check.cpp | 25 +- tests/unit/frontend/CMakeLists.txt | 7 + tests/unit/frontend/CallerLinkTest.cpp | 312 +++++++++++++++++++++++++ 7 files changed, 646 insertions(+), 126 deletions(-) create mode 100644 modules/frontend/caller_link.cpp create mode 100644 tests/unit/frontend/CallerLinkTest.cpp diff --git a/modules/frontend/CMakeLists.txt b/modules/frontend/CMakeLists.txt index 19778b60e..28aa25671 100644 --- a/modules/frontend/CMakeLists.txt +++ b/modules/frontend/CMakeLists.txt @@ -16,11 +16,13 @@ configure_file(map2check_version.hpp.in "${CMAKE_CURRENT_BINARY_DIR}/map2check_version.hpp" @ONLY) add_library(Caller OBJECT caller.cpp) +add_library(CallerLink OBJECT caller_link.cpp) add_library(WasmLifter OBJECT wasm_lifter.cpp) #set_target_properties(Caller PROPERTIES COMPILE_FLAGS ${CXX_FLAGS}) add_executable(map2check map2check.cpp $ + $ $ $ $ diff --git a/modules/frontend/caller.cpp b/modules/frontend/caller.cpp index 5958fb4dc..a13f397ff 100644 --- a/modules/frontend/caller.cpp +++ b/modules/frontend/caller.cpp @@ -399,21 +399,20 @@ void Caller::applyNonDetGenerator() { std::to_string(Map2Check::killGracePeriod) + " " + std::to_string(static_cast(compileBudget)) + " "; - command - << bound << Map2Check::aflClangFastBinary() - << " -g " << Caller::postOptimizationFlags() - << " -o " + programHash + "-fuzzed.out" - << " " + programHash + "-result.bc"; - + // Route B1 (D1): afl-clang-fast's libFuzzer driver calls the + // library's LLVMFuzzerTestOneInput, which runs __map2check_main__ once + // per input. The witness binary also links the witness constructor. + Caller::LinkInputs inputs{programHash, map2checkMode, nonDetGenerator, + dataStructure, wasmMode, false}; + command << bound << buildFuzzerCommand(inputs); + Map2Check::Log::Debug(command.str()); system(command.str().c_str()); + Caller::LinkInputs witnessInputs = inputs; + witnessInputs.witness = true; std::ostringstream commandWitness; - commandWitness.str(""); - commandWitness << bound << Map2Check::aflClangFastBinary() - << " -g " - << " -o " + programHash + "-witness-fuzzed.out" - << " " + programHash + "-witness-result.bc"; - + commandWitness << bound << buildFuzzerCommand(witnessInputs); + Map2Check::Log::Debug(commandWitness.str()); system(commandWitness.str().c_str()); // The CmpLog companion binary: the same program instrumented to log @@ -423,12 +422,11 @@ void Caller::applyNonDetGenerator() { // previous fuzzer ran with (-use_value_profile=1); without it the // tacasv1 comparison would pit an unarmed AFL++ against an armed // LibFuzzer. Optional: if it does not build, the fuzzer runs without. + Caller::LinkInputs cmplogInputs = inputs; + cmplogInputs.cmplog = true; std::ostringstream commandCmplog; - commandCmplog << "AFL_LLVM_CMPLOG=1 " << bound - << Map2Check::aflClangFastBinary() << " -g " - << Caller::postOptimizationFlags() - << " -o " + programHash + "-cmplog.out" - << " " + programHash + "-result.bc"; + commandCmplog << bound << buildFuzzerCommand(cmplogInputs); + Map2Check::Log::Debug(commandCmplog.str()); system(commandCmplog.str().c_str()); // Announced rather than discovered later as a silent no-op -- the same @@ -436,9 +434,10 @@ void Caller::applyNonDetGenerator() { std::error_code fuzzErr; if (!std::filesystem::exists(programHash + "-fuzzed.out", fuzzErr)) { Map2Check::Log::Warning( - "the AFL++ binary did not build within " + + "the AFL++ binary did not build (link error, or over the " + std::to_string(static_cast(compileBudget)) + - "s -- skipping the fuzzer phase and leaving the budget to KLEE"); + "s budget) -- skipping the fuzzer phase and leaving the budget " + "to KLEE"); } else if (!std::filesystem::exists(programHash + "-cmplog.out", fuzzErr)) { Map2Check::Log::Warning( @@ -553,99 +552,59 @@ int Caller::callPass(std::string target_function, bool sv_comp) { } void Caller::linkLLVM() { - /* Link functions called after executing the passes */ - // TODO(rafa.sa.xp@gmail.com) Only link against used libraries - + // The runtime is map2check-library (decision D1). No bitcode of the C + // runtime is linked any more: the mode reaches the library through + // map2check_set_mode, and the witness through a constructor (Step 4b). + // See caller_link.cpp. Map2Check::Log::Info("Linking with map2check library"); - std::ostringstream witnessCommand; - std::ostringstream linkCommand; - linkCommand.str(""); - linkCommand << Map2Check::llvmLinkBinary; - linkCommand << " " + programHash + "-output.bc" - << " ${MAP2CHECK_PATH}/lib/Map2CheckFunctions.bc" - << " ${MAP2CHECK_PATH}/lib/TrackBBLog.bc" - << " ${MAP2CHECK_PATH}/lib/NonDetLog.bc" - << " ${MAP2CHECK_PATH}/lib/PropertyGenerator.bc"; - - switch (dataStructure) { - case DataStructure::Array: { - linkCommand << " ${MAP2CHECK_PATH}/lib/ContainerRealloc.bc"; - break; - } - case DataStructure::BTree: { - linkCommand << " ${MAP2CHECK_PATH}/lib/ContainerBTree.bc" - << " ${MAP2CHECK_PATH}/lib/BTree.bc"; - break; - } + if (this->dataStructure == DataStructure::BTree) { + // Already announced at option parsing; the Rust runtime has one container. + Map2Check::Log::Debug("--btree ignored at link time"); } - switch (map2checkMode) { - case Map2CheckMode::MEMTRACK_MODE: { - linkCommand << " ${MAP2CHECK_PATH}/lib/AnalysisModeMemtrack.bc" - << " ${MAP2CHECK_PATH}/lib/AllocationLog.bc" - << " ${MAP2CHECK_PATH}/lib/ListLog.bc" - << " ${MAP2CHECK_PATH}/lib/HeapLog.bc"; - break; - } - case Map2CheckMode::MEMCLEANUP_MODE: { - linkCommand << " ${MAP2CHECK_PATH}/lib/AnalysisModeMemcleanup.bc" - << " ${MAP2CHECK_PATH}/lib/AllocationLog.bc" - << " ${MAP2CHECK_PATH}/lib/ListLog.bc" - << " ${MAP2CHECK_PATH}/lib/HeapLog.bc"; - break; - } - case Map2CheckMode::OVERFLOW_MODE: { - linkCommand << " ${MAP2CHECK_PATH}/lib/AnalysisModeOverflow.bc"; - break; - } - case Map2CheckMode::ASSERT_MODE: { - linkCommand << " ${MAP2CHECK_PATH}/lib/AnalysisModeAssert.bc"; - break; - } - case Map2CheckMode::REACHABILITY_MODE: { - // Since the map2check api provides the function, we do not need to do any - // analysis - linkCommand << " ${MAP2CHECK_PATH}/lib/AnalysisModeNone.bc"; - break; - } - case Map2CheckMode::COVER_BRANCHES_MODE: { - // No property, so no analysis -- the run exists to explore and record. - linkCommand << " ${MAP2CHECK_PATH}/lib/AnalysisModeNone.bc"; - break; - } + Caller::LinkInputs verification{programHash, map2checkMode, nonDetGenerator, + dataStructure, wasmMode, false}; + Caller::LinkInputs witness = verification; + witness.witness = true; + + if (nonDetGenerator == NonDetGenerator::Klee && !kleeRuntimeInstalled()) { + Map2Check::Log::Error( + "the symex generator needs the KLEE runtime of map2check-library at " + + installedKleeRuntime() + + ", which this install does not have (configure Map2Check with " + "-DMAP2CHECK_RUST_KLEE_BC). Skipping the KLEE phase."); + return; } - switch (nonDetGenerator) { - case (NonDetGenerator::None): { - linkCommand << " ${MAP2CHECK_PATH}/lib/NonDetGeneratorNone.bc"; - break; - } - case (NonDetGenerator::Klee): { // TODO(hbgit): Add klee non det generator - linkCommand << " ${MAP2CHECK_PATH}/lib/NonDetGeneratorKlee.bc"; - break; - } - case (NonDetGenerator::AFLPlusPlus): { - linkCommand << " ${MAP2CHECK_PATH}/lib/NonDetGeneratorAFL.bc"; - break; - } + // The witness constructor: native for the AFL++ witness binary, bitcode + // for KLEE, in both cases with -fexceptions (D1 condition 11). + { + std::ofstream source(witnessSourcePath(witness)); + source << witnessConstructorSource(); + if (!source.good()) + Map2Check::Log::Warning("could not write the witness constructor"); } - - if (this->wasmMode) { - linkCommand << " ${MAP2CHECK_PATH}/lib/WasmRuntimeStubs.bc"; + const std::string compileWitness = buildWitnessObjectCommand(witness); + Map2Check::Log::Debug(compileWitness); + if (system(compileWitness.c_str()) != 0) { + Map2Check::Log::Warning( + "the witness constructor did not compile -- a violation will not be " + "confirmed"); } - witnessCommand.str(""); - witnessCommand << linkCommand.str(); - witnessCommand << " ${MAP2CHECK_PATH}/lib/WitnessGeneration.bc"; - witnessCommand << " > " + programHash + "-witness-result.bc"; - Map2Check::Log::Debug(witnessCommand.str()); - system(witnessCommand.str().c_str()); - - linkCommand << " ${MAP2CHECK_PATH}/lib/WitnessGenerationNone.bc"; - linkCommand << " > " + programHash + "-result.bc"; - Map2Check::Log::Debug(linkCommand.str()); - system(linkCommand.str().c_str()); + // KLEE runs only the witness bitcode, and linking the 7 MB runtime twice + // would be wasted time; the native generators link both variants (the + // runtime itself enters at the afl-clang-fast step). + std::vector variants = {witness}; + if (nonDetGenerator != NonDetGenerator::Klee) variants.push_back(verification); + for (const Caller::LinkInputs &variant : variants) { + const std::string command = buildLinkCommand(variant); + Map2Check::Log::Debug(command); + if (system(command.c_str()) != 0) { + Map2Check::Log::Warning("llvm-link failed for " + resultBitcode(variant)); + } + } } std::string Caller::generateWasmWrapperStatic(const std::string& wasmOutHeaderPath, @@ -714,6 +673,11 @@ void Caller::executeAnalysis(std::string solvername) { break; } case (NonDetGenerator::Klee): { + if (!std::filesystem::exists(programHash + "-witness-result.bc")) { + Map2Check::Log::Warning( + "no KLEE bitcode was linked -- skipping the KLEE phase"); + break; + } Map2Check::Log::Info("Executing Klee with map2check"); std::ostringstream kleeCommand; kleeCommand.str(""); @@ -904,19 +868,16 @@ void Caller::executeAnalysis(std::string solvername) { // without the exchange leaves no seeds/ behind. Either way it gets one // placeholder input when empty, because afl-fuzz refuses to start // without one (the previous fuzzer could start from nothing). + // + // The placeholder is at least kAflSeedMinBytes long (D1 condition 4): + // the uninstrumented Rust reader adds no edges that would grow the + // corpus to a whole operand, so CmpLog needs one in the seed. std::error_code seedErr; const std::string inputDir = this->seedExchange ? std::string(Caller::seedDirectory) : "afl-in"; - std::filesystem::create_directories(inputDir, seedErr); - if (std::filesystem::is_empty(inputDir, seedErr)) { - std::ofstream seed(inputDir + "/seed"); - seed << "A"; - if (!seed.good()) - Map2Check::Log::Warning("could not write the AFL++ placeholder seed"); - } - if (seedErr) + if (!prepareAflInputDir(inputDir)) Map2Check::Log::Warning("could not prepare the AFL++ input dir " + - inputDir + ": " + seedErr.message()); + inputDir); std::filesystem::remove_all("afl-out", seedErr); // The AFL_* settings go on the command line, not only into the dev // image's ENV, so that a release install or a benchmark host outside @@ -959,9 +920,9 @@ void Caller::executeAnalysis(std::string solvername) { const std::string aflFindings = "afl-out/default"; // Replay crashes with the witness binary to confirm a real violation. - // Standalone, the persistent binary reads its input from stdin (see - // NonDetGeneratorAFL.c), so the crash file is redirected in; the names - // AFL++ gives them contain ':' and ',', hence the quoting. Stop at the + // The crash file is passed as an ARGUMENT: the libFuzzer driver reading + // stdin never ends (D1 condition 2). The names AFL++ gives them contain + // ':' and ',', hence the quoting (buildReplayCommand). Stop at the // first confirmed one: every replay rewrites the recorded property, and // a later one that does not reproduce would overwrite the violation. // Each replay is capped: a crash that does not reproduce from a fresh @@ -978,9 +939,9 @@ void Caller::executeAnalysis(std::string solvername) { if (entry.path().filename() == "README.txt") continue; std::ostringstream commandWitness; commandWitness << "timeout -k " << Map2Check::killGracePeriod << " " - << replayBudget << " ./" << programHash - << "-witness-fuzzed.out < '" << entry.path().string() - << "'"; + << replayBudget << " " + << buildReplayCommand(programHash, + entry.path().string()); system(commandWitness.str().c_str()); if (isWitnessFileCreated()) break; } diff --git a/modules/frontend/caller.hpp b/modules/frontend/caller.hpp index 945ff3034..4624fa0c8 100644 --- a/modules/frontend/caller.hpp +++ b/modules/frontend/caller.hpp @@ -9,6 +9,7 @@ #ifndef MODULES_FRONTEND_CALLER_HPP_ #define MODULES_FRONTEND_CALLER_HPP_ +#include #include #include @@ -65,7 +66,7 @@ inline const char* runtimeAnalysisMode(Map2CheckMode mode) { // TODO(hbgit): Add suport to other nondet like: klee, afl++, afl+klee enum class NonDetGenerator { None, /**< Do not generate any input */ - AFLPlusPlus, /**< AFL++ (persistent mode, PCGUARD) */ + AFLPlusPlus, /**< AFL++ through its libFuzzer driver (D1 route B1) */ Klee, /**< Use klee for symbolic analysis */ }; @@ -95,6 +96,19 @@ class Caller { bool witnessVerified = false; public: + /** What decides how the instrumented program is linked with the runtime + * (map2check-library, decision D1). Consumed by the pure command builders + * below, so the link can be tested without running anything. */ + struct LinkInputs { + std::string hash; //!< scratch prefix, -output.bc + Map2CheckMode mode; //!< property mode + NonDetGenerator generator; //!< None/AFLPlusPlus: native, Klee: bitcode + DataStructure dataStructure; //!< ignored by the Rust runtime (--btree) + bool wasm; //!< wasm2c-lifted input + bool witness; //!< witness binary/bitcode (Step 4b) + bool cmplog = false; //!< AFL++ CmpLog companion binary + }; + /** @brief Constructor if .bc file already exists * @param bc_progam_path Path for the file */ Caller(std::string bc_program_path, Map2CheckMode mode, @@ -214,7 +228,7 @@ class Caller { /** Instrument and execute nondeterministic generator */ void applyNonDetGenerator(); - /** Use btree mode */ + /** Use btree mode. Ignored by the Rust runtime (kBtreeIgnoredWarning). */ void useBTree() { this->dataStructure = DataStructure::BTree; } /** Generate wasm wrapper bitcode for KLEE compatibility */ @@ -243,6 +257,74 @@ class Caller { const std::string& entry, const std::string& label); }; +// --------------------------------------------------------------------------- +// Linking with map2check-library (caller_link.cpp). Pure: they build strings +// or touch only the directory they are given, so CallerLinkTest covers them. +// --------------------------------------------------------------------------- + +/** Installed native runtime, linked into every AFL++ binary (route B). */ +inline constexpr const char* kRustRuntimeLibrary = + "${MAP2CHECK_PATH}/lib/libmap2check.a"; +/** Installed KLEE runtime bitcode (route A'), optional in CMake. */ +inline constexpr const char* kRustKleeRuntime = + "${MAP2CHECK_PATH}/lib/map2check-klee.bc"; +/** System libraries the Rust standard library needs. */ +inline constexpr const char* kRustRuntimeSystemLibs = "-ldl -lpthread -lm"; +/** Minimum size of the AFL++ placeholder seed (D1 condition 4): the widest + * value a nondet generator reads (long, double, pointers). */ +inline constexpr std::size_t kAflSeedMinBytes = 8; +/** Logged once when --btree is given. Provisional until decision D3. */ +inline constexpr const char* kBtreeIgnoredWarning = + "--btree is ignored by the Rust runtime"; + +/** -result.bc, or -witness-result.bc for the witness variant. */ +std::string resultBitcode(const Caller::LinkInputs& in); + +/** llvm-link of the instrumented module into resultBitcode(in). Native + * generators link nothing else (the runtime enters at the final link); + * Klee links map2check-klee.bc and, for the witness, the witness bitcode. */ +std::string buildLinkCommand(const Caller::LinkInputs& in); + +/** afl-clang-fast -fsanitize=fuzzer over resultBitcode(in), the native + * witness object (witness only) and libmap2check.a (D1 route B1). CmpLog is + * prefixed with `env AFL_LLVM_CMPLOG=1`, so the command can follow `timeout`. */ +std::string buildFuzzerCommand(const Caller::LinkInputs& in); + +/** Name of the binary buildFuzzerCommand(in) writes. */ +std::string fuzzerBinary(const Caller::LinkInputs& in); + +/** C source of the witness constructor (Step 4b). */ +std::string witnessConstructorSource(); + +/** -witness.c, the file witnessConstructorSource() is written to. */ +std::string witnessSourcePath(const Caller::LinkInputs& in); + +/** -witness.bc for Klee, -witness.o otherwise. */ +std::string witnessObjectPath(const Caller::LinkInputs& in); + +/** clang -c (-emit-llvm for Klee) -fexceptions of the witness constructor. */ +std::string buildWitnessObjectCommand(const Caller::LinkInputs& in); + +/** Replay of one AFL++ finding on the witness binary, the file passed as an + * ARGUMENT (D1 condition 2: the libFuzzer driver never ends reading stdin). */ +std::string buildReplayCommand(const std::string& hash, + const std::string& input); + +/** Makes `dir` usable as afl-fuzz -i: creates it and, only when it is empty, + * writes one placeholder seed of at least kAflSeedMinBytes bytes. A directory + * that already holds seeds (the KLEE exchange) is left untouched. Returns + * false if the directory or the seed could not be written. */ +bool prepareAflInputDir(const std::string& dir); + +/** kRustKleeRuntime with MAP2CHECK_PATH expanded from the environment. */ +std::string installedKleeRuntime(); + +/** Whether installedKleeRuntime() exists. */ +bool kleeRuntimeInstalled(); + +/** Logs kBtreeIgnoredWarning. */ +void warnBtreeIgnored(); + } // namespace Map2Check #endif // MODULES_FRONTEND_CALLER_HPP_ diff --git a/modules/frontend/caller_link.cpp b/modules/frontend/caller_link.cpp new file mode 100644 index 000000000..d33652ece --- /dev/null +++ b/modules/frontend/caller_link.cpp @@ -0,0 +1,143 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// Linking the instrumented program with map2check-library (decision D1 in +// map2check-library's docs/cutover/decisoes.md): +// +// afl / none route B + B1: the instrumented bitcode is compiled natively by +// afl-clang-fast -fsanitize=fuzzer and linked with the installed +// libmap2check.a, whose LLVMFuzzerTestOneInput drives the +// renamed __map2check_main__. No runtime bitcode is llvm-linked. +// symex route A': the instrumented bitcode is llvm-linked with +// map2check-klee.bc (rustc 1.72.1 / LLVM 16), which defines the +// main KLEE runs. +// +// The C runtime chose the property mode, the container, the generator and +// the witness behaviour by WHICH .bc files it linked. The Rust runtime is one +// library: the mode comes from map2check_set_mode (Map2CheckLibrary pass), +// there is one container, and the witness is switched on at run time by a +// constructor that calls map2check_enable_witness (Step 4b), linked only into +// the witness artefacts as WitnessGeneration.bc used to be. + +#include +#include +#include +#include +#include + +#include "caller.hpp" +#include "utils/clang.hpp" +#include "utils/log.hpp" +#include "utils/tools.hpp" + +namespace Map2Check { + +std::string resultBitcode(const Caller::LinkInputs& in) { + return in.hash + (in.witness ? "-witness-result.bc" : "-result.bc"); +} + +std::string witnessSourcePath(const Caller::LinkInputs& in) { + return in.hash + "-witness.c"; +} + +std::string witnessObjectPath(const Caller::LinkInputs& in) { + return in.hash + + (in.generator == NonDetGenerator::Klee ? "-witness.bc" : "-witness.o"); +} + +std::string witnessConstructorSource() { + return "void map2check_enable_witness(void);\n" + "__attribute__((constructor)) static void m2c_witness(void) {\n" + " map2check_enable_witness();\n" + "}\n"; +} + +std::string buildWitnessObjectCommand(const Caller::LinkInputs& in) { + std::ostringstream command; + command << clangBinary << " -c"; + if (in.generator == NonDetGenerator::Klee) command << " -emit-llvm"; + command << " " << kProgramUnwindFlags << " -o " << witnessObjectPath(in) + << " " << witnessSourcePath(in); + return command.str(); +} + +std::string buildLinkCommand(const Caller::LinkInputs& in) { + std::ostringstream command; + command << llvmLinkBinary << " " << in.hash << "-output.bc"; + if (in.generator == NonDetGenerator::Klee) { + command << " " << kRustKleeRuntime; + if (in.witness) command << " " << witnessObjectPath(in); + } + command << " -o " << resultBitcode(in); + return command.str(); +} + +std::string fuzzerBinary(const Caller::LinkInputs& in) { + if (in.cmplog) return in.hash + "-cmplog.out"; + return in.hash + (in.witness ? "-witness-fuzzed.out" : "-fuzzed.out"); +} + +std::string buildFuzzerCommand(const Caller::LinkInputs& in) { + // Flags as before the cutover: the fuzzing and CmpLog binaries at -O2, the + // witness (replay) binary without. CmpLog instruments the fuzzing program, + // so it never carries the witness constructor. + Caller::LinkInputs native = in; + native.generator = NonDetGenerator::AFLPlusPlus; + native.witness = in.witness && !in.cmplog; + std::ostringstream command; + if (in.cmplog) command << "env AFL_LLVM_CMPLOG=1 "; + command << aflClangFastBinary() << " -g "; + if (!native.witness) command << "-O2 "; + command << "-fsanitize=fuzzer " << resultBitcode(native) << " "; + if (native.witness) command << witnessObjectPath(native) << " "; + command << kRustRuntimeLibrary << " " << kRustRuntimeSystemLibs << " -o " + << fuzzerBinary(in); + return command.str(); +} + +std::string buildReplayCommand(const std::string& hash, + const std::string& input) { + std::string quoted; + for (char c : input) { + if (c == '\'') + quoted += "'\\''"; + else + quoted += c; + } + return "./" + hash + "-witness-fuzzed.out '" + quoted + "'"; +} + +bool prepareAflInputDir(const std::string& dir) { + std::error_code error; + std::filesystem::create_directories(dir, error); + if (error) return false; + const bool empty = std::filesystem::is_empty(dir, error); + if (error) return false; + if (!empty) return true; + // afl-fuzz refuses an empty -i. The placeholder is as wide as the widest + // value a generator reads, so CmpLog's input-to-state stage finds a whole + // operand in the input from the first execution (D1 condition 4). + std::ofstream seed(dir + "/seed", std::ios::binary); + seed << std::string(kAflSeedMinBytes, 'A'); + return seed.good(); +} + +std::string installedKleeRuntime() { + const char* prefix = getenv("MAP2CHECK_PATH"); + return std::string(prefix != nullptr ? prefix : "") + + "/lib/map2check-klee.bc"; +} + +bool kleeRuntimeInstalled() { + std::error_code error; + return std::filesystem::is_regular_file(installedKleeRuntime(), error); +} + +void warnBtreeIgnored() { Log::Warning(kBtreeIgnoredWarning); } + +} // namespace Map2Check diff --git a/modules/frontend/map2check.cpp b/modules/frontend/map2check.cpp index a39aed7d7..100d5db21 100644 --- a/modules/frontend/map2check.cpp +++ b/modules/frontend/map2check.cpp @@ -496,10 +496,6 @@ int map2check_execution(map2check_args args) { caller->compileCFile(is_llvmir_in); } - if (args.btree) { - caller->useBTree(); - } - // (2) Instrument functions for current mode // BEFORE instrumentation, and the order was learned the hard way. // @@ -787,8 +783,8 @@ z3 (Z3 is default), btor (Boolector), and yices2 (Yices))") ("architecture", po::value()->default_value("64bit"), "\tmachine model recorded in the test-suite metadata") ("expected-result", po::value(), "\tspecifies type of violation expected") - ("btree", "\tuses btree structure to hold information (experimental, use this " - "if you are having memory problems)") + ("btree", "\tignored: the Rust runtime has a single container (kept for " + "compatibility)") ("wasm", "\tverify a WebAssembly (.wasm) binary via wasm2c lifting") ("entry-function", po::value()->default_value("main"), R"(define the entry function name (default: main))"); @@ -865,7 +861,9 @@ z3 (Z3 is default), btor (Boolector), and yices2 (Yices))") args.mode = Map2Check::Map2CheckMode::MEMCLEANUP_MODE; } if (vm.count("btree")) { + // Provisional until decision D3: map2check-library has one container. args.btree = true; + Map2Check::warnBtreeIgnored(); } if (vm.count("add-invariants")) { args.invCrabLlvm = true; @@ -964,6 +962,21 @@ z3 (Z3 is default), btor (Boolector), and yices2 (Yices))") return ERROR_UNAVAILABLE_CAPABILITY; } + // The symex generator runs map2check-library's KLEE runtime bitcode, + // which a build without -DMAP2CHECK_RUST_KLEE_BC does not install. Asked + // for explicitly, that is a missing capability; the hybrid default only + // loses its KLEE phase, and linkLLVM says so. + if (args.generator == Map2Check::NonDetGenerator::Klee && + !Map2Check::kleeRuntimeInstalled()) { + Map2Check::Log::Error( + "--nondet-generator symex needs the KLEE runtime of " + "map2check-library at " + Map2Check::installedKleeRuntime() + + ", which this install does not have. Rebuild Map2Check with " + "-DMAP2CHECK_RUST_KLEE_BC=, or use " + "--nondet-generator afl."); + return ERROR_UNAVAILABLE_CAPABILITY; + } + if (vm.count("input-file")) { std::string pathfile; pathfile = accumulate( diff --git a/tests/unit/frontend/CMakeLists.txt b/tests/unit/frontend/CMakeLists.txt index 6ea2e854e..031a818e8 100644 --- a/tests/unit/frontend/CMakeLists.txt +++ b/tests/unit/frontend/CMakeLists.txt @@ -25,3 +25,10 @@ add_executable(AnalysisModeTest AnalysisModeTest.cpp ) map2check_test(AnalysisModeTest) + +add_executable(CallerLinkTest + CallerLinkTest.cpp + $ + $ +) +map2check_test(CallerLinkTest) diff --git a/tests/unit/frontend/CallerLinkTest.cpp b/tests/unit/frontend/CallerLinkTest.cpp new file mode 100644 index 000000000..c45915f0c --- /dev/null +++ b/tests/unit/frontend/CallerLinkTest.cpp @@ -0,0 +1,312 @@ +/** + * Copyright (C) 2014 - 2026 Map2Check tool + * This file is part of the Map2Check tool, and is made available under + * the terms of the GNU General Public License version 2. + * + * SPDX-License-Identifier: (GPL-2.0) + **/ + +// How the frontend links the instrumented program with map2check-library +// (decision D1): the native libmap2check.a for AFL++ (route B1), the +// map2check-klee.bc bitcode for KLEE (route A'), and never a bitcode file of +// the old C runtime. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../../modules/frontend/caller.hpp" + +using Map2Check::Caller; +using Map2Check::DataStructure; +using Map2Check::Map2CheckMode; +using Map2Check::NonDetGenerator; +using Map2Check::buildFuzzerCommand; +using Map2Check::buildLinkCommand; + +namespace fs = std::filesystem; + +namespace { + +const Map2CheckMode kAllModes[] = { + Map2CheckMode::MEMTRACK_MODE, Map2CheckMode::MEMCLEANUP_MODE, + Map2CheckMode::OVERFLOW_MODE, Map2CheckMode::ASSERT_MODE, + Map2CheckMode::REACHABILITY_MODE, Map2CheckMode::COVER_BRANCHES_MODE}; + +const NonDetGenerator kAllGenerators[] = { + NonDetGenerator::None, NonDetGenerator::AFLPlusPlus, NonDetGenerator::Klee}; + +// Every bitcode file of the C runtime that linkLLVM used to pass to llvm-link. +const char* const kCRuntimeBitcode[] = { + "Map2CheckFunctions.bc", "TrackBBLog.bc", + "NonDetLog.bc", "PropertyGenerator.bc", + "ContainerRealloc.bc", "ContainerBTree.bc", + "BTree.bc", "AnalysisModeMemtrack.bc", + "AnalysisModeMemcleanup.bc", "AnalysisModeOverflow.bc", + "AnalysisModeAssert.bc", "AnalysisModeNone.bc", + "AllocationLog.bc", "ListLog.bc", + "HeapLog.bc", "NonDetGeneratorNone.bc", + "NonDetGeneratorKlee.bc", "NonDetGeneratorAFL.bc", + "WasmRuntimeStubs.bc", "WitnessGeneration.bc", + "WitnessGenerationNone.bc"}; + +size_t occurrences(const std::string& haystack, const std::string& needle) { + size_t count = 0; + for (size_t at = haystack.find(needle); at != std::string::npos; + at = haystack.find(needle, at + needle.size())) + ++count; + return count; +} + +bool contains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) != std::string::npos; +} + +// A fresh, empty directory under the system temp dir. +std::string freshDir(const std::string& tag) { + std::string pattern = + (fs::temp_directory_path() / ("callerlink-" + tag + "-XXXXXX")).string(); + std::vector buffer(pattern.begin(), pattern.end()); + buffer.push_back('\0'); + const char* made = mkdtemp(buffer.data()); + EXPECT_NE(made, nullptr); + return made != nullptr ? std::string(made) : std::string(); +} + +} // namespace + +TEST(CallerLink, LinksOnlyTheRustRuntime) { + Caller::LinkInputs in{"h", Map2CheckMode::MEMTRACK_MODE, + NonDetGenerator::AFLPlusPlus, DataStructure::Array, + /*wasm=*/false, /*witness=*/false}; + std::string link = buildLinkCommand(in); + EXPECT_FALSE(link.empty()); + EXPECT_EQ(link.find("${MAP2CHECK_PATH}/lib/"), std::string::npos) << link; + EXPECT_NE(buildFuzzerCommand(in).find("libmap2check.a"), std::string::npos); +} + +TEST(CallerLink, EveryModeAndGeneratorLinksRuntime) { + for (auto mode : kAllModes) + for (auto gen : {NonDetGenerator::AFLPlusPlus, NonDetGenerator::None}) + for (bool wasm : {false, true}) + for (bool witness : {false, true}) + for (bool cmplog : {false, true}) { + if (witness && cmplog) continue; // CmpLog is never a witness + Caller::LinkInputs in{"h", mode, gen, DataStructure::Array, + wasm, witness, cmplog}; + const std::string fuzz = buildFuzzerCommand(in); + EXPECT_TRUE(contains(fuzz, "${MAP2CHECK_PATH}/lib/libmap2check.a")) + << fuzz; + // The system libraries follow the archive that needs them. + EXPECT_TRUE(contains( + fuzz, "${MAP2CHECK_PATH}/lib/libmap2check.a -ldl -lpthread -lm")) + << fuzz; + EXPECT_TRUE(contains(fuzz, "-fsanitize=fuzzer")) << fuzz; + EXPECT_TRUE(contains(fuzz, " " + Map2Check::resultBitcode(in) + " ")) + << fuzz; + EXPECT_TRUE(contains(fuzz, " -o " + Map2Check::fuzzerBinary(in))) + << fuzz; + } +} + +TEST(CallerLink, NoCRuntimeBitcodeIsLinkedInAnyConfiguration) { + for (auto mode : kAllModes) + for (auto gen : kAllGenerators) + for (auto ds : {DataStructure::Array, DataStructure::BTree}) + for (bool wasm : {false, true}) + for (bool witness : {false, true}) { + Caller::LinkInputs in{"h", mode, gen, ds, wasm, witness}; + const std::string link = buildLinkCommand(in); + const std::string fuzz = buildFuzzerCommand(in); + for (const char* bc : kCRuntimeBitcode) { + EXPECT_FALSE(contains(link, bc)) << link; + EXPECT_FALSE(contains(fuzz, bc)) << fuzz; + } + // The one installed file a link may name is the KLEE runtime, + // and only for KLEE. + const size_t expected = gen == NonDetGenerator::Klee ? 1 : 0; + EXPECT_EQ(occurrences(link, "${MAP2CHECK_PATH}/lib/"), expected) + << link; + EXPECT_EQ(occurrences(link, Map2Check::kRustKleeRuntime), expected) + << link; + EXPECT_TRUE(contains(link, " h-output.bc")) << link; + EXPECT_TRUE(contains(link, " -o " + Map2Check::resultBitcode(in))) + << link; + } +} + +TEST(CallerLink, ResultAndBinaryNames) { + Caller::LinkInputs in{"h", Map2CheckMode::ASSERT_MODE, + NonDetGenerator::AFLPlusPlus, DataStructure::Array, + false, false}; + EXPECT_EQ(Map2Check::resultBitcode(in), "h-result.bc"); + EXPECT_EQ(Map2Check::fuzzerBinary(in), "h-fuzzed.out"); + in.witness = true; + EXPECT_EQ(Map2Check::resultBitcode(in), "h-witness-result.bc"); + EXPECT_EQ(Map2Check::fuzzerBinary(in), "h-witness-fuzzed.out"); + in.witness = false; + in.cmplog = true; + EXPECT_EQ(Map2Check::resultBitcode(in), "h-result.bc"); + EXPECT_EQ(Map2Check::fuzzerBinary(in), "h-cmplog.out"); +} + +TEST(CallerLink, FuzzerFlagsAreKeptAndCmplogIsAnEnvPrefix) { + Caller::LinkInputs in{"h", Map2CheckMode::OVERFLOW_MODE, + NonDetGenerator::AFLPlusPlus, DataStructure::Array, + false, false}; + const std::string fuzzed = buildFuzzerCommand(in); + EXPECT_TRUE(contains(fuzzed, " -g ")) << fuzzed; + EXPECT_TRUE(contains(fuzzed, " -O2 ")) << fuzzed; + EXPECT_FALSE(contains(fuzzed, "AFL_LLVM_CMPLOG")) << fuzzed; + + in.cmplog = true; + const std::string cmplog = buildFuzzerCommand(in); + // `env` so that the command can be run after `timeout`. + EXPECT_EQ(cmplog.rfind("env AFL_LLVM_CMPLOG=1 ", 0), 0u) << cmplog; + EXPECT_TRUE(contains(cmplog, " -O2 ")) << cmplog; + + in.cmplog = false; + in.witness = true; + const std::string witness = buildFuzzerCommand(in); + EXPECT_TRUE(contains(witness, " -g ")) << witness; + EXPECT_FALSE(contains(witness, "AFL_LLVM_CMPLOG")) << witness; +} + +TEST(CallerLink, WitnessConstructorIsLinkedOnlyIntoWitnessArtifacts) { + const std::string source = Map2Check::witnessConstructorSource(); + EXPECT_TRUE(contains(source, "__attribute__((constructor))")) << source; + EXPECT_TRUE(contains(source, "map2check_enable_witness();")) << source; + EXPECT_TRUE(contains(source, "void map2check_enable_witness(void);")) + << source; + + for (auto mode : kAllModes) + for (bool wasm : {false, true}) { + // AFL++: a native object in the witness fuzzer binary only. + Caller::LinkInputs afl{"h", mode, NonDetGenerator::AFLPlusPlus, + DataStructure::Array, wasm, true}; + const std::string object = Map2Check::witnessObjectPath(afl); + EXPECT_EQ(object, "h-witness.o"); + EXPECT_TRUE(contains(buildFuzzerCommand(afl), " " + object + " ")); + EXPECT_FALSE(contains(buildLinkCommand(afl), "h-witness.")); + afl.witness = false; + EXPECT_FALSE(contains(buildFuzzerCommand(afl), "h-witness.")); + afl.cmplog = true; + EXPECT_FALSE(contains(buildFuzzerCommand(afl), "h-witness.")); + + // KLEE: bitcode linked into the witness bitcode only. + Caller::LinkInputs klee{"h", mode, NonDetGenerator::Klee, + DataStructure::Array, wasm, true}; + const std::string bitcode = Map2Check::witnessObjectPath(klee); + EXPECT_EQ(bitcode, "h-witness.bc"); + EXPECT_TRUE(contains(buildLinkCommand(klee), " " + bitcode + " ")) + << buildLinkCommand(klee); + klee.witness = false; + EXPECT_FALSE(contains(buildLinkCommand(klee), "h-witness.")) + << buildLinkCommand(klee); + } +} + +TEST(CallerLink, WitnessObjectIsNativeForAflAndBitcodeForKlee) { + Caller::LinkInputs afl{"h", Map2CheckMode::MEMTRACK_MODE, + NonDetGenerator::AFLPlusPlus, DataStructure::Array, + false, true}; + Caller::LinkInputs klee = afl; + klee.generator = NonDetGenerator::Klee; + const std::string native = Map2Check::buildWitnessObjectCommand(afl); + const std::string bitcode = Map2Check::buildWitnessObjectCommand(klee); + for (const std::string& cmd : {native, bitcode}) { + EXPECT_TRUE(contains(cmd, " -c ")) << cmd; + EXPECT_TRUE(contains(cmd, " -fexceptions")) << cmd; + EXPECT_TRUE(contains(cmd, " h-witness.c")) << cmd; + } + EXPECT_FALSE(contains(native, "-emit-llvm")) << native; + EXPECT_TRUE(contains(native, " -o h-witness.o")) << native; + EXPECT_TRUE(contains(bitcode, " -emit-llvm")) << bitcode; + EXPECT_TRUE(contains(bitcode, " -o h-witness.bc")) << bitcode; + EXPECT_EQ(Map2Check::witnessSourcePath(afl), "h-witness.c"); +} + +TEST(CallerLink, KleeLinksTheKleeRuntimeBitcode) { + Caller::LinkInputs in{"h", Map2CheckMode::MEMTRACK_MODE, + NonDetGenerator::Klee, DataStructure::Array, false, + true}; + const std::string link = buildLinkCommand(in); + EXPECT_TRUE(contains(link, "llvm-link")) << link; + EXPECT_TRUE(contains(link, " ${MAP2CHECK_PATH}/lib/map2check-klee.bc")) + << link; + EXPECT_TRUE(contains(link, " -o h-witness-result.bc")) << link; + EXPECT_FALSE(contains(link, "libmap2check.a")) << link; +} + +TEST(CallerLink, ReplayPassesTheInputAsAnArgument) { + const std::string file = "afl-out/default/crashes/id:000000,sig:06,src:000000"; + const std::string replay = Map2Check::buildReplayCommand("h", file); + EXPECT_EQ(replay.find('<'), std::string::npos) << replay; + EXPECT_EQ(replay, "./h-witness-fuzzed.out '" + file + "'"); + // A quote in the name cannot break out of the argument. + EXPECT_EQ(Map2Check::buildReplayCommand("h", "a'b"), + "./h-witness-fuzzed.out 'a'\\''b'"); +} + +TEST(CallerLink, PlaceholderSeedHasAtLeastEightBytes) { + const std::string root = freshDir("seed"); + const std::string dir = root + "/afl-in"; // does not exist yet + ASSERT_TRUE(Map2Check::prepareAflInputDir(dir)); + std::vector seeds(fs::directory_iterator(dir), + fs::directory_iterator{}); + ASSERT_EQ(seeds.size(), 1u); + EXPECT_GE(fs::file_size(seeds[0]), Map2Check::kAflSeedMinBytes); + EXPECT_GE(Map2Check::kAflSeedMinBytes, 8u); + fs::remove_all(root); +} + +TEST(CallerLink, ExistingSeedsAreLeftUntouched) { + const std::string dir = freshDir("exchange"); + { + std::ofstream(dir + "/klee-0", std::ios::binary) << "AB"; + } + ASSERT_TRUE(Map2Check::prepareAflInputDir(dir)); + std::set names; + for (const auto& entry : fs::directory_iterator(dir)) + names.insert(entry.path().filename().string()); + EXPECT_EQ(names, std::set{"klee-0"}); + std::ifstream in(dir + "/klee-0", std::ios::binary); + std::string content((std::istreambuf_iterator(in)), + std::istreambuf_iterator()); + EXPECT_EQ(content, "AB"); + fs::remove_all(dir); +} + +TEST(CallerLink, KleeRuntimeIsLookedUpUnderMap2CheckPath) { + const std::string prefix = freshDir("prefix"); + ASSERT_EQ(setenv("MAP2CHECK_PATH", prefix.c_str(), 1), 0); + EXPECT_EQ(Map2Check::installedKleeRuntime(), + prefix + "/lib/map2check-klee.bc"); + EXPECT_FALSE(Map2Check::kleeRuntimeInstalled()); + fs::create_directories(prefix + "/lib"); + std::ofstream(prefix + "/lib/map2check-klee.bc") << "BC"; + EXPECT_TRUE(Map2Check::kleeRuntimeInstalled()); + fs::remove_all(prefix); +} + +TEST(CallerLink, BtreeIsIgnoredWithOneWarning) { + testing::internal::CaptureStdout(); + Map2Check::warnBtreeIgnored(); + const std::string out = testing::internal::GetCapturedStdout(); + EXPECT_EQ(occurrences(out, "--btree is ignored by the Rust runtime"), 1u) + << out; + for (auto gen : kAllGenerators) { + Caller::LinkInputs array{"h", Map2CheckMode::MEMTRACK_MODE, gen, + DataStructure::Array, false, true}; + Caller::LinkInputs btree = array; + btree.dataStructure = DataStructure::BTree; + EXPECT_EQ(buildLinkCommand(array), buildLinkCommand(btree)); + EXPECT_EQ(buildFuzzerCommand(array), buildFuzzerCommand(btree)); + } +} From 0ab2fbce021fdd9fbc703ba7ad4ffca8208f1d75 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 14:19:14 -0400 Subject: [PATCH 25/44] test: restore MAP2CHECK_PATH after the KLEE runtime lookup test Also include where caller_link.cpp calls getenv. --- modules/frontend/caller_link.cpp | 1 + tests/unit/frontend/CallerLinkTest.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/modules/frontend/caller_link.cpp b/modules/frontend/caller_link.cpp index d33652ece..f6b4008ed 100644 --- a/modules/frontend/caller_link.cpp +++ b/modules/frontend/caller_link.cpp @@ -24,6 +24,7 @@ // constructor that calls map2check_enable_witness (Step 4b), linked only into // the witness artefacts as WitnessGeneration.bc used to be. +#include #include #include #include diff --git a/tests/unit/frontend/CallerLinkTest.cpp b/tests/unit/frontend/CallerLinkTest.cpp index c45915f0c..ba6ef527e 100644 --- a/tests/unit/frontend/CallerLinkTest.cpp +++ b/tests/unit/frontend/CallerLinkTest.cpp @@ -284,6 +284,20 @@ TEST(CallerLink, ExistingSeedsAreLeftUntouched) { } TEST(CallerLink, KleeRuntimeIsLookedUpUnderMap2CheckPath) { + // Restores MAP2CHECK_PATH however the test ends. + struct RestoreEnv { + bool had; + std::string value; + ~RestoreEnv() { + if (had) + setenv("MAP2CHECK_PATH", value.c_str(), 1); + else + unsetenv("MAP2CHECK_PATH"); + } + }; + const char* previous = getenv("MAP2CHECK_PATH"); + RestoreEnv restore{previous != nullptr, + previous != nullptr ? previous : ""}; const std::string prefix = freshDir("prefix"); ASSERT_EQ(setenv("MAP2CHECK_PATH", prefix.c_str(), 1), 0); EXPECT_EQ(Map2Check::installedKleeRuntime(), From 7cc8ac7ae656d0d4f54368ce8b971ed72899160b Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 16:18:52 -0400 Subject: [PATCH 26/44] test: add differential gate comparing C and Rust runtime baselines --- scripts/cutover/compare.py | 80 ++++++++++++++++++++++++++++++++ scripts/cutover/test_compare.py | 41 ++++++++++++++++ tests/cutover/deltas-aceitos.tsv | 1 + 3 files changed, 122 insertions(+) create mode 100644 scripts/cutover/compare.py create mode 100644 scripts/cutover/test_compare.py create mode 100644 tests/cutover/deltas-aceitos.tsv diff --git a/scripts/cutover/compare.py b/scripts/cutover/compare.py new file mode 100644 index 000000000..78c779974 --- /dev/null +++ b/scripts/cutover/compare.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +"""Gate diferencial do cutover: compara as linhas de base C e Rust (critérios 1-8).""" +import argparse, csv, statistics, sys +from collections import Counter, defaultdict + +KEY = ("task", "prp", "gen") +FIELDS = ("verdict", "tag", "line", "function", "witness") + + +def load(path): + groups = defaultdict(list) + with open(path, newline="") as f: + for row in csv.DictReader(f, delimiter="\t"): + groups[tuple(row[k] for k in KEY)].append(row) + return groups + + +def mode(rows, field): + return Counter(r[field] for r in rows).most_common(1)[0][0] + + +def median_num(rows, field): + vals = [float(r[field]) for r in rows if r[field] not in ("-", "")] + return statistics.median(vals) if vals else None + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("c"); ap.add_argument("rust") + ap.add_argument("--accepted", required=True) + ap.add_argument("--max-wall", type=float, default=1.10) + ap.add_argument("--max-rss", type=float, default=1.25) + a = ap.parse_args() + c, r = load(a.c), load(a.rust) + accepted = set() + with open(a.accepted, newline="") as f: + for row in csv.DictReader(f, delimiter="\t"): + accepted.add((row["task"], row["prp"], row["gen"], row["field"], row["c_value"], row["rust_value"])) + + failures, wall_ratios, rss_ratios = [], [], [] + timeouts = Counter() + for key in sorted(set(c) | set(r)): + if key not in r or key not in c: + failures.append(f"| {' '.join(key)} | missing | {key in c} | {key in r} |") + continue + for field in FIELDS: + cv, rv = mode(c[key], field), mode(r[key], field) + if cv != rv and (*key, field, cv, rv) not in accepted: + failures.append(f"| {' '.join(key)} | {field} | {cv} | {rv} |") + for side, rows in (("c", c[key]), ("rust", r[key])): + if mode(rows, "verdict") == "TIMEOUT": + timeouts[(key[2], side)] += 1 + cw, rw = median_num(c[key], "wall_s"), median_num(r[key], "wall_s") + if cw and rw: + wall_ratios.append(rw / cw) + cm, rm = median_num(c[key], "maxrss_kb"), median_num(r[key], "maxrss_kb") + if cm and rm: + rss_ratios.append(rm / cm) + + for gen in {k[2] for k in c}: + if timeouts[(gen, "rust")] > timeouts[(gen, "c")]: + failures.append(f"| gen={gen} | TIMEOUT count | {timeouts[(gen, 'c')]} | {timeouts[(gen, 'rust')]} |") + wall = statistics.median(wall_ratios) if wall_ratios else 1.0 + rss = statistics.median(rss_ratios) if rss_ratios else 1.0 + if wall > a.max_wall: + failures.append(f"| all | median wall ratio | <= {a.max_wall} | {wall:.3f} |") + if rss > a.max_rss: + failures.append(f"| all | median rss ratio | <= {a.max_rss} | {rss:.3f} |") + + print(f"median wall ratio: {wall:.3f} median rss ratio: {rss:.3f}\n") + if failures: + print("| key | field | c | rust |\n|---|---|---|---|") + print("\n".join(failures)) + return 1 + print("gate: PASS") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/cutover/test_compare.py b/scripts/cutover/test_compare.py new file mode 100644 index 000000000..5cba19c0a --- /dev/null +++ b/scripts/cutover/test_compare.py @@ -0,0 +1,41 @@ +# Testes do comparador do gate de cutover. +import subprocess, sys, textwrap, pathlib, tempfile + +HERE = pathlib.Path(__file__).parent +HDR = "task\tprp\tgen\trep\tverdict\ttag\tline\tfunction\twitness\twall_s\tmaxrss_kb\n" + +def run(c_rows, r_rows, accepted=""): + d = pathlib.Path(tempfile.mkdtemp()) + (d / "c.tsv").write_text(HDR + "".join(c_rows)) + (d / "r.tsv").write_text(HDR + "".join(r_rows)) + (d / "a.tsv").write_text("task\tprp\tgen\tfield\tc_value\trust_value\tsd_ref\n" + accepted) + return subprocess.run([sys.executable, HERE / "compare.py", d / "c.tsv", d / "r.tsv", + "--accepted", d / "a.tsv"], capture_output=True, text=True) + +ROW = "t.yml\tvalid-memsafety\tafl\t{rep}\t{v}\t{tag}\t7\tmain\t0\t{wall}\t1000\n" + +def rows(v="FAILED", tag="FALSE-DEREF", wall=1.0): + return [ROW.format(rep=i, v=v, tag=tag, wall=wall) for i in range(1, 6)] + +def test_identical_passes(): + assert run(rows(), rows()).returncode == 0 + +def test_verdict_change_blocks(): + p = run(rows(), rows(v="UNKNOWN", tag="-")) + assert p.returncode == 1 and "verdict" in p.stdout + +def test_accepted_delta_passes(): + acc = "t.yml\tvalid-memsafety\tafl\ttag\tFALSE-DEREF\tFALSE-FREE\tSD-06\n" + assert run(rows(), rows(tag="FALSE-FREE"), acc).returncode == 0 + +def test_slowdown_over_10_percent_blocks(): + p = run(rows(wall=1.0), rows(wall=1.2)) + assert p.returncode == 1 and "wall" in p.stdout + +def test_new_timeout_blocks(): + p = run(rows(), rows(v="TIMEOUT", tag="-")) + assert p.returncode == 1 and "TIMEOUT" in p.stdout + +def test_missing_task_blocks(): + p = run(rows(), []) + assert p.returncode == 1 and "missing" in p.stdout diff --git a/tests/cutover/deltas-aceitos.tsv b/tests/cutover/deltas-aceitos.tsv new file mode 100644 index 000000000..1a3be47f8 --- /dev/null +++ b/tests/cutover/deltas-aceitos.tsv @@ -0,0 +1 @@ +task prp gen field c_value rust_value sd_ref From 8cf38ce9807ab6f83c682a44e584f85a716cd25d Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 16:24:34 -0400 Subject: [PATCH 27/44] test: let the corpus runner append EXTRA_FLAGS to the map2check flags Task 4.3 measures the C runtime with --btree. EXTRA_FLAGS is appended to the per-property flags; unset, the command line is unchanged. --- scripts/cutover/run-corpus.sh | 3 +++ scripts/cutover/test-run-corpus.sh | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/scripts/cutover/run-corpus.sh b/scripts/cutover/run-corpus.sh index 487db1e75..0cf88ffbe 100755 --- a/scripts/cutover/run-corpus.sh +++ b/scripts/cutover/run-corpus.sh @@ -7,6 +7,8 @@ BIN_DIR="$(cd "$1" && pwd)"; OUT="$2" ROOT="$(cd "$(dirname "$0")/../.." && pwd)" CASES="${CASES:-$ROOT/tests/regression_test/test_cases/sv-benchmarks}" GENS="${GENS:-afl symex}"; REPS="${REPS:-5}"; TIMEOUT="${TIMEOUT:-45}" +# EXTRA_FLAGS: flags acrescentadas às da propriedade (ex.: --btree, Task 4.3). +EXTRA_FLAGS="${EXTRA_FLAGS:-}" flags_for() { case "$1" in @@ -24,6 +26,7 @@ while IFS= read -r yml; do input="$dir/$(sed -nE "s/^input_files: *'?([^' ]+)'?.*/\1/p" "$yml")" while IFS= read -r prp; do flags="$(flags_for "$prp")" || continue + flags="$flags${EXTRA_FLAGS:+ $EXTRA_FLAGS}" for gen in $GENS; do for rep in $(seq 1 "$REPS"); do work="$(mktemp -d)" diff --git a/scripts/cutover/test-run-corpus.sh b/scripts/cutover/test-run-corpus.sh index 7946b0c87..e89a83fc4 100755 --- a/scripts/cutover/test-run-corpus.sh +++ b/scripts/cutover/test-run-corpus.sh @@ -102,4 +102,17 @@ echo "VERIFICATION UNKNOWN" EOS check_rust "violacao com veredito UNKNOWN" UNKNOWN - - - +# EXTRA_FLAGS e acrescentada as flags da propriedade (Task 4.3: --btree). +cat > "$T/cbin/map2check" < "$T/args" +echo "VERIFICATION UNKNOWN" +EOS +CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/x.tsv" +grep -q -- '--memtrack .*b.c$' "$T/args" && ! grep -q -- '--btree' "$T/args" \ + || { echo "sem EXTRA_FLAGS: args inesperados: $(cat "$T/args")" >&2; exit 1; } +EXTRA_FLAGS="--btree" CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/x.tsv" +grep -q -- '--memtrack --btree .*b.c$' "$T/args" \ + || { echo "EXTRA_FLAGS nao repassado: $(cat "$T/args")" >&2; exit 1; } + echo ok From 20e0572b0700039ca67e7356728f47f6665445ff Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 19:05:49 -0400 Subject: [PATCH 28/44] test: record an OOM kill in the container's cgroup as verdict OOM The gate runs each side under a container memory cap. A new oom_kill in memory.events during a task without a decided verdict is written as OOM; a decided verdict is kept and the kill is reported on stderr. --- scripts/cutover/run-corpus.sh | 13 +++++++++++++ scripts/cutover/test-run-corpus.sh | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/scripts/cutover/run-corpus.sh b/scripts/cutover/run-corpus.sh index 0cf88ffbe..fb2228a9b 100755 --- a/scripts/cutover/run-corpus.sh +++ b/scripts/cutover/run-corpus.sh @@ -9,6 +9,10 @@ CASES="${CASES:-$ROOT/tests/regression_test/test_cases/sv-benchmarks}" GENS="${GENS:-afl symex}"; REPS="${REPS:-5}"; TIMEOUT="${TIMEOUT:-45}" # EXTRA_FLAGS: flags acrescentadas às da propriedade (ex.: --btree, Task 4.3). EXTRA_FLAGS="${EXTRA_FLAGS:-}" +# OOM_EVENTS: memory.events do cgroup (default: o do container, se legível). +# Um oom_kill novo durante uma tarefa sem veredito decidido grava veredito OOM. +OOM_EVENTS="${OOM_EVENTS:-/sys/fs/cgroup/memory.events}" +oom_kills() { sed -nE 's/^oom_kill ([0-9]+)$/\1/p' "$OOM_EVENTS" 2>/dev/null || true; } flags_for() { case "$1" in @@ -30,6 +34,7 @@ while IFS= read -r yml; do for gen in $GENS; do for rep in $(seq 1 "$REPS"); do work="$(mktemp -d)" + oom_before="$(oom_kills)" # shellcheck disable=SC2086 ( cd "$work" && /usr/bin/time -f '%e\t%M' -o time.txt \ timeout "$((TIMEOUT + 15))" "$BIN_DIR/map2check" --timeout "$TIMEOUT" --nondet-generator "$gen" $flags "$input" \ @@ -38,6 +43,14 @@ while IFS= read -r yml; do grep -q 'VERIFICATION SUCCEEDED' "$work/out.txt" && verdict=SUCCEEDED grep -q 'VERIFICATION FAILED' "$work/out.txt" && verdict=FAILED grep -q 'VERIFICATION UNKNOWN' "$work/out.txt" && verdict=UNKNOWN + oom_after="$(oom_kills)" + if [ -n "$oom_before" ] && [ -n "$oom_after" ] && [ "$oom_after" -gt "$oom_before" ]; then + case "$verdict" in + SUCCEEDED|FAILED) + echo "run-corpus: oom_kill during ${yml#"$CASES"/} ($prp, $gen, rep $rep), verdict $verdict kept" >&2 ;; + *) verdict=OOM ;; + esac + fi tag=-; line=-; func=- # tag/line/function are only meaningful for a FAILED verdict; every other # verdict gets "-" whichever source (property file or stdout) was used. diff --git a/scripts/cutover/test-run-corpus.sh b/scripts/cutover/test-run-corpus.sh index e89a83fc4..f21f1ff16 100755 --- a/scripts/cutover/test-run-corpus.sh +++ b/scripts/cutover/test-run-corpus.sh @@ -115,4 +115,29 @@ EXTRA_FLAGS="--btree" CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" " grep -q -- '--memtrack --btree .*b.c$' "$T/args" \ || { echo "EXTRA_FLAGS nao repassado: $(cat "$T/args")" >&2; exit 1; } +# OOM_EVENTS: um oom_kill novo no cgroup durante a tarefa vira veredito OOM, +# a menos que a tarefa tenha decidido (SUCCEEDED/FAILED); nesse caso so avisa. +printf 'oom 0\noom_kill 0\n' > "$T/events" +cat > "$T/cbin/map2check" < "$T/events" +echo "VERIFICATION UNKNOWN" +EOS +OOM_EVENTS="$T/events" CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/o.tsv" +[ "$(cut -f5 <(sed -n 2p "$T/o.tsv"))" = OOM ] || { echo "OOM nao registrado: $(sed -n 2p "$T/o.tsv")" >&2; exit 1; } +cat > "$T/cbin/map2check" < "$T/events" +echo "VERIFICATION FAILED" +EOS +OOM_EVENTS="$T/events" CASES="$T/cases" GENS=symex REPS=1 "$HERE/run-corpus.sh" "$T/cbin" "$T/o.tsv" 2>"$T/err" +[ "$(cut -f5 <(sed -n 2p "$T/o.tsv"))" = FAILED ] && grep -q 'oom_kill' "$T/err" \ + || { echo "OOM com veredito decidido: $(sed -n 2p "$T/o.tsv")" >&2; exit 1; } +cat > "$T/cbin/map2check" <&2; exit 1; } + echo ok From 815e1b5bda08dbe7d9dd44457c589c9ec8fab33c Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 21:37:29 -0400 Subject: [PATCH 29/44] test: record the first differential gate run of the Rust runtime Rust (lib 44585e8) and C (f01e8c3e) baselines, GENS="afl symex" REPS=5, the C --btree run on valid-memsafety (REPS=3), both sides capped at 3 GiB / 4 CPUs with KLEE --max-memory=2000. The gate fails: three C defects (property-file race under KLEE, afl OOM) and the median RSS ratio of 1.36. Proposed accepted deltas cover only budget gains and the list-ext benchmark UB. --- tests/cutover/baseline-c-btree.tsv | 181 ++++++++++ tests/cutover/baseline-c-gate.tsv | 411 ++++++++++++++++++++++ tests/cutover/baseline-rust.tsv | 411 ++++++++++++++++++++++ tests/cutover/deltas-aceitos-PROPOSTA.tsv | 7 + tests/cutover/gate-report.md | 194 ++++++++++ 5 files changed, 1204 insertions(+) create mode 100644 tests/cutover/baseline-c-btree.tsv create mode 100644 tests/cutover/baseline-c-gate.tsv create mode 100644 tests/cutover/baseline-rust.tsv create mode 100644 tests/cutover/deltas-aceitos-PROPOSTA.tsv create mode 100644 tests/cutover/gate-report.md diff --git a/tests/cutover/baseline-c-btree.tsv b/tests/cutover/baseline-c-btree.tsv new file mode 100644 index 000000000..4103253bd --- /dev/null +++ b/tests/cutover/baseline-c-btree.tsv @@ -0,0 +1,181 @@ +task prp gen rep verdict tag line function witness wall_s maxrss_kb +array-examples/relax-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.66 94028 +array-examples/relax-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.67 94276 +array-examples/relax-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.68 94464 +array-examples/relax-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 5.05 151024 +array-examples/relax-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 4.86 151212 +array-examples/relax-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 4.81 151940 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.61 93844 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.63 93684 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.62 93980 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 1 FAILED FALSE-DEREF 522 main 0 0.88 135984 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 2 FAILED FALSE-DEREF 522 main 0 0.85 135988 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 3 FAILED FALSE-DEREF 522 main 0 0.83 136532 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.50 93584 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.51 94620 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.50 93748 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.48 137308 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.50 137420 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.51 136764 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.78 94032 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.87 94588 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.94 93712 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.90 137380 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.92 137456 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 2.14 137968 +array-memsafety/lis_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.52 94760 +array-memsafety/lis_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.50 94292 +array-memsafety/lis_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.50 93944 +array-memsafety/lis_unsafe.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.42 140276 +array-memsafety/lis_unsafe.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.25 140644 +array-memsafety/lis_unsafe.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.56 140188 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.64 205516 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.61 340940 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.83 204952 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.18 129500 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.07 129940 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.69 129592 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 1 FAILED FALSE-FREE 46 main 0 0.62 94500 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 2 FAILED FALSE-FREE 46 main 0 0.62 94624 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 3 FAILED FALSE-FREE 46 main 0 0.62 94168 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 1 FAILED FALSE-FREE 46 main 0 0.74 129720 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 2 FAILED FALSE-FREE 46 main 0 0.76 129972 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 3 FAILED FALSE-FREE 46 main 0 0.76 129676 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.56 340864 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.72 341052 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.68 341320 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 0.70 128600 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 0.62 128484 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 0.64 128692 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.52 94096 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.48 93980 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.51 93792 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.38 131888 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.40 132316 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.38 132288 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.50 93932 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.51 93756 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.57 94168 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.38 135204 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.38 134652 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.37 134280 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.76 95088 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.76 96360 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.74 96088 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 9.51 148912 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 9.39 151300 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 9.10 149928 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.67 504616 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.66 502504 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.66 505584 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 10.85 151868 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 10.90 151928 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 10.89 151496 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 779 free_17 0 0.76 96048 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 779 free_17 0 0.77 95884 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 779 free_17 0 0.76 95688 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 11.28 153372 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 12.22 152352 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 11.87 154652 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.69 341200 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.86 564400 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.72 599088 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 9.61 149164 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 9.42 149596 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 9.55 149460 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.71 203072 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.74 203032 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.82 340976 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.69 127444 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.58 126740 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.58 127948 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 1 FAILED FALSE-DEREF 533 main 0 0.63 93344 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 2 FAILED FALSE-DEREF 533 main 0 0.63 93460 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 3 FAILED FALSE-DEREF 533 main 0 0.62 93272 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 533 main 0 1.34 136524 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 533 main 0 1.39 136252 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 533 main 0 1.41 137196 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.50 248396 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.53 93924 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.51 340760 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.49 136900 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.49 136604 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.50 136616 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 1 FAILED FALSE-FREE 536 main 0 0.67 93888 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 2 FAILED FALSE-FREE 536 main 0 0.67 93400 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 3 FAILED FALSE-FREE 536 main 0 0.63 93960 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 1 FAILED FALSE-FREE 536 main 0 1.56 136760 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 2 FAILED FALSE-FREE 536 main 0 1.37 136480 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 3 FAILED FALSE-FREE 536 main 0 1.35 136820 +list-ext-properties/list-ext.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.57 94800 +list-ext-properties/list-ext.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.57 94132 +list-ext-properties/list-ext.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.67 94232 +list-ext-properties/list-ext.yml valid-memsafety symex 1 UNKNOWN - - - 0 0.81 135896 +list-ext-properties/list-ext.yml valid-memsafety symex 2 UNKNOWN - - - 0 0.81 135764 +list-ext-properties/list-ext.yml valid-memsafety symex 3 UNKNOWN - - - 0 0.82 136324 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.64 93480 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.64 93636 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.64 93128 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 1.02 129200 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 1.08 129368 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 1.11 129284 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.71 340804 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.69 341112 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.69 341008 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.66 135388 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.67 134644 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.67 135916 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.48 93840 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.51 93668 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.50 93040 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 2.65 137392 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 2.81 138172 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 2.70 138684 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.50 93296 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.47 94548 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.49 94420 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.00 135380 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.99 136456 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.00 135480 +memsafety-ext/tree_stack.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.50 94676 +memsafety-ext/tree_stack.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.49 94200 +memsafety-ext/tree_stack.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.49 94740 +memsafety-ext/tree_stack.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.22 135996 +memsafety-ext/tree_stack.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.24 135948 +memsafety-ext/tree_stack.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.23 136464 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.51 94684 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.51 93604 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.50 93900 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 5.93 140388 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 5.83 140352 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 5.98 140724 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.53 94128 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.53 94312 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.59 94392 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 540 containsHead 0 16.53 149040 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 540 containsHead 0 15.06 149456 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 540 containsHead 0 14.90 148368 +memsafety/960521-1-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 532 main 0 0.64 93124 +memsafety/960521-1-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 532 main 0 0.62 93464 +memsafety/960521-1-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 532 main 0 0.62 93376 +memsafety/960521-1-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 532 main 0 3.00 129636 +memsafety/960521-1-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 532 main 0 2.93 129792 +memsafety/960521-1-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 532 main 0 3.00 129692 +memsafety/960521-1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.47 93436 +memsafety/960521-1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.50 93632 +memsafety/960521-1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.48 93812 +memsafety/960521-1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.39 129252 +memsafety/960521-1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.37 129408 +memsafety/960521-1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.38 129236 +memsafety/960521-1-3.yml valid-memsafety afl 1 FAILED FALSE-DEREF 529 main 0 0.66 94096 +memsafety/960521-1-3.yml valid-memsafety afl 2 FAILED FALSE-DEREF 529 main 0 0.62 94524 +memsafety/960521-1-3.yml valid-memsafety afl 3 FAILED FALSE-DEREF 529 main 0 0.61 93488 +memsafety/960521-1-3.yml valid-memsafety symex 1 FAILED FALSE-DEREF 529 main 0 2.84 130380 +memsafety/960521-1-3.yml valid-memsafety symex 2 FAILED FALSE-DEREF 529 main 0 4.09 130472 +memsafety/960521-1-3.yml valid-memsafety symex 3 FAILED FALSE-DEREF 529 main 0 2.92 129756 +memsafety/test-0102-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.51 93460 +memsafety/test-0102-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.52 93852 +memsafety/test-0102-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.52 94020 +memsafety/test-0102-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 8.12 147332 +memsafety/test-0102-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 8.38 147724 +memsafety/test-0102-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 8.05 147192 diff --git a/tests/cutover/baseline-c-gate.tsv b/tests/cutover/baseline-c-gate.tsv new file mode 100644 index 000000000..4e3c4f213 --- /dev/null +++ b/tests/cutover/baseline-c-gate.tsv @@ -0,0 +1,411 @@ +task prp gen rep verdict tag line function witness wall_s maxrss_kb +array-examples/relax-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.62 93548 +array-examples/relax-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.60 92988 +array-examples/relax-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.62 94232 +array-examples/relax-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.63 93936 +array-examples/relax-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.61 94060 +array-examples/relax-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.87 178072 +array-examples/relax-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.49 178260 +array-examples/relax-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.81 169348 +array-examples/relax-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.77 178284 +array-examples/relax-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 8.65 170724 +array-examples/standard_sentinel-2.yml unreach-call afl 1 OOM - - - 0 9.35 91344 +array-examples/standard_sentinel-2.yml unreach-call afl 2 OOM - - - 0 9.56 3109896 +array-examples/standard_sentinel-2.yml unreach-call afl 3 OOM - - - 0 9.56 3110004 +array-examples/standard_sentinel-2.yml unreach-call afl 4 OOM - - - 0 9.54 3109884 +array-examples/standard_sentinel-2.yml unreach-call afl 5 OOM - - - 0 9.55 3109764 +array-examples/standard_sentinel-2.yml unreach-call symex 1 UNKNOWN - - - 0 31.49 182596 +array-examples/standard_sentinel-2.yml unreach-call symex 2 UNKNOWN - - - 0 31.39 174880 +array-examples/standard_sentinel-2.yml unreach-call symex 3 UNKNOWN - - - 0 31.39 163520 +array-examples/standard_sentinel-2.yml unreach-call symex 4 UNKNOWN - - - 0 31.39 168008 +array-examples/standard_sentinel-2.yml unreach-call symex 5 UNKNOWN - - - 0 31.40 174872 +array-examples/standard_two_index_04.yml unreach-call afl 1 OOM - - - 0 9.44 3109996 +array-examples/standard_two_index_04.yml unreach-call afl 2 OOM - - - 0 9.53 3110004 +array-examples/standard_two_index_04.yml unreach-call afl 3 OOM - - - 0 9.55 3109976 +array-examples/standard_two_index_04.yml unreach-call afl 4 OOM - - - 0 9.54 3109928 +array-examples/standard_two_index_04.yml unreach-call afl 5 OOM - - - 0 9.54 3109880 +array-examples/standard_two_index_04.yml unreach-call symex 1 UNKNOWN - - - 0 31.49 163392 +array-examples/standard_two_index_04.yml unreach-call symex 2 UNKNOWN - - - 0 31.41 163480 +array-examples/standard_two_index_04.yml unreach-call symex 3 UNKNOWN - - - 0 31.43 163496 +array-examples/standard_two_index_04.yml unreach-call symex 4 UNKNOWN - - - 0 31.40 157648 +array-examples/standard_two_index_04.yml unreach-call symex 5 UNKNOWN - - - 0 31.38 163392 +array-examples/standard_two_index_05.yml unreach-call afl 1 OOM - - - 0 9.44 3109820 +array-examples/standard_two_index_05.yml unreach-call afl 2 OOM - - - 0 9.46 3109924 +array-examples/standard_two_index_05.yml unreach-call afl 3 OOM - - - 0 9.53 3110076 +array-examples/standard_two_index_05.yml unreach-call afl 4 OOM - - - 0 9.54 3109740 +array-examples/standard_two_index_05.yml unreach-call afl 5 OOM - - - 0 9.54 3110184 +array-examples/standard_two_index_05.yml unreach-call symex 1 UNKNOWN - - - 0 31.48 160664 +array-examples/standard_two_index_05.yml unreach-call symex 2 UNKNOWN - - - 0 31.40 164436 +array-examples/standard_two_index_05.yml unreach-call symex 3 UNKNOWN - - - 0 31.40 166168 +array-examples/standard_two_index_05.yml unreach-call symex 4 UNKNOWN - - - 0 31.39 162624 +array-examples/standard_two_index_05.yml unreach-call symex 5 UNKNOWN - - - 0 31.42 164244 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.60 92676 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.60 93308 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.60 92832 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.58 93116 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.59 92940 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 1 FAILED FALSE-DEREF 522 main 0 5.64 169036 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 2 FAILED FALSE-DEREF 522 main 0 5.68 168620 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 3 FAILED FALSE-DEREF 522 main 0 5.55 169224 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 4 FAILED FALSE-DEREF 522 main 0 5.49 169676 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 5 FAILED FALSE-DEREF 522 main 0 5.41 169376 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 92872 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 93412 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.45 93192 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.45 93032 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.44 92816 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.47 168720 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.44 169248 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.49 168676 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.47 168748 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.62 168560 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.92 94012 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.84 93680 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.84 93892 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.83 93100 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.37 92724 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.63 143584 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.64 143772 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.76 143736 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.72 143520 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.65 144156 +array-memsafety/lis_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.55 93252 +array-memsafety/lis_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.52 93384 +array-memsafety/lis_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.53 93256 +array-memsafety/lis_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.57 94140 +array-memsafety/lis_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.56 93180 +array-memsafety/lis_unsafe.yml valid-memsafety symex 1 UNKNOWN - - - 0 4.78 169964 +array-memsafety/lis_unsafe.yml valid-memsafety symex 2 UNKNOWN - - - 0 4.57 169788 +array-memsafety/lis_unsafe.yml valid-memsafety symex 3 UNKNOWN - - - 0 4.45 169968 +array-memsafety/lis_unsafe.yml valid-memsafety symex 4 UNKNOWN - - - 0 4.43 166412 +array-memsafety/lis_unsafe.yml valid-memsafety symex 5 UNKNOWN - - - 0 4.34 170164 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 93744 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 93532 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.42 93928 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.42 93724 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 341056 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.42 127512 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.41 127272 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.41 127776 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 0.44 127632 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 0.42 126844 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 1 FAILED FALSE-FREE 46 main 0 0.58 93868 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 2 FAILED FALSE-FREE 46 main 0 0.57 93488 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 3 FAILED FALSE-FREE 46 main 0 0.57 93664 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 4 FAILED FALSE-FREE 46 main 0 0.59 93752 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 5 FAILED FALSE-FREE 46 main 0 0.58 93656 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 1 FAILED FALSE-FREE 46 main 0 0.47 127672 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 2 FAILED FALSE-FREE 46 main 0 0.44 128036 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 3 FAILED FALSE-FREE 46 main 0 0.47 127452 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 4 FAILED FALSE-FREE 46 main 0 0.46 127384 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 5 FAILED FALSE-FREE 46 main 0 0.48 128080 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.43 92840 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.42 93808 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 93476 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341052 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 341016 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 0.35 127312 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 0.35 127892 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 0.35 127328 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 0.35 127556 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 0.34 126884 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 93088 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 93716 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 93344 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.43 93356 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.43 93260 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.34 128060 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.35 127760 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.35 127536 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.37 127364 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.34 127404 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.46 94016 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.45 93452 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 93644 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.45 93068 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.50 93196 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.35 128688 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.36 128228 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.36 128928 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.36 127920 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.35 127980 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.95 94860 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.87 94400 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.87 94524 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.92 95508 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.91 95392 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 9.42 167880 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 8.68 176792 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 8.55 168092 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 8.67 170500 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 8.74 170592 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.68 570412 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.63 569388 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.67 572588 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.66 341176 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.59 570660 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 14.30 140600 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 14.28 140612 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 13.96 141028 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 13.85 140792 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 13.57 140380 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 779 free_17 0 0.71 95220 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 779 free_17 0 0.70 95932 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 779 free_17 0 0.71 94852 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 779 free_17 0 0.72 95148 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 779 free_17 0 0.72 94740 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 779 free_17 0 28.40 181260 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 779 free_17 0 27.83 180924 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 779 free_17 0 27.21 180948 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 779 free_17 0 27.67 181244 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 779 free_17 0 28.56 181132 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.58 465496 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.56 465576 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.55 341196 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.56 465496 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.58 465320 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 4.55 139080 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 4.31 138276 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 4.56 138640 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 4.48 138520 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 4.53 138472 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.41 92696 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.41 92780 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.41 92696 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.48 341116 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.41 92896 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.37 126964 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.37 127436 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.37 127304 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 4 SUCCEEDED - - - 0 0.36 126988 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 5 SUCCEEDED - - - 0 0.36 127132 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 1 FAILED FALSE-DEREF 533 main 0 0.56 93000 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 2 FAILED FALSE-DEREF 533 main 0 0.57 93860 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 3 FAILED FALSE-DEREF 533 main 0 0.58 93136 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 4 FAILED FALSE-DEREF 533 main 0 0.59 93180 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 5 FAILED FALSE-DEREF 533 main 0 0.57 93152 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 0 - 0 1.59 136344 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 0 - 0 1.55 135884 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 0 - 0 1.51 136556 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 0 - 0 1.63 136048 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 0 - 0 1.59 136300 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.48 341372 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.47 341216 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.47 341308 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341328 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.68 341328 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 14.25 136880 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 14.97 138908 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 14.65 136620 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 14.75 136404 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 14.70 136312 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 1 FAILED FALSE-FREE 536 main 0 0.58 92968 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 2 FAILED FALSE-FREE 536 main 0 0.56 93076 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 3 FAILED FALSE-FREE 536 main 0 0.57 93128 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 4 FAILED FALSE-FREE 536 main 0 0.58 93068 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 5 FAILED FALSE-FREE 536 main 0 0.56 93504 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 1 FAILED FALSE-FREE 536 main 0 1.73 136572 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 2 FAILED FALSE-FREE 536 main 0 1.65 136576 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 3 FAILED FALSE-FREE 536 main 0 1.63 136340 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 4 FAILED FALSE-FREE 536 main 0 1.71 136036 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 5 FAILED FALSE-FREE 536 main 0 1.82 136576 +list-ext-properties/list-ext.yml unreach-call afl 1 UNKNOWN - - - 0 0.50 92148 +list-ext-properties/list-ext.yml unreach-call afl 2 UNKNOWN - - - 0 0.51 92508 +list-ext-properties/list-ext.yml unreach-call afl 3 UNKNOWN - - - 0 0.48 92380 +list-ext-properties/list-ext.yml unreach-call afl 4 UNKNOWN - - - 0 0.48 91896 +list-ext-properties/list-ext.yml unreach-call afl 5 UNKNOWN - - - 0 0.50 92408 +list-ext-properties/list-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 556 main 0 4.53 172304 +list-ext-properties/list-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 556 main 0 3.76 172588 +list-ext-properties/list-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 556 main 0 3.77 172072 +list-ext-properties/list-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 556 main 0 3.81 174084 +list-ext-properties/list-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 556 main 0 3.77 172032 +list-ext-properties/list-ext.yml valid-memsafety afl 1 FAILED FALSE-DEREF 558 main 0 0.59 93608 +list-ext-properties/list-ext.yml valid-memsafety afl 2 FAILED FALSE-DEREF 558 main 0 0.58 93068 +list-ext-properties/list-ext.yml valid-memsafety afl 3 FAILED FALSE-DEREF 558 main 0 0.71 93512 +list-ext-properties/list-ext.yml valid-memsafety afl 4 FAILED FALSE-DEREF 558 main 0 0.64 93300 +list-ext-properties/list-ext.yml valid-memsafety afl 5 FAILED FALSE-DEREF 558 main 0 0.58 93676 +list-ext-properties/list-ext.yml valid-memsafety symex 1 FAILED FALSE-DEREF 558 main 0 32.08 234924 +list-ext-properties/list-ext.yml valid-memsafety symex 2 FAILED FALSE-DEREF 558 main 0 32.18 233880 +list-ext-properties/list-ext.yml valid-memsafety symex 3 FAILED FALSE-DEREF 558 main 0 32.18 232444 +list-ext-properties/list-ext.yml valid-memsafety symex 4 FAILED FALSE-DEREF 558 main 0 32.02 231460 +list-ext-properties/list-ext.yml valid-memsafety symex 5 FAILED FALSE-DEREF 558 main 0 32.27 244472 +list-ext-properties/simple-ext.yml unreach-call afl 1 FAILED TARGET-REACHED 540 main 0 0.50 91776 +list-ext-properties/simple-ext.yml unreach-call afl 2 FAILED TARGET-REACHED 540 main 0 0.48 91888 +list-ext-properties/simple-ext.yml unreach-call afl 3 FAILED TARGET-REACHED 540 main 0 0.51 92072 +list-ext-properties/simple-ext.yml unreach-call afl 4 FAILED TARGET-REACHED 540 main 0 0.48 92312 +list-ext-properties/simple-ext.yml unreach-call afl 5 FAILED TARGET-REACHED 540 main 0 0.50 91540 +list-ext-properties/simple-ext.yml unreach-call symex 1 UNKNOWN - - - 0 0.45 133940 +list-ext-properties/simple-ext.yml unreach-call symex 2 UNKNOWN - - - 0 0.43 133936 +list-ext-properties/simple-ext.yml unreach-call symex 3 UNKNOWN - - - 0 0.45 133724 +list-ext-properties/simple-ext.yml unreach-call symex 4 UNKNOWN - - - 0 0.43 133532 +list-ext-properties/simple-ext.yml unreach-call symex 5 UNKNOWN - - - 0 0.45 133944 +list-ext-properties/simple-ext.yml valid-memcleanup afl 1 UNKNOWN - - - 0 9.46 567880 +list-ext-properties/simple-ext.yml valid-memcleanup afl 2 UNKNOWN - - - 0 9.45 580424 +list-ext-properties/simple-ext.yml valid-memcleanup afl 3 UNKNOWN - - - 0 9.44 593312 +list-ext-properties/simple-ext.yml valid-memcleanup afl 4 UNKNOWN - - - 0 9.45 575988 +list-ext-properties/simple-ext.yml valid-memcleanup afl 5 UNKNOWN - - - 0 9.45 586696 +list-ext-properties/simple-ext.yml valid-memcleanup symex 1 UNKNOWN - - - 0 0.95 134444 +list-ext-properties/simple-ext.yml valid-memcleanup symex 2 UNKNOWN - - - 0 0.96 135020 +list-ext-properties/simple-ext.yml valid-memcleanup symex 3 UNKNOWN - - - 0 0.96 135228 +list-ext-properties/simple-ext.yml valid-memcleanup symex 4 UNKNOWN - - - 0 0.99 134464 +list-ext-properties/simple-ext.yml valid-memcleanup symex 5 UNKNOWN - - - 0 0.94 134464 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.57 92828 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.58 93632 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.58 93616 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.57 93104 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.57 92768 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 0.59 127540 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 0.62 128328 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 0.59 129504 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 0.59 127956 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 0.66 128052 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.43 341040 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 341380 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 341320 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.47 341076 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 341032 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 0.52 134400 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 0.51 134552 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 0.54 134032 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 0.51 134128 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 0.51 134140 +map2check-assert/array_bug.yml unreach-call afl 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.49 92272 +map2check-assert/array_bug.yml unreach-call afl 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.50 91232 +map2check-assert/array_bug.yml unreach-call afl 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.48 92044 +map2check-assert/array_bug.yml unreach-call afl 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.52 91372 +map2check-assert/array_bug.yml unreach-call afl 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.52 92252 +map2check-assert/array_bug.yml unreach-call symex 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 6.19 171440 +map2check-assert/array_bug.yml unreach-call symex 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 6.05 171064 +map2check-assert/array_bug.yml unreach-call symex 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 5.97 171144 +map2check-assert/array_bug.yml unreach-call symex 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 6.01 171492 +map2check-assert/array_bug.yml unreach-call symex 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 6.11 171352 +map2check-assert/byte_add_bug.yml unreach-call afl 1 UNKNOWN - - - 0 9.39 91788 +map2check-assert/byte_add_bug.yml unreach-call afl 2 UNKNOWN - - - 0 9.39 91748 +map2check-assert/byte_add_bug.yml unreach-call afl 3 UNKNOWN - - - 0 9.35 91968 +map2check-assert/byte_add_bug.yml unreach-call afl 4 UNKNOWN - - - 0 9.37 91752 +map2check-assert/byte_add_bug.yml unreach-call afl 5 UNKNOWN - - - 0 9.38 340704 +map2check-assert/byte_add_bug.yml unreach-call symex 1 SUCCEEDED - - - 0 0.36 126804 +map2check-assert/byte_add_bug.yml unreach-call symex 2 SUCCEEDED - - - 0 0.36 126812 +map2check-assert/byte_add_bug.yml unreach-call symex 3 SUCCEEDED - - - 0 0.35 127624 +map2check-assert/byte_add_bug.yml unreach-call symex 4 SUCCEEDED - - - 0 0.35 127068 +map2check-assert/byte_add_bug.yml unreach-call symex 5 SUCCEEDED - - - 0 0.36 127192 +map2check-assert/check_if_bug.yml unreach-call afl 1 UNKNOWN - - - 0 0.36 91168 +map2check-assert/check_if_bug.yml unreach-call afl 2 UNKNOWN - - - 0 0.33 91472 +map2check-assert/check_if_bug.yml unreach-call afl 3 UNKNOWN - - - 0 0.32 91452 +map2check-assert/check_if_bug.yml unreach-call afl 4 UNKNOWN - - - 0 0.33 91644 +map2check-assert/check_if_bug.yml unreach-call afl 5 UNKNOWN - - - 0 0.33 91360 +map2check-assert/check_if_bug.yml unreach-call symex 1 UNKNOWN - - - 0 31.77 181296 +map2check-assert/check_if_bug.yml unreach-call symex 2 UNKNOWN - - - 0 31.96 184544 +map2check-assert/check_if_bug.yml unreach-call symex 3 UNKNOWN - - - 0 31.77 176252 +map2check-assert/check_if_bug.yml unreach-call symex 4 UNKNOWN - - - 0 31.82 183956 +map2check-assert/check_if_bug.yml unreach-call symex 5 UNKNOWN - - - 0 31.78 184676 +map2check-assert/ex01_false.yml unreach-call afl 1 UNKNOWN - - - 0 1.35 92272 +map2check-assert/ex01_false.yml unreach-call afl 2 UNKNOWN - - - 0 1.35 91732 +map2check-assert/ex01_false.yml unreach-call afl 3 UNKNOWN - - - 0 1.36 91424 +map2check-assert/ex01_false.yml unreach-call afl 4 UNKNOWN - - - 0 1.36 91524 +map2check-assert/ex01_false.yml unreach-call afl 5 UNKNOWN - - - 0 1.35 91592 +map2check-assert/ex01_false.yml unreach-call symex 1 UNKNOWN - - - 0 2.59 144384 +map2check-assert/ex01_false.yml unreach-call symex 2 UNKNOWN - - - 0 2.61 146564 +map2check-assert/ex01_false.yml unreach-call symex 3 UNKNOWN - - - 0 2.54 144484 +map2check-assert/ex01_false.yml unreach-call symex 4 UNKNOWN - - - 0 2.59 144560 +map2check-assert/ex01_false.yml unreach-call symex 5 UNKNOWN - - - 0 2.57 144128 +map2check-assert/ex02_false.yml unreach-call afl 1 UNKNOWN - - - 0 0.34 91200 +map2check-assert/ex02_false.yml unreach-call afl 2 UNKNOWN - - - 0 0.34 92040 +map2check-assert/ex02_false.yml unreach-call afl 3 UNKNOWN - - - 0 0.34 91332 +map2check-assert/ex02_false.yml unreach-call afl 4 UNKNOWN - - - 0 0.33 91180 +map2check-assert/ex02_false.yml unreach-call afl 5 UNKNOWN - - - 0 0.34 91116 +map2check-assert/ex02_false.yml unreach-call symex 1 UNKNOWN - - - 0 31.40 222104 +map2check-assert/ex02_false.yml unreach-call symex 2 UNKNOWN - - - 0 31.46 220824 +map2check-assert/ex02_false.yml unreach-call symex 3 UNKNOWN - - - 0 31.42 221684 +map2check-assert/ex02_false.yml unreach-call symex 4 UNKNOWN - - - 0 31.45 221196 +map2check-assert/ex02_false.yml unreach-call symex 5 UNKNOWN - - - 0 31.44 222768 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 93016 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.43 92684 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 93192 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.42 93548 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.43 93188 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.74 167996 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.80 168560 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.91 170172 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.74 170628 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.97 169884 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.45 92880 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.45 93792 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.44 93044 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.44 93152 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.45 92720 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.51 157036 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.58 152260 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.51 153648 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.52 152384 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.51 154968 +memsafety-ext/tree_stack.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.45 93480 +memsafety-ext/tree_stack.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.45 94104 +memsafety-ext/tree_stack.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 94228 +memsafety-ext/tree_stack.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.45 92956 +memsafety-ext/tree_stack.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.45 93456 +memsafety-ext/tree_stack.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.60 182152 +memsafety-ext/tree_stack.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.59 181736 +memsafety-ext/tree_stack.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.59 181988 +memsafety-ext/tree_stack.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.59 181960 +memsafety-ext/tree_stack.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.60 182208 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.44 93208 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.45 93032 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.45 93996 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.46 93336 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.46 93096 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.36 141436 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.36 141768 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.36 141688 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.37 143332 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.36 141344 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 93720 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.47 93476 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.49 93740 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.48 94368 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 93512 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.11 243392 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.94 242576 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.96 247204 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.91 242244 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.99 245372 +memsafety/960521-1-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 532 main 0 0.56 92792 +memsafety/960521-1-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 532 main 0 0.56 92784 +memsafety/960521-1-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 532 main 0 0.56 93104 +memsafety/960521-1-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 532 main 0 0.73 92756 +memsafety/960521-1-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 532 main 0 0.59 93232 +memsafety/960521-1-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 532 main 0 1.00 127900 +memsafety/960521-1-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 532 main 0 0.99 127812 +memsafety/960521-1-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 532 main 0 1.00 128020 +memsafety/960521-1-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 532 main 0 1.01 127792 +memsafety/960521-1-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 532 main 0 0.97 127936 +memsafety/960521-1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.43 92968 +memsafety/960521-1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.42 93708 +memsafety/960521-1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.42 93048 +memsafety/960521-1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.42 93044 +memsafety/960521-1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.43 92920 +memsafety/960521-1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.34 127364 +memsafety/960521-1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.35 127456 +memsafety/960521-1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.35 127736 +memsafety/960521-1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.35 127084 +memsafety/960521-1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.35 127284 +memsafety/960521-1-3.yml valid-memsafety afl 1 FAILED FALSE-DEREF 529 main 0 0.58 92952 +memsafety/960521-1-3.yml valid-memsafety afl 2 FAILED FALSE-DEREF 529 main 0 0.60 93076 +memsafety/960521-1-3.yml valid-memsafety afl 3 FAILED FALSE-DEREF 529 main 0 0.60 93120 +memsafety/960521-1-3.yml valid-memsafety afl 4 FAILED FALSE-DEREF 529 main 0 0.60 93500 +memsafety/960521-1-3.yml valid-memsafety afl 5 FAILED FALSE-DEREF 529 main 0 0.57 93240 +memsafety/960521-1-3.yml valid-memsafety symex 1 FAILED FALSE-DEREF 529 main 0 0.99 127860 +memsafety/960521-1-3.yml valid-memsafety symex 2 FAILED FALSE-DEREF 529 main 0 0.98 128188 +memsafety/960521-1-3.yml valid-memsafety symex 3 FAILED FALSE-DEREF 529 main 0 0.95 127796 +memsafety/960521-1-3.yml valid-memsafety symex 4 FAILED FALSE-DEREF 529 main 0 1.00 127856 +memsafety/960521-1-3.yml valid-memsafety symex 5 FAILED FALSE-DEREF 529 main 0 0.97 128332 +memsafety/test-0102-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 94212 +memsafety/test-0102-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.48 94100 +memsafety/test-0102-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.48 93508 +memsafety/test-0102-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 93600 +memsafety/test-0102-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.48 94216 +memsafety/test-0102-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 31.38 149168 +memsafety/test-0102-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 31.43 149080 +memsafety/test-0102-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 31.38 150612 +memsafety/test-0102-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 31.44 149012 +memsafety/test-0102-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 31.40 150804 diff --git a/tests/cutover/baseline-rust.tsv b/tests/cutover/baseline-rust.tsv new file mode 100644 index 000000000..2474e34d4 --- /dev/null +++ b/tests/cutover/baseline-rust.tsv @@ -0,0 +1,411 @@ +task prp gen rep verdict tag line function witness wall_s maxrss_kb +array-examples/relax-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.60 92376 +array-examples/relax-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.61 92200 +array-examples/relax-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.60 92280 +array-examples/relax-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.62 91984 +array-examples/relax-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.62 92292 +array-examples/relax-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 3.43 226436 +array-examples/relax-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 3.43 227548 +array-examples/relax-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 3.32 227900 +array-examples/relax-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 3.27 217960 +array-examples/relax-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 3.47 227432 +array-examples/standard_sentinel-2.yml unreach-call afl 1 UNKNOWN - - - 0 9.44 340960 +array-examples/standard_sentinel-2.yml unreach-call afl 2 UNKNOWN - - - 0 9.44 340724 +array-examples/standard_sentinel-2.yml unreach-call afl 3 UNKNOWN - - - 0 9.44 340924 +array-examples/standard_sentinel-2.yml unreach-call afl 4 UNKNOWN - - - 0 9.44 341064 +array-examples/standard_sentinel-2.yml unreach-call afl 5 UNKNOWN - - - 0 9.45 340992 +array-examples/standard_sentinel-2.yml unreach-call symex 1 UNKNOWN - - - 0 34.22 254128 +array-examples/standard_sentinel-2.yml unreach-call symex 2 UNKNOWN - - - 0 34.19 253748 +array-examples/standard_sentinel-2.yml unreach-call symex 3 UNKNOWN - - - 0 34.03 254648 +array-examples/standard_sentinel-2.yml unreach-call symex 4 UNKNOWN - - - 0 34.06 254224 +array-examples/standard_sentinel-2.yml unreach-call symex 5 UNKNOWN - - - 0 34.17 253264 +array-examples/standard_two_index_04.yml unreach-call afl 1 UNKNOWN - - - 0 9.45 340996 +array-examples/standard_two_index_04.yml unreach-call afl 2 UNKNOWN - - - 0 9.43 340984 +array-examples/standard_two_index_04.yml unreach-call afl 3 UNKNOWN - - - 0 9.44 341364 +array-examples/standard_two_index_04.yml unreach-call afl 4 UNKNOWN - - - 0 9.45 340864 +array-examples/standard_two_index_04.yml unreach-call afl 5 UNKNOWN - - - 0 9.44 340900 +array-examples/standard_two_index_04.yml unreach-call symex 1 UNKNOWN - - - 0 34.11 254292 +array-examples/standard_two_index_04.yml unreach-call symex 2 UNKNOWN - - - 0 34.09 253788 +array-examples/standard_two_index_04.yml unreach-call symex 3 UNKNOWN - - - 0 34.14 254024 +array-examples/standard_two_index_04.yml unreach-call symex 4 UNKNOWN - - - 0 34.08 254160 +array-examples/standard_two_index_04.yml unreach-call symex 5 UNKNOWN - - - 0 34.19 253924 +array-examples/standard_two_index_05.yml unreach-call afl 1 UNKNOWN - - - 0 9.44 341016 +array-examples/standard_two_index_05.yml unreach-call afl 2 UNKNOWN - - - 0 9.44 340944 +array-examples/standard_two_index_05.yml unreach-call afl 3 UNKNOWN - - - 0 9.43 340928 +array-examples/standard_two_index_05.yml unreach-call afl 4 UNKNOWN - - - 0 9.44 341204 +array-examples/standard_two_index_05.yml unreach-call afl 5 UNKNOWN - - - 0 9.46 341212 +array-examples/standard_two_index_05.yml unreach-call symex 1 UNKNOWN - - - 0 34.14 253068 +array-examples/standard_two_index_05.yml unreach-call symex 2 UNKNOWN - - - 0 34.10 254048 +array-examples/standard_two_index_05.yml unreach-call symex 3 UNKNOWN - - - 0 34.14 256884 +array-examples/standard_two_index_05.yml unreach-call symex 4 UNKNOWN - - - 0 34.13 253584 +array-examples/standard_two_index_05.yml unreach-call symex 5 UNKNOWN - - - 0 34.09 253880 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.61 92192 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.59 91832 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.60 92108 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.60 92280 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.59 92028 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 1 FAILED FALSE-DEREF 522 main 0 3.16 216456 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 2 FAILED FALSE-DEREF 522 main 0 3.22 216188 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 3 FAILED FALSE-DEREF 522 main 0 3.24 216780 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 4 FAILED FALSE-DEREF 522 main 0 3.16 226292 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 5 FAILED FALSE-DEREF 522 main 0 3.30 225644 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91788 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 91876 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 92148 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.46 92004 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.45 92240 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 34.23 238592 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 34.27 239044 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 34.16 238780 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 34.25 238520 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 34.22 238344 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.90 340820 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.76 341148 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.76 341056 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.76 340828 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.76 341056 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.23 227308 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.29 227440 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.20 229752 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 3.25 227516 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.33 215964 +array-memsafety/lis_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91876 +array-memsafety/lis_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 91660 +array-memsafety/lis_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 91904 +array-memsafety/lis_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 91852 +array-memsafety/lis_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 91668 +array-memsafety/lis_unsafe.yml valid-memsafety symex 1 UNKNOWN - - - 0 3.24 227400 +array-memsafety/lis_unsafe.yml valid-memsafety symex 2 UNKNOWN - - - 0 3.33 227488 +array-memsafety/lis_unsafe.yml valid-memsafety symex 3 UNKNOWN - - - 0 3.26 227780 +array-memsafety/lis_unsafe.yml valid-memsafety symex 4 UNKNOWN - - - 0 3.37 217408 +array-memsafety/lis_unsafe.yml valid-memsafety symex 5 UNKNOWN - - - 0 3.19 217612 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.43 340980 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 340772 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 340900 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341432 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 340964 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.02 221728 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.06 220928 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.09 221624 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 3.10 220748 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.11 219784 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 1 FAILED FALSE-FREE 46 main 0 0.61 91428 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 2 FAILED FALSE-FREE 46 main 0 0.59 92228 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 3 FAILED FALSE-FREE 46 main 0 0.60 91428 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 4 FAILED FALSE-FREE 46 main 0 0.60 91556 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 5 FAILED FALSE-FREE 46 main 0 0.59 91240 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 1 FAILED FALSE-FREE 46 main 0 3.11 201440 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 2 FAILED FALSE-FREE 46 main 0 3.22 219780 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 3 FAILED FALSE-FREE 46 main 0 3.21 219596 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 4 FAILED FALSE-FREE 46 main 0 3.09 202484 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 5 FAILED FALSE-FREE 46 main 0 3.06 202892 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 340784 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 340948 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 341176 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 341272 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 341288 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 3.21 200960 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 3.15 200808 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 3.23 200336 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 3.21 200536 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 3.15 200584 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 341132 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 341012 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.45 341116 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 341420 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 341164 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 1 SUCCEEDED - - - 0 22.58 220100 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 2 SUCCEEDED - - - 0 21.81 201920 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 3 SUCCEEDED - - - 0 22.88 220620 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 4 SUCCEEDED - - - 0 22.84 202944 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 5 SUCCEEDED - - - 0 22.35 203456 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91448 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 91176 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 91672 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.48 90948 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.46 91672 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 1 UNKNOWN - - - 0 34.11 220684 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 2 UNKNOWN - - - 0 34.13 201604 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 3 UNKNOWN - - - 0 34.03 205008 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 4 UNKNOWN - - - 0 34.10 202236 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 5 UNKNOWN - - - 0 34.07 220100 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.67 92496 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.67 91944 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.68 92420 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.70 92432 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.70 93132 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 3.57 227392 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 3.50 227596 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 3.49 209416 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 3.45 226872 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 3.39 209392 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.56 341196 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.55 341132 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.53 340604 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.54 340808 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.55 341076 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 4.15 209912 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 4.08 210636 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 4.05 210540 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 4.02 210272 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 4.10 210540 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 779 free_17 0 0.72 92688 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 779 free_17 0 0.69 92540 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 779 free_17 0 0.71 93060 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 779 free_17 0 0.71 93024 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 779 free_17 0 0.70 92632 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 779 free_17 0 4.43 212304 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 779 free_17 0 4.52 228120 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 779 free_17 0 4.44 211476 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 779 free_17 0 4.51 211696 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 779 free_17 0 4.41 212112 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.53 341144 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.52 341132 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.53 340956 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.55 340836 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.54 340592 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.58 209796 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.48 209644 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.41 210076 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 3.41 209800 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.45 209728 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 340996 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 340508 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 340720 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.43 341112 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 340772 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.02 200768 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.08 200756 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.16 218684 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 4 SUCCEEDED - - - 0 3.11 218576 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.10 222872 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 1 FAILED FALSE-DEREF 533 main 0 0.61 92052 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 2 FAILED FALSE-DEREF 533 main 0 0.60 91640 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 3 FAILED FALSE-DEREF 533 main 0 0.59 92072 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 4 FAILED FALSE-DEREF 533 main 0 0.61 91812 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 5 FAILED FALSE-DEREF 533 main 0 0.61 91772 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 533 main 0 3.58 225784 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 533 main 0 3.54 208408 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 533 main 0 3.37 225440 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 533 main 0 3.32 226220 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 533 main 0 3.32 226376 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 340940 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.51 341372 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.48 341244 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.46 340832 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 340904 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 6.13 226480 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 6.72 209508 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 6.22 227704 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 5.93 228328 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 6.13 209716 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 1 FAILED FALSE-FREE 536 main 0 0.59 92476 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 2 FAILED FALSE-FREE 536 main 0 0.61 91664 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 3 FAILED FALSE-FREE 536 main 0 0.59 91472 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 4 FAILED FALSE-FREE 536 main 0 0.61 91736 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 5 FAILED FALSE-FREE 536 main 0 0.59 91660 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 1 FAILED FALSE-FREE 536 main 0 3.44 211304 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 2 FAILED FALSE-FREE 536 main 0 3.56 226460 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 3 FAILED FALSE-FREE 536 main 0 3.53 225744 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 4 FAILED FALSE-FREE 536 main 0 3.32 226224 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 5 FAILED FALSE-FREE 536 main 0 3.28 209232 +list-ext-properties/list-ext.yml unreach-call afl 1 FAILED TARGET-REACHED 556 main 0 0.78 340928 +list-ext-properties/list-ext.yml unreach-call afl 2 FAILED TARGET-REACHED 556 main 0 0.81 341184 +list-ext-properties/list-ext.yml unreach-call afl 3 FAILED TARGET-REACHED 556 main 0 0.76 340552 +list-ext-properties/list-ext.yml unreach-call afl 4 FAILED TARGET-REACHED 556 main 0 0.77 340568 +list-ext-properties/list-ext.yml unreach-call afl 5 FAILED TARGET-REACHED 556 main 0 0.78 340540 +list-ext-properties/list-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 556 main 0 3.39 226868 +list-ext-properties/list-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 556 main 0 3.38 226860 +list-ext-properties/list-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 556 main 0 3.45 208688 +list-ext-properties/list-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 556 main 0 3.29 226288 +list-ext-properties/list-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 556 main 0 3.28 228836 +list-ext-properties/list-ext.yml valid-memsafety afl 1 FAILED FALSE-DEREF 558 main 0 0.61 92284 +list-ext-properties/list-ext.yml valid-memsafety afl 2 FAILED FALSE-DEREF 558 main 0 0.63 92044 +list-ext-properties/list-ext.yml valid-memsafety afl 3 FAILED FALSE-DEREF 558 main 0 0.61 92360 +list-ext-properties/list-ext.yml valid-memsafety afl 4 FAILED FALSE-DEREF 558 main 0 0.61 91680 +list-ext-properties/list-ext.yml valid-memsafety afl 5 FAILED FALSE-DEREF 558 main 0 0.59 91956 +list-ext-properties/list-ext.yml valid-memsafety symex 1 FAILED FALSE-DEREF 558 main 0 8.49 229236 +list-ext-properties/list-ext.yml valid-memsafety symex 2 FAILED FALSE-DEREF 558 main 0 8.60 228864 +list-ext-properties/list-ext.yml valid-memsafety symex 3 FAILED FALSE-DEREF 558 main 0 8.54 211504 +list-ext-properties/list-ext.yml valid-memsafety symex 4 FAILED FALSE-DEREF 558 main 0 8.39 212056 +list-ext-properties/list-ext.yml valid-memsafety symex 5 FAILED FALSE-DEREF 558 main 0 8.39 212324 +list-ext-properties/simple-ext.yml unreach-call afl 1 FAILED TARGET-REACHED 540 main 0 0.61 91960 +list-ext-properties/simple-ext.yml unreach-call afl 2 FAILED TARGET-REACHED 540 main 0 0.59 92076 +list-ext-properties/simple-ext.yml unreach-call afl 3 FAILED TARGET-REACHED 540 main 0 0.60 91704 +list-ext-properties/simple-ext.yml unreach-call afl 4 FAILED TARGET-REACHED 540 main 0 0.60 92000 +list-ext-properties/simple-ext.yml unreach-call afl 5 FAILED TARGET-REACHED 540 main 0 0.59 92044 +list-ext-properties/simple-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 540 main 0 3.27 225072 +list-ext-properties/simple-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 540 main 0 3.26 228396 +list-ext-properties/simple-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 540 main 0 3.20 225288 +list-ext-properties/simple-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 540 main 0 3.32 226460 +list-ext-properties/simple-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 540 main 0 3.19 226720 +list-ext-properties/simple-ext.yml valid-memcleanup afl 1 UNKNOWN - - - 0 9.46 341140 +list-ext-properties/simple-ext.yml valid-memcleanup afl 2 UNKNOWN - - - 0 9.46 340876 +list-ext-properties/simple-ext.yml valid-memcleanup afl 3 UNKNOWN - - - 0 9.46 341088 +list-ext-properties/simple-ext.yml valid-memcleanup afl 4 UNKNOWN - - - 0 9.45 341028 +list-ext-properties/simple-ext.yml valid-memcleanup afl 5 UNKNOWN - - - 0 9.46 341316 +list-ext-properties/simple-ext.yml valid-memcleanup symex 1 UNKNOWN - - - 0 3.29 224264 +list-ext-properties/simple-ext.yml valid-memcleanup symex 2 UNKNOWN - - - 0 3.23 208188 +list-ext-properties/simple-ext.yml valid-memcleanup symex 3 UNKNOWN - - - 0 3.32 226212 +list-ext-properties/simple-ext.yml valid-memcleanup symex 4 UNKNOWN - - - 0 3.49 226604 +list-ext-properties/simple-ext.yml valid-memcleanup symex 5 UNKNOWN - - - 0 3.32 207700 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.60 91780 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.60 92380 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.60 92068 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.59 92616 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.58 92540 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 3.17 219960 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 3.18 220824 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 3.22 220976 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 3.26 203036 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 3.28 219484 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.47 340712 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 340788 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 340624 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341140 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 340860 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.16 225564 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.26 225632 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.30 225480 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 3.14 211028 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.10 225460 +map2check-assert/array_bug.yml unreach-call afl 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.60 90700 +map2check-assert/array_bug.yml unreach-call afl 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.58 91468 +map2check-assert/array_bug.yml unreach-call afl 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.57 90796 +map2check-assert/array_bug.yml unreach-call afl 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.59 90764 +map2check-assert/array_bug.yml unreach-call afl 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.58 91564 +map2check-assert/array_bug.yml unreach-call symex 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 3.21 225772 +map2check-assert/array_bug.yml unreach-call symex 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 3.21 228348 +map2check-assert/array_bug.yml unreach-call symex 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 3.15 207020 +map2check-assert/array_bug.yml unreach-call symex 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 3.16 224876 +map2check-assert/array_bug.yml unreach-call symex 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 3.09 207320 +map2check-assert/byte_add_bug.yml unreach-call afl 1 UNKNOWN - - - 0 9.45 340932 +map2check-assert/byte_add_bug.yml unreach-call afl 2 UNKNOWN - - - 0 9.46 341136 +map2check-assert/byte_add_bug.yml unreach-call afl 3 UNKNOWN - - - 0 9.46 340744 +map2check-assert/byte_add_bug.yml unreach-call afl 4 UNKNOWN - - - 0 9.47 341032 +map2check-assert/byte_add_bug.yml unreach-call afl 5 UNKNOWN - - - 0 9.46 341080 +map2check-assert/byte_add_bug.yml unreach-call symex 1 SUCCEEDED - - - 0 3.17 220320 +map2check-assert/byte_add_bug.yml unreach-call symex 2 SUCCEEDED - - - 0 3.22 203200 +map2check-assert/byte_add_bug.yml unreach-call symex 3 SUCCEEDED - - - 0 3.09 218880 +map2check-assert/byte_add_bug.yml unreach-call symex 4 SUCCEEDED - - - 0 3.23 220980 +map2check-assert/byte_add_bug.yml unreach-call symex 5 SUCCEEDED - - - 0 3.14 220676 +map2check-assert/check_if_bug.yml unreach-call afl 1 UNKNOWN - - - 0 1.45 90736 +map2check-assert/check_if_bug.yml unreach-call afl 2 UNKNOWN - - - 0 1.45 91656 +map2check-assert/check_if_bug.yml unreach-call afl 3 UNKNOWN - - - 0 1.47 90976 +map2check-assert/check_if_bug.yml unreach-call afl 4 UNKNOWN - - - 0 1.45 90984 +map2check-assert/check_if_bug.yml unreach-call afl 5 UNKNOWN - - - 0 1.45 91308 +map2check-assert/check_if_bug.yml unreach-call symex 1 UNKNOWN - - - 0 34.67 254060 +map2check-assert/check_if_bug.yml unreach-call symex 2 UNKNOWN - - - 0 34.72 254024 +map2check-assert/check_if_bug.yml unreach-call symex 3 UNKNOWN - - - 0 34.58 254220 +map2check-assert/check_if_bug.yml unreach-call symex 4 UNKNOWN - - - 0 34.69 255068 +map2check-assert/check_if_bug.yml unreach-call symex 5 UNKNOWN - - - 0 34.66 254548 +map2check-assert/ex01_false.yml unreach-call afl 1 UNKNOWN - - - 0 1.46 91304 +map2check-assert/ex01_false.yml unreach-call afl 2 UNKNOWN - - - 0 1.45 91368 +map2check-assert/ex01_false.yml unreach-call afl 3 UNKNOWN - - - 0 1.45 91208 +map2check-assert/ex01_false.yml unreach-call afl 4 UNKNOWN - - - 0 1.44 90676 +map2check-assert/ex01_false.yml unreach-call afl 5 UNKNOWN - - - 0 1.46 90744 +map2check-assert/ex01_false.yml unreach-call symex 1 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 4.96 225852 +map2check-assert/ex01_false.yml unreach-call symex 2 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 4.86 225744 +map2check-assert/ex01_false.yml unreach-call symex 3 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 4.81 215992 +map2check-assert/ex01_false.yml unreach-call symex 4 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 4.86 217988 +map2check-assert/ex01_false.yml unreach-call symex 5 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 4.78 216124 +map2check-assert/ex02_false.yml unreach-call afl 1 UNKNOWN - - - 0 1.44 91132 +map2check-assert/ex02_false.yml unreach-call afl 2 UNKNOWN - - - 0 1.44 90824 +map2check-assert/ex02_false.yml unreach-call afl 3 UNKNOWN - - - 0 1.44 90572 +map2check-assert/ex02_false.yml unreach-call afl 4 UNKNOWN - - - 0 1.45 90536 +map2check-assert/ex02_false.yml unreach-call afl 5 UNKNOWN - - - 0 1.44 91140 +map2check-assert/ex02_false.yml unreach-call symex 1 UNKNOWN - - - 0 34.17 251868 +map2check-assert/ex02_false.yml unreach-call symex 2 UNKNOWN - - - 0 34.25 250880 +map2check-assert/ex02_false.yml unreach-call symex 3 UNKNOWN - - - 0 34.15 251668 +map2check-assert/ex02_false.yml unreach-call symex 4 UNKNOWN - - - 0 34.24 250468 +map2check-assert/ex02_false.yml unreach-call symex 5 UNKNOWN - - - 0 34.16 251024 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.46 341004 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 340788 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.46 340864 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 340544 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 340976 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 35.65 247356 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 35.64 246676 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 35.73 244480 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 35.57 245100 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 35.42 244120 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 91820 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 92232 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 91864 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 91804 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 92524 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 1 UNKNOWN - - - 0 34.57 289196 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 2 UNKNOWN - - - 0 34.54 287708 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 3 UNKNOWN - - - 0 34.76 287448 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 4 UNKNOWN - - - 0 35.10 287468 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 5 UNKNOWN - - - 0 34.44 289644 +memsafety-ext/tree_stack.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91908 +memsafety-ext/tree_stack.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.47 91664 +memsafety-ext/tree_stack.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.48 91760 +memsafety-ext/tree_stack.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.48 91980 +memsafety-ext/tree_stack.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 91968 +memsafety-ext/tree_stack.yml valid-memsafety symex 1 UNKNOWN - - - 0 34.79 323092 +memsafety-ext/tree_stack.yml valid-memsafety symex 2 UNKNOWN - - - 0 34.87 321036 +memsafety-ext/tree_stack.yml valid-memsafety symex 3 UNKNOWN - - - 0 34.72 326928 +memsafety-ext/tree_stack.yml valid-memsafety symex 4 UNKNOWN - - - 0 34.75 325792 +memsafety-ext/tree_stack.yml valid-memsafety symex 5 UNKNOWN - - - 0 34.85 326164 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 91732 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 92008 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 92460 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 91736 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.48 92048 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 34.12 221528 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 34.16 230884 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 34.11 219528 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 34.08 231356 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 34.14 219212 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.50 92108 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.48 92220 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.49 92452 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.50 92732 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.49 92076 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 35.70 458696 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 35.41 472032 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 35.50 473600 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 35.63 470916 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 35.42 475664 +memsafety/960521-1-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 532 main 0 0.59 91732 +memsafety/960521-1-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 532 main 0 0.59 92744 +memsafety/960521-1-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 532 main 0 0.57 91732 +memsafety/960521-1-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 532 main 0 0.58 91472 +memsafety/960521-1-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 532 main 0 0.61 91548 +memsafety/960521-1-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 532 main 0 3.28 219840 +memsafety/960521-1-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 532 main 0 3.32 219692 +memsafety/960521-1-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 532 main 0 3.29 202108 +memsafety/960521-1-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 532 main 0 3.28 220396 +memsafety/960521-1-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 532 main 0 3.38 219828 +memsafety/960521-1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 340752 +memsafety/960521-1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.46 340852 +memsafety/960521-1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.45 340984 +memsafety/960521-1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 341216 +memsafety/960521-1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 340784 +memsafety/960521-1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 30.01 219572 +memsafety/960521-1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 32.06 219864 +memsafety/960521-1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 32.88 220076 +memsafety/960521-1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 31.28 204672 +memsafety/960521-1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 30.40 219456 +memsafety/960521-1-3.yml valid-memsafety afl 1 FAILED FALSE-DEREF 529 main 0 0.61 92324 +memsafety/960521-1-3.yml valid-memsafety afl 2 FAILED FALSE-DEREF 529 main 0 0.61 91776 +memsafety/960521-1-3.yml valid-memsafety afl 3 FAILED FALSE-DEREF 529 main 0 0.60 91828 +memsafety/960521-1-3.yml valid-memsafety afl 4 FAILED FALSE-DEREF 529 main 0 0.62 92420 +memsafety/960521-1-3.yml valid-memsafety afl 5 FAILED FALSE-DEREF 529 main 0 0.60 91888 +memsafety/960521-1-3.yml valid-memsafety symex 1 FAILED FALSE-DEREF 529 main 0 3.53 218924 +memsafety/960521-1-3.yml valid-memsafety symex 2 FAILED FALSE-DEREF 529 main 0 3.30 222048 +memsafety/960521-1-3.yml valid-memsafety symex 3 FAILED FALSE-DEREF 529 main 0 3.36 219980 +memsafety/960521-1-3.yml valid-memsafety symex 4 FAILED FALSE-DEREF 529 main 0 3.36 202212 +memsafety/960521-1-3.yml valid-memsafety symex 5 FAILED FALSE-DEREF 529 main 0 3.29 220108 +memsafety/test-0102-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 91960 +memsafety/test-0102-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.49 91744 +memsafety/test-0102-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.48 92908 +memsafety/test-0102-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.50 92740 +memsafety/test-0102-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.48 92220 +memsafety/test-0102-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 34.28 284444 +memsafety/test-0102-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 34.59 269004 +memsafety/test-0102-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 36.39 268464 +memsafety/test-0102-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 34.94 271516 +memsafety/test-0102-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 34.89 278452 diff --git a/tests/cutover/deltas-aceitos-PROPOSTA.tsv b/tests/cutover/deltas-aceitos-PROPOSTA.tsv new file mode 100644 index 000000000..52ba47d93 --- /dev/null +++ b/tests/cutover/deltas-aceitos-PROPOSTA.tsv @@ -0,0 +1,7 @@ +task prp gen field c_value rust_value sd_ref +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex verdict UNKNOWN SUCCEEDED GANHO-ORCAMENTO +memsafety/960521-1-2.yml valid-memsafety symex verdict UNKNOWN SUCCEEDED GANHO-ORCAMENTO +list-ext-properties/list-ext.yml unreach-call afl verdict UNKNOWN FAILED UB-BENCHMARK-list-ext +list-ext-properties/list-ext.yml unreach-call afl tag - TARGET-REACHED UB-BENCHMARK-list-ext +list-ext-properties/list-ext.yml unreach-call afl line - 556 UB-BENCHMARK-list-ext +list-ext-properties/list-ext.yml unreach-call afl function - main UB-BENCHMARK-list-ext diff --git a/tests/cutover/gate-report.md b/tests/cutover/gate-report.md new file mode 100644 index 000000000..e32aadbe5 --- /dev/null +++ b/tests/cutover/gate-report.md @@ -0,0 +1,194 @@ +# Gate diferencial (Task 4.2) e memória D3/D4 (Task 4.3), execução 1 + +**Result: `gate` FAIL, both without and with the proposed accepted deltas.** The wall-time median passes, the TIMEOUT counts pass, and no Rust defect was found. Two kinds of rows still block: + +- C defects that need a new SD; +- the median RSS ratio (1.36 against the 1.25 limit). + +## Setup + +### Rust side + +- Map2Check-rust `7cc8ac7a` (the runner files are from `20e0572b`, which does not change the binary). +- map2check-library `44585e8` (cutover/runtime-rust), built from a `git archive` with a fresh `CARGO_TARGET_DIR`: + - `cargo build --profile runtime --features libfuzzer,wasm`; + - `scripts/build-klee-runtime.sh` (rustc 1.72.1, LLVM 16.0.5). +- Installed into fresh `build-gate2/` and `release-gate2/` with `-G Ninja -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm -DMAP2CHECK_DYNAMIC_LINK=ON -DMAP2CHECK_RUST_LIB_DIR=… -DMAP2CHECK_RUST_KLEE_BC=…`, plus the klee/clang symlinks. `cmp` confirms that the installed `.a` and `.bc` are the ones built. +- `release-gate2/map2check` mtime: 2026-10-16 19:05:06 -0400. +- sha256 prefixes: `map2check-klee.bc` 1f5edca0756922dc, `libmap2check.a` fda95ed02de3954a. +- Image: `map2check-dev:cutover-klee-rust-time` (`sha256:ef46e184…`), which is `cutover-klee-rust` plus GNU `time`. + +### C side + +- `Map2Check-cutover/release-afl`, built from `b3c10cb7` (develop `f01e8c3e` plus the runner commits, which is the base of feat/rust-runtime). Binary mtime: 2026-10-15 19:33:45 -0400. +- Image: `map2check-dev:cutover-f01e8c3e-time` (`sha256:48a8ed09…`), which is `cutover-f01e8c3e` plus GNU `time`. + +### Corpus and settings + +- Corpus: `tests/regression_test/test_cases/sv-benchmarks`, with 41 task×property pairs. +- Settings: `GENS="afl symex" TIMEOUT=45`, REPS=5 for C and Rust, and REPS=3 for C `--btree`. +- The runs were sequential: Rust 19:08–20:12, C 20:12–21:17, C-btree 21:17–21:33. +- Before each run, `free -g` showed 4 GB or more available. + +### Resource caps (the same on both sides) + +- Every container ran with `--memory 3g --memory-swap 3g --cpus 4`. +- **KLEE `--max-memory=2000`:** + - The frontend runs `${MAP2CHECK_PATH}/bin/klee …` and has no option for extra KLEE flags. It also resets `MAP2CHECK_PATH` from `/proc/self/exe`. + - The cap is therefore applied through an overlay install tree, built per container. It contains a copy of `map2check`, symlinks to the rest of the install, and a `bin/klee` wrapper that runs `exec /bin/klee --max-memory=2000 "$@"`. + - The overlay script is `$S/t42b/overlay.sh`. + - The wrapper was confirmed on both sides through a logged argv. +- The caps change the absolute numbers. They do not change the fairness of the comparison. +- **OOM detection:** `run-corpus.sh` (`20e0572b`) compares `oom_kill` in the container's `memory.events` before and after each task. A new kill without a decided verdict is recorded as verdict `OOM`. + +### Runner commits (signed, not pushed) + +- `8cf38ce9`: `EXTRA_FLAGS`. +- `20e0572b`: OOM verdict. + +## compare.py output + +``` +$ python3 scripts/cutover/compare.py tests/cutover/baseline-c-gate.tsv tests/cutover/baseline-rust.tsv --accepted tests/cutover/deltas-aceitos.tsv +median wall ratio: 1.015 median rss ratio: 1.360 + +| key | field | c | rust | +|---|---|---|---| +| array-examples/standard_sentinel-2.yml unreach-call afl | verdict | OOM | UNKNOWN | +| array-examples/standard_two_index_04.yml unreach-call afl | verdict | OOM | UNKNOWN | +| array-examples/standard_two_index_05.yml unreach-call afl | verdict | OOM | UNKNOWN | +| ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex | verdict | UNKNOWN | SUCCEEDED | +| list-ext-properties/960521-1_1-1.yml valid-memsafety symex | line | 0 | 533 | +| list-ext-properties/960521-1_1-1.yml valid-memsafety symex | function | - | main | +| list-ext-properties/list-ext.yml unreach-call afl | verdict | UNKNOWN | FAILED | +| list-ext-properties/list-ext.yml unreach-call afl | tag | - | TARGET-REACHED | +| list-ext-properties/list-ext.yml unreach-call afl | line | - | 556 | +| list-ext-properties/list-ext.yml unreach-call afl | function | - | main | +| list-ext-properties/simple-ext.yml unreach-call symex | verdict | UNKNOWN | FAILED | +| list-ext-properties/simple-ext.yml unreach-call symex | tag | - | TARGET-REACHED | +| list-ext-properties/simple-ext.yml unreach-call symex | line | - | 540 | +| list-ext-properties/simple-ext.yml unreach-call symex | function | - | main | +| map2check-assert/ex01_false.yml unreach-call symex | verdict | UNKNOWN | FAILED | +| map2check-assert/ex01_false.yml unreach-call symex | tag | - | TARGET-REACHED | +| map2check-assert/ex01_false.yml unreach-call symex | line | - | 5 | +| map2check-assert/ex01_false.yml unreach-call symex | function | - | __VERIFIER_assert | +| memsafety/960521-1-2.yml valid-memsafety symex | verdict | UNKNOWN | SUCCEEDED | +| all | median rss ratio | <= 1.25 | 1.360 | +``` + +With `--accepted tests/cutover/deltas-aceitos-PROPOSTA.tsv`, the four verdict-gain rows and the four list-ext afl rows drop out. The following still fail: + +- the 3 OOM rows; +- the 2 rows for 960521-1_1-1; +- the 8 rows for simple-ext and ex01_false; +- the RSS median. + +The result is still **FAIL**. + +## Verdict counts (mode of the reps per task) + +| gen | side | FAILED | SUCCEEDED | UNKNOWN | OOM | TIMEOUT | correct vs `expected_verdict` | +|---|---|---|---|---|---|---|---| +| afl | C | 11 | 0 | 27 | 3 | 0 | 11 | +| afl | Rust | 12 | 0 | 29 | 0 | 0 | 12 | +| symex | C | 13 | 8 | 20 | 0 | 0 | 20 | +| symex | Rust | 15 | 10 | 16 | 0 | 0 | 24 | + +- No row went from SUCCEEDED to FAILED or back, and no tag changed between rows that are FAILED on both sides. +- The C reps never disagree on any field (they are fully stable), and the Rust reps don't either. So there are no (d) rows. +- Criterion 4 holds: Rust has 36 correct verdicts against 31 for C. + +## Classification of every failing row + +| # | task / prp / gen | C → Rust | class | diagnosis | proposed | +|---|---|---|---|---|---| +| 1 | ArraysOfVariableLength / memsafety / symex | UNKNOWN → SUCCEEDED (expected true) | **(a)** | C stops on KLEE's 31 s `--max-time` (31.35 s, 5/5). Rust finishes the exploration in 22.6 s, thanks to the 2.7b throughput gain. | GANHO-ORCAMENTO | +| 2 | 960521-1-2 / memsafety / symex | UNKNOWN → SUCCEEDED (expected true) | **(a)** | Same: C at 31.35 s, the budget; Rust at 31.28 s. | GANHO-ORCAMENTO | +| 3 | list-ext / unreach / afl (4 fields) | UNKNOWN → FAILED TARGET-REACHED line 556 main (expected false) | **(b)** | Known UB in the benchmark (task-3.3 "Cause A"). The tail node's `n` is never initialised. In C, glibc reuses a chunk the runtime freed, so the seed crashes on a garbage dereference, the replay misses the target, and the result is UNKNOWN. In Rust the word is 0, and CmpLog finds the target. | UB-BENCHMARK-list-ext | +| 4 | simple-ext / unreach / symex (4 fields) | UNKNOWN → FAILED TARGET-REACHED line 540 main (expected false) | **C defect** (not a/b/c/d) | Reproduced by hand, see "C property-file race" below. C's KLEE does reach `__VERIFIER_error` (line 539, `abort.err`), but `map2check_property` ends up **0 bytes**, so the frontend says UNKNOWN in 0.45 s. This is not a budget effect. | no: needs an SD ("bug do C corrigido") | +| 5 | ex01_false / unreach / symex (4 fields) | UNKNOWN → FAILED TARGET-REACHED line 5 `__VERIFIER_assert` (expected false) | **C defect** | Same race. KLEE `abort.err` at line 4 or 5, 199 ktests, `map2check_property` 0 bytes, UNKNOWN in 2.6 s. | no: needs an SD | +| 6 | 960521-1_1-1 / memsafety / symex (line, function) | `0`/`-` → `533`/`main` | **C defect** | Same race. Both `map2check_property` and `map2check_property_deref` are 0 bytes. The frontend still prints FALSE-DEREF, because the `_deref` file exists, but it parses line 0 and an empty function. C afl on the same task reports `533 main`, the same as Rust. | no: needs an SD | +| 7 | standard_sentinel-2 / unreach / afl | OOM → UNKNOWN (expected true) | **C defect (memory)** | C hits the 3 GB cap in 15 of 15 reps (`oom_kill` seen; maxrss about 3.1 GB). Without the cap, the committed `baseline-c.tsv` shows **12.8 GB**, with UNKNOWN. Rust uses 341 MB. The program reads 100 000 `__VERIFIER_nondet_int`. Hypothesis, not profiled: per-call growth of the C NonDetLog under AFL. | no: needs an SD, or a ruling that a C OOM is equivalent to UNKNOWN | +| 8 | standard_two_index_04 / unreach / afl | OOM → UNKNOWN | C defect (memory) | Same as #7 (`a[100000]`, `b[100000]`). | no | +| 9 | standard_two_index_05 / unreach / afl | OOM → UNKNOWN | C defect (memory) | Same as #7. | no | +| 10 | all / median RSS ratio | 1.360 > 1.25 | D4 (criterion 8) | See "Performance". The excess is a fixed overhead under symex, about +80 MB. | not a delta row | + +- **(c) Rust or pass defects: 0.** +- **(d) C nondeterminism: 0.** + +### C property-file race (rows 4–6) + +How the cases were reproduced: +- `map2check --debug --timeout 45 --nondet-generator symex …` with `release-afl`, under the same caps. +- The kept dirs are in `$S/t42b/repro/{c-simple-ext,c-ex01,c-960}`. + +What the C runtime does: +- `write_property` (`PropertyGenerator.c:50`) does `fopen("map2check_property","w")`, then `fprintf`, then `fclose`. +- Under KLEE with `--external-calls=all`, every state shares the host file. A state that later opens the file with `"w"` (O_TRUNC) truncates the violating state's content. +- `--exit-on-error-type=Abort` then halts KLEE before that state writes anything. + +Evidence: +- `map2check_checked_error` (12 bytes) and `abort.err` are present; +- the property files are 0 bytes. + +This is the same last-writer race the Rust runtime had (task-3.3 "Cause B"). Rust fixed it in `6b49b82` (temp file + `rename`). In this window the C race is deterministic: 5 of 5 reps on each task. + +## Performance (criteria 6–9) + +| gen | n | median wall ratio Rust/C | median RSS ratio | Σ median wall C | Σ median wall Rust | TIMEOUT C | TIMEOUT Rust | +|---|---|---|---|---|---|---|---| +| afl | 41 | 1.003 | 0.987 | 165.1 s | 167.5 s | 0 | 0 | +| symex | 41 | 1.091 | 1.582 | 617.0 s | 599.7 s | 0 | 0 | +| all | 82 | **1.015** | **1.360** | 782.2 s | 767.2 s | 0 | 0 | + +- **Criterion 6 PASSES:** 1.015 ≤ 1.10. symex alone is 1.091. +- **Criterion 7 PASSES:** TIMEOUT is 0 on both sides for each generator. C additionally has 3 afl OOM rows. +- **Criterion 8 FAILS: 1.360 > 1.25.** + - Under symex, Rust uses about 80 MB more than C at the median (about 200–230 MB against 127–170 MB), and the excess is nearly constant across tasks. + - Hypothesis, not profiled: KLEE loads and `--optimize`s a 2.2 MB `map2check-klee.bc`, while the C runtime's `.bc` files total 0.13 MB. + - afl is neutral (0.987). Some afl rows sit at a plateau of about 341 MB on both sides (for example C 960521-1_1-2, test-0158); those are AFL++ process peaks, not runtime state. +- **Criterion 9:** 18 rows have a wall ratio above 1.5. Each needs a profile in `docs/cutover/perf.md`. + - 16 are symex runs where C finishes in under 2 s and Rust takes about 3.1–3.4 s. The median extra is +2.4 s on short symex tasks, which looks like a fixed start-up cost with the same probable cause as the RSS excess. + - The other two are `check_if_bug` and `ex02_false` (afl, 0.33 s → 1.45 s). + - Largest RSS outlier: split_list_test05-1 symex, 243 → 472 MB (1.94). The largest Rust peak in the whole run is 476 MB, and Rust had no OOM. + +## D3 (`--btree`) and D4 (RSS) + +valid-memsafety: 30 tasks × 2 generators. C-array and Rust have 5 reps, C-btree has 3. Peaks are medians. + +**Local corpus note.** No "5 largest MemSafety-Arrays.set tasks" set is available locally. `MemSafety-Arrays.set` (`array-memsafety/*.yml`, `array-examples/*.yml`) matches exactly 5 memsafety tasks in the corpus: relax-1 (621 lines), insertionsort-alloca-1, array01-alloca-2, lis_unsafe and add_last_unsafe. They are included in the 30. + +| gen | median C-array | median C-btree | median Rust | tasks where Rust > C-btree | max Rust/C-btree | median Rust/C-array | +|---|---|---|---|---|---|---| +| afl | 93.5 MB | 94.3 MB | 92.3 MB | 8 / 30 (the 341 MB AFL plateau) | 3.64 | 0.987 | +| symex | 139.6 MB | 136.3 MB | 221.2 MB | 30 / 30 | 3.17 (split_list_test05-1: 149 vs 472 MB) | 1.597 | + +The 5 MemSafety-Arrays tasks, symex (C-array / C-btree / Rust): + +| task | C-array | C-btree | Rust | +|---|---|---|---| +| relax-1 | 178 MB | 151 MB | 227 MB | +| add_last_unsafe | 169 MB | 136 MB | 217 MB | +| array01-alloca-2 | 169 MB | 137 MB | 239 MB | +| insertionsort-alloca-1 | 144 MB | 137 MB | 227 MB | +| lis_unsafe | 170 MB | 140 MB | 227 MB | + +**C `--btree` changes verdicts and is unsound.** Under symex it gives **3 wrong SUCCEEDED results on tasks whose expected verdict is false**: lis_unsafe, memleaks_test1-1 and memleaks_test17_2-1. It also loses list-ext (FAILED → UNKNOWN, on both generators). Correct results: afl 8 vs 9 for C-array; symex 22 correct plus 3 wrong vs 18 correct plus 0 wrong for C-array. Rust: 20 correct, 0 wrong. + +**Recommendation** + +- **D3: do not port `--btree`. Make it a no-op that prints a warning in the Rust frontend.** + - The literal Task 2.6 condition fails: Rust's peak is above C-btree on all 30 symex tasks. But that excess is a fixed overhead of about 80 MB, and the largest peak is 472 MB, far from any limit. + - The C-btree baseline is not a valid target: it is unsound on 3 tasks. + - The maintainer should approve this deviation from the literal condition explicitly. +- **D4: do not approve 1.25 as a median ratio as it stands.** The symex median of 1.58 comes from a constant overhead, not from growth with the program's state. + - Option 1: reduce the overhead first. A smaller or stripped `map2check-klee.bc` would act on start-up and RSS together, and then the gate is re-measured. + - Option 2: write D4 per generator: afl ratio ≤ 1.25, plus an absolute symex bound, for example a median excess of 100 MB or less. + +## Proposal + +- `tests/cutover/deltas-aceitos-PROPOSTA.tsv` covers only classes (a) and (b). +- It must not be merged into `deltas-aceitos.tsv` without the maintainer's approval. +- The C defects in rows 4–9 need new `SD-xx` entries ("bug do C corrigido") in `docs/semantic-deltas.md` before they can be accepted. The reproductions are given above. + +`$S` = `/tmp/claude-1000/-home-rock-Documents-Dev-map2check-library/561b38ab-d0f9-4bb7-a72d-b85b8d5834c3/scratchpad`. It holds the logs, the overlay script, the analysis script (`t42/analyse.py`) and the reproduction dirs. From 4f937db0feeea7c2e96d8cdc8a7fac03878d8911 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 22:03:05 -0400 Subject: [PATCH 30/44] test: approve gate deltas and raise the RSS limit to 1.36 (D4) --- scripts/cutover/compare.py | 2 +- tests/cutover/deltas-aceitos-PROPOSTA.tsv | 7 ------- tests/cutover/deltas-aceitos.tsv | 19 ++++++++++++++++++ tests/cutover/gate-report.md | 24 +++++++++++++++++++++++ 4 files changed, 44 insertions(+), 8 deletions(-) delete mode 100644 tests/cutover/deltas-aceitos-PROPOSTA.tsv diff --git a/scripts/cutover/compare.py b/scripts/cutover/compare.py index 78c779974..7bef6d2e7 100644 --- a/scripts/cutover/compare.py +++ b/scripts/cutover/compare.py @@ -29,7 +29,7 @@ def main(): ap.add_argument("c"); ap.add_argument("rust") ap.add_argument("--accepted", required=True) ap.add_argument("--max-wall", type=float, default=1.10) - ap.add_argument("--max-rss", type=float, default=1.25) + ap.add_argument("--max-rss", type=float, default=1.36) a = ap.parse_args() c, r = load(a.c), load(a.rust) accepted = set() diff --git a/tests/cutover/deltas-aceitos-PROPOSTA.tsv b/tests/cutover/deltas-aceitos-PROPOSTA.tsv deleted file mode 100644 index 52ba47d93..000000000 --- a/tests/cutover/deltas-aceitos-PROPOSTA.tsv +++ /dev/null @@ -1,7 +0,0 @@ -task prp gen field c_value rust_value sd_ref -ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex verdict UNKNOWN SUCCEEDED GANHO-ORCAMENTO -memsafety/960521-1-2.yml valid-memsafety symex verdict UNKNOWN SUCCEEDED GANHO-ORCAMENTO -list-ext-properties/list-ext.yml unreach-call afl verdict UNKNOWN FAILED UB-BENCHMARK-list-ext -list-ext-properties/list-ext.yml unreach-call afl tag - TARGET-REACHED UB-BENCHMARK-list-ext -list-ext-properties/list-ext.yml unreach-call afl line - 556 UB-BENCHMARK-list-ext -list-ext-properties/list-ext.yml unreach-call afl function - main UB-BENCHMARK-list-ext diff --git a/tests/cutover/deltas-aceitos.tsv b/tests/cutover/deltas-aceitos.tsv index 1a3be47f8..4bab5ec10 100644 --- a/tests/cutover/deltas-aceitos.tsv +++ b/tests/cutover/deltas-aceitos.tsv @@ -1 +1,20 @@ task prp gen field c_value rust_value sd_ref +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex verdict UNKNOWN SUCCEEDED GANHO-ORCAMENTO +memsafety/960521-1-2.yml valid-memsafety symex verdict UNKNOWN SUCCEEDED GANHO-ORCAMENTO +list-ext-properties/list-ext.yml unreach-call afl verdict UNKNOWN FAILED UB-BENCHMARK-list-ext +list-ext-properties/list-ext.yml unreach-call afl tag - TARGET-REACHED UB-BENCHMARK-list-ext +list-ext-properties/list-ext.yml unreach-call afl line - 556 UB-BENCHMARK-list-ext +list-ext-properties/list-ext.yml unreach-call afl function - main UB-BENCHMARK-list-ext +array-examples/standard_sentinel-2.yml unreach-call afl verdict OOM UNKNOWN C-BUG-oom-afl-nondet +array-examples/standard_two_index_04.yml unreach-call afl verdict OOM UNKNOWN C-BUG-oom-afl-nondet +array-examples/standard_two_index_05.yml unreach-call afl verdict OOM UNKNOWN C-BUG-oom-afl-nondet +list-ext-properties/960521-1_1-1.yml valid-memsafety symex line 0 533 C-BUG-property-race +list-ext-properties/960521-1_1-1.yml valid-memsafety symex function - main C-BUG-property-race +list-ext-properties/simple-ext.yml unreach-call symex verdict UNKNOWN FAILED C-BUG-property-race +list-ext-properties/simple-ext.yml unreach-call symex tag - TARGET-REACHED C-BUG-property-race +list-ext-properties/simple-ext.yml unreach-call symex line - 540 C-BUG-property-race +list-ext-properties/simple-ext.yml unreach-call symex function - main C-BUG-property-race +map2check-assert/ex01_false.yml unreach-call symex verdict UNKNOWN FAILED C-BUG-property-race +map2check-assert/ex01_false.yml unreach-call symex tag - TARGET-REACHED C-BUG-property-race +map2check-assert/ex01_false.yml unreach-call symex line - 5 C-BUG-property-race +map2check-assert/ex01_false.yml unreach-call symex function - __VERIFIER_assert C-BUG-property-race diff --git a/tests/cutover/gate-report.md b/tests/cutover/gate-report.md index e32aadbe5..68fe7b418 100644 --- a/tests/cutover/gate-report.md +++ b/tests/cutover/gate-report.md @@ -192,3 +192,27 @@ The 5 MemSafety-Arrays tasks, symex (C-array / C-btree / Rust): - The C defects in rows 4–9 need new `SD-xx` entries ("bug do C corrigido") in `docs/semantic-deltas.md` before they can be accepted. The reproductions are given above. `$S` = `/tmp/claude-1000/-home-rock-Documents-Dev-map2check-library/561b38ab-d0f9-4bb7-a72d-b85b8d5834c3/scratchpad`. It holds the logs, the overlay script, the analysis script (`t42/analyse.py`) and the reproduction dirs. + +## Decisões do mantenedor (2026-10-16) + +1. **Deltas: "Aceitar tudo".** + - As 6 linhas da PROPOSTA (GANHO-ORCAMENTO e UB-BENCHMARK-list-ext) foram aprovadas. + - Foram acrescentadas 13 linhas por bugs do runtime C: + - `C-BUG-property-race` (10 linhas): o arquivo `map2check_property` compartilhado é truncado por outros estados do KLEE, e o frontend do C dá UNKNOWN (simple-ext, ex01_false) ou lê "Line 0"/função vazia (960521-1_1-1). Os campos verdict/tag/line/function de simple-ext e ex01_false e line/function de 960521-1_1-1. + - `C-BUG-oom-afl-nondet` (3 linhas): o C estoura os 3 GB nas três tarefas `standard_*` em afl (Rust, cerca de 341 MB). A causa (crescimento do NonDetLog por chamada) é hipótese, não perfilada. + - Todas as divergências de campo listadas neste relatório ficaram cobertas. Nenhuma ficou sem causa. As entradas correspondentes em `docs/semantic-deltas.md` (map2check-library) ainda precisam ser escritas. + - `deltas-aceitos-PROPOSTA.tsv` foi removido; `deltas-aceitos.tsv` tem 19 linhas de dados. +2. **D3:** `--btree` não é portado; continua um no-op com aviso. O `--btree` do C dá SUCCEEDED errado em lis_unsafe, memleaks_test1-1 e memleaks_test17_2-1, então não é referência válida. O mantenedor aprovou se afastar da condição literal da Task 2.6. +3. **D4:** aceita a razão mediana medida. O limite do critério 8 passa a ser **1,36** (medido 1,36; afl 0,99, symex 1,58). `compare.py` usa `--max-rss` 1.36 por padrão. Causa (KLEE com `.bc` do runtime de 2,2 MB contra 0,13 MB): hipótese, não perfilada. +4. **Critério 9 continua ABERTO:** as 18 linhas com razão de tempo de parede acima de 1,5 ainda precisam de perfil em `docs/cutover/perf.md`. Não foi feito. + +### Novo veredito + +``` +$ python3 scripts/cutover/compare.py tests/cutover/baseline-c-gate.tsv tests/cutover/baseline-rust.tsv --accepted tests/cutover/deltas-aceitos.tsv +median wall ratio: 1.015 median rss ratio: 1.360 + +gate: PASS +``` + +O `gate` (critérios 1–8) passa. O critério 9 segue pendente. `test_compare.py`: 6 de 6 testes passam. From 33e3b00512c35c9516a93e633f4f88bb62868b05 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 22:22:56 -0400 Subject: [PATCH 31/44] test: record the criterion 9 profiles of the 18 rows above 1.5 wall 15 symex rows: KLEE spends about 2.6 s before the first instruction on the 2.3 MB runtime module (about 1.9 s of it in --optimize); exploration is as fast as C or faster. Deleting the std backtrace symbolizer bodies halves that start-up and lowers KLEE's peak RSS from 221 to 161 MB. 2 afl rows: C's AFL++ link fails on __VERIFIER_assert and skips fuzzing, Rust fuzzes and hits AFL++'s 1 s dry-run timeout. list-ext afl: extra fuzzing that finds the target (accepted delta). --- tests/cutover/gate-report.md | 135 +++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/tests/cutover/gate-report.md b/tests/cutover/gate-report.md index 68fe7b418..59b9299b1 100644 --- a/tests/cutover/gate-report.md +++ b/tests/cutover/gate-report.md @@ -216,3 +216,138 @@ gate: PASS ``` O `gate` (critérios 1–8) passa. O critério 9 segue pendente. `test_compare.py`: 6 de 6 testes passam. + +## Critério 9 — perfis + +Gate run 1 has 18 rows with a wall ratio (Rust/C, medians of 5 reps) above 1.5: **15 symex and 3 afl**. The earlier count of "16 symex + 2 afl" in this report was wrong, because list-ext afl is at 1.56. Every row falls into one of three cause groups. + +### How the profiles were taken + +- **Same images, installs and caps as the gate:** + - `release-gate2` in `cutover-klee-rust-time`; + - `release-afl` in `cutover-f01e8c3e-time`; + - `--memory 3g --memory-swap 3g --cpus 4`, KLEE `--max-memory=2000`; + - `free -g` showed 4 GB or more available before each container. +- **Phase times:** the overlay install wraps every `bin/*` tool (clang, opt, llvm-link, klee) with a timer, and the `--debug` output is timestamped line by line. The AFL++ phases are read from those timestamps. +- **KLEE breakdown:** + - `klee-stats --to-csv` on `klee-out-0`. The `UserTime` of the first `run.stats` row is the CPU spent before the first instruction runs; the final row gives the exploration `WallTime` and `SolverTime`. + - KLEE re-run alone on the kept `-witness-result.bc` with flags removed one at a time. + - Host `perf record -g -p` on KLEE inside the container (run as the host uid), with symbols from the image's `libLLVM-16.so.1` via `--symfs`. +- **Scripts:** `$S/c9/` (`prof.sh`, `kvar2.sh`, `dropbt.sh`, `rssbt.sh`, `perfk.sh`, `ksum.sh`). +- **Kept run directories:** `$S/c9/runs/` and `$S/c9/runs2/`. + +### Group A: KLEE start-up on the 2.3 MB runtime module (15 symex rows) + +**Measured.** +- **What it is:** a fixed cost of about 2.6–2.7 s per KLEE run, before any instruction executes. +- **What it is not:** path count, the solver, or per-path cost in the runtime. +- **The C rows that take longer** (1–2.6 s) show a smaller delta, because Rust's exploration is faster there (the 2.7b gain) and absorbs part of the fixed cost. + +KLEE profiles (`klee` = wall time of the KLEE process; `pre_exec` = `UserTime` before the first instruction): + +| run | side | klee s | pre_exec s | exploration wall s | solver s | instructions | paths | +|---|---|---|---|---|---|---|---| +| byte_add_bug | Rust | 2.93 | 2.63 | 0.11 | 0.00 | 46 186 | 1 | +| byte_add_bug | C | 0.29 | 0.22 | 0.03 | 0.00 | 19 658 | 1 | +| test-bitfields-3.1-2 | Rust | 3.17 | 2.88 | 0.12 | 0.00 | 34 356 | 1 | +| test-bitfields-3.1-2 | C | 0.31 | 0.23 | 0.03 | 0.00 | 30 180 | 1 | +| 960521-1_1-3 | Rust | 3.35 | 2.85 | 0.35 | 0.07 | 471 187 | 15 | +| 960521-1_1-3 | C | 1.67 | 0.23 | 1.40 | 0.09 | 3 457 247 | 19 | +| insertionsort-alloca-1 | Rust | 3.35 | 2.90 | 0.29 | 0.05 | 406 655 | 4 | +| insertionsort-alloca-1 | C | 1.49 | 0.24 | 1.20 | 0.04 | 3 629 574 | 4 | +| ex01_false | Rust | 4.86 | 2.88 | 1.82 | 1.55 | 233 479 | 165 | +| ex01_false | C | 2.55 | 0.22 | 2.28 | 2.00 | 317 741 | 199 | + +**Other pipeline phases:** +- clang, opt and the frontend take under 0.1 s on both sides. +- Rust's single `llvm-link` with `map2check-klee.bc` takes 0.18–0.19 s, against 2 × 0.015 s for C's links of the C `.bc` files. + +**Where the start-up goes** (byte_add_bug, KLEE alone on the kept module, 2 runs each): + +| variant | Rust s | C s | +|---|---|---| +| as in the gate (`--optimize`) | 3.14 | 0.29 | +| without `--optimize` | 1.22 | 0.27 | +| without `--optimize`, `--max-instructions=1` | 1.12 | 0.25 | +| `--optimize`, without `assembly.ll` and `run.istats` | 3.02 | 0.28 | +| `--optimize`, debug info stripped from the whole module | 3.07–3.14 | – | +| `--optimize`, internalize + globaldce (2.05 MB) | 2.95–3.07 | – | +| `--optimize`, **std backtrace symbolizer bodies deleted** (1.44 MB) | **1.47–1.53** | – | +| same, without `--optimize` | 0.75–0.77 | – | + +- **`--optimize` is about 1.9 s.** + - The `perf` profile is 81.5% in `libLLVM-16`. + - The top symbols are LLVM optimization passes: `ScalarEvolution::getRangeRef`, `InstructionCombiningPass::runOnFunction`, `ValueHandleBase::AddToUseList`, `decomposeBitTestICmp` and `FoldingSet`. + - KLEE re-optimizes a runtime that rustc already built at O3 with fat LTO. +- **Loading, linking with uclibc and module preparation are about 0.9 s.** + - Without `--optimize`, 64% of the samples are in `libLLVM-16` (bitcode reader, `TypeFinder`, `IRMover`, `formatted_raw_ostream`) and 29% are in `ld-linux`. +- **What the module holds:** + - The kept `-witness-result.bc` has 583 defined functions, 7 371 branches and an 11 MB `assembly.ll`. C's has 80 functions, 478 branches and 2.2 MB. + - Of the runtime's 125 829 IR instructions, about 60 000 are std's backtrace symbolizer, pulled in by the default panic hook: gimli, addr2line and miniz_oxide (52 806) plus rustc_demangle (7 299). + - The library itself is 30 896 instructions. + - The symbolizer code never runs on a non-panicking path. With its bodies deleted, KLEE's instruction count is unchanged (45 184 against 45 176) and the result is the same. +- **RSS:** the same deletion lowers KLEE's peak RSS from 221 MB to 161 MB (C: 127 MB). That is about 60 of the 94 MB symex excess behind D4. + +**Library defect: reported, not fixed.** See the task-4.3 criterion 9 report in map2check-library for the suggested fix. + +### Group B: C skips AFL++ because its link fails; Rust runs it (2 afl rows) + +**Measured.** Rows: check_if_bug and ex02_false (unreach-call, afl). Both sides say UNKNOWN. + +**C** (0.36 s): +- All three `afl-clang-fast` links fail with `undefined reference to '__VERIFIER_assert'`. The C runtime does not define it. +- The frontend prints "the AFL++ binary is unavailable -- skipping the fuzzer phase" at 0.356 s and reports UNKNOWN. + +**Rust** (1.48 s): +- The three AFL++ binaries build: 0.11 s → 0.45 s. +- `afl-fuzz` then runs for 1.03 s and exits with 256, on "The program took more than 1000 ms to process one of the initial test cases". +- The seed `AAAAAAAA` makes the loop bound `0x41414141`, so the dry run reaches AFL++'s 1 s timeout. + +**Conclusion:** the extra 1.1 s is a fuzzing phase that C never reaches. It is not runtime cost. The C link failure is a C-side defect outside this gate's field comparison, because the verdicts are equal. + +### Group C: a different verdict, from extra work that pays off (1 afl row) + +**Measured.** Row: list-ext (unreach-call, afl): C UNKNOWN 0.53 s, Rust FAILED 0.79 s. This is the accepted `UB-BENCHMARK-list-ext` delta. + +| phase | C | Rust | +|---|---|---| +| AFL++ builds | 0.28 s | 0.34 s | +| `afl-fuzz` | 0.08 s, exit 256 | 0.26 s, exit 0 (finds the target) | +| report | – | witness and replay | + +- The +0.28 s is the work of reaching FAILED TARGET-REACHED. +- The RSS of 340 MB is the AFL++ process plateau already noted above. + +### Per-row table + +R−C is the difference of the median wall times. "profiled" marks a row with its own profile above; the other rows are assigned by the same signature. +- **Group A signature:** Rust at 3.1–3.4 s whatever C's time, and R−C between +1.6 and +2.9 s, falling as C's exploration time grows. +- **Group B signature:** both UNKNOWN, C at about 0.33 s. + +| task | gen | ratio | cause group | evidence | +|---|---|---|---|---| +| ldv-memsafety-bitfields/test-bitfields-3.1-2 (memsafety) | symex | 9.17 | A: KLEE start-up | profiled: pre_exec 2.88 s vs 0.23 s; exploration 0.12 s vs 0.03 s; R−C +2.86 s | +| map2check-assert/byte_add_bug (unreach) | symex | 8.81 | A | profiled: pre_exec 2.63 s vs 0.22 s; 0 queries, 1 path; `perf`, flag ablation and symbolizer deletion done on this row; R−C +2.81 s | +| ldv-memsafety/memsetNonZero (memsafety) | symex | 8.38 | A | R−C +2.73 s; Rust 3.10 s | +| ldv-memsafety-bitfields/test-bitfields-1-1 (memsafety) | symex | 7.36 | A | R−C +2.67 s; Rust 3.09 s | +| list-ext-properties/simple-ext (unreach) | symex | 7.24 | A (verdict differs: C-BUG-property-race) | R−C +2.81 s; Rust 3.26 s; C stops at UNKNOWN in 0.45 s because of the race (SD-20) | +| ldv-memsafety-bitfields/test-bitfields-2.1-2 (memsafety) | symex | 6.62 | A | R−C +2.64 s; Rust 3.11 s | +| list-ext-properties/test-0158_1-1 (memsafety) | symex | 6.20 | A | R−C +2.65 s; Rust 3.16 s | +| list-ext-properties/test-0019_1-1 (memsafety) | symex | 5.46 | A | R−C +2.63 s; Rust 3.22 s | +| check_if_bug (unreach) | afl | 4.39 | B: C skips AFL++ | profiled: C link fails on `__VERIFIER_assert` at 0.36 s; Rust `afl-fuzz` dry-run timeout of 1.03 s; R−C +1.12 s | +| ex02_false (unreach) | afl | 4.24 | B | profiled: same as check_if_bug; R−C +1.10 s | +| list-ext-properties/simple-ext (memcleanup) | symex | 3.46 | A | R−C +2.36 s; Rust 3.32 s | +| memsafety/960521-1-3 (memsafety) | symex | 3.43 | A | R−C +2.38 s; Rust 3.36 s | +| memsafety/960521-1-1 (memsafety) | symex | 3.29 | A | R−C +2.29 s; Rust 3.29 s | +| list-ext-properties/960521-1_1-1 (memsafety) | symex | 2.12 | A | R−C +1.78 s; Rust 3.37 s; same program family as 960521-1_1-3 | +| list-ext-properties/960521-1_1-3 (memsafety) | symex | 2.01 | A | profiled: pre_exec 2.85 s vs 0.23 s; exploration 0.35 s vs 1.40 s (Rust 7× fewer instructions); R−C +1.73 s | +| array-memsafety/insertionsort-alloca-1 (memsafety) | symex | 1.97 | A | profiled: pre_exec 2.90 s vs 0.24 s; exploration 0.29 s vs 1.20 s; R−C +1.60 s | +| map2check-assert/ex01_false (unreach) | symex | 1.88 | A (verdict differs: C-BUG-property-race) | profiled: pre_exec 2.88 s vs 0.22 s; exploration 1.82 s vs 2.28 s, solver 1.55 s vs 2.00 s; R−C +2.27 s | +| list-ext-properties/list-ext (unreach) | afl | 1.56 | C: extra work for a better verdict | profiled: `afl-fuzz` 0.26 s (finds the target) vs 0.08 s; FAILED vs UNKNOWN (UB-BENCHMARK-list-ext); R−C +0.28 s | + +**Totals:** A = 15 rows, B = 2, C = 1. +- No row shows a per-path or per-call cost in the runtime. +- No row shows solver time above C's. +- Every profiled exploration phase is as fast as C's or faster. + +**Criterion 9:** criteria 6 and 7 pass, so none of the 18 rows blocks. All 18 now have a recorded cause. The plan names `docs/cutover/perf.md` as the place for these profiles. That file does not exist yet in either repository, so the profiles are recorded here. From c57fef52068e49f5dddbb0c06ecae7253b3a6316 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Fri, 16 Oct 2026 23:44:32 -0400 Subject: [PATCH 32/44] test: re-run the Rust symex gate with the slimmed KLEE runtime --- tests/cutover/baseline-rust-symex-slim.tsv | 206 +++++++++++ tests/cutover/baseline-rust-v2.tsv | 411 +++++++++++++++++++++ tests/cutover/gate-report.md | 34 ++ 3 files changed, 651 insertions(+) create mode 100644 tests/cutover/baseline-rust-symex-slim.tsv create mode 100644 tests/cutover/baseline-rust-v2.tsv diff --git a/tests/cutover/baseline-rust-symex-slim.tsv b/tests/cutover/baseline-rust-symex-slim.tsv new file mode 100644 index 000000000..f31c172cd --- /dev/null +++ b/tests/cutover/baseline-rust-symex-slim.tsv @@ -0,0 +1,206 @@ +task prp gen rep verdict tag line function witness wall_s maxrss_kb +array-examples/relax-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.73 173312 +array-examples/relax-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.68 174236 +array-examples/relax-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.72 174264 +array-examples/relax-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.73 174372 +array-examples/relax-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.73 173644 +array-examples/standard_sentinel-2.yml unreach-call symex 1 UNKNOWN - - - 0 32.52 207684 +array-examples/standard_sentinel-2.yml unreach-call symex 2 UNKNOWN - - - 0 32.52 208052 +array-examples/standard_sentinel-2.yml unreach-call symex 3 UNKNOWN - - - 0 32.50 210292 +array-examples/standard_sentinel-2.yml unreach-call symex 4 UNKNOWN - - - 0 32.47 207876 +array-examples/standard_sentinel-2.yml unreach-call symex 5 UNKNOWN - - - 0 32.46 208272 +array-examples/standard_two_index_04.yml unreach-call symex 1 UNKNOWN - - - 0 32.50 208936 +array-examples/standard_two_index_04.yml unreach-call symex 2 UNKNOWN - - - 0 32.51 211456 +array-examples/standard_two_index_04.yml unreach-call symex 3 UNKNOWN - - - 0 32.49 210104 +array-examples/standard_two_index_04.yml unreach-call symex 4 UNKNOWN - - - 0 32.52 209684 +array-examples/standard_two_index_04.yml unreach-call symex 5 UNKNOWN - - - 0 32.52 208500 +array-examples/standard_two_index_05.yml unreach-call symex 1 UNKNOWN - - - 0 32.46 208960 +array-examples/standard_two_index_05.yml unreach-call symex 2 UNKNOWN - - - 0 32.52 208820 +array-examples/standard_two_index_05.yml unreach-call symex 3 UNKNOWN - - - 0 32.45 209412 +array-examples/standard_two_index_05.yml unreach-call symex 4 UNKNOWN - - - 0 32.48 208460 +array-examples/standard_two_index_05.yml unreach-call symex 5 UNKNOWN - - - 0 32.48 209004 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 1 FAILED FALSE-DEREF 522 main 0 1.53 172764 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 2 FAILED FALSE-DEREF 522 main 0 1.55 172712 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 3 FAILED FALSE-DEREF 522 main 0 1.54 172372 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 4 FAILED FALSE-DEREF 522 main 0 1.56 174524 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 5 FAILED FALSE-DEREF 522 main 0 1.58 171772 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.59 192832 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.56 197836 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.58 192304 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.52 198024 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.64 199776 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.54 172988 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.58 172652 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.58 172780 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.52 172816 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.52 172516 +array-memsafety/lis_unsafe.yml valid-memsafety symex 1 UNKNOWN - - - 0 1.49 172324 +array-memsafety/lis_unsafe.yml valid-memsafety symex 2 UNKNOWN - - - 0 1.50 172840 +array-memsafety/lis_unsafe.yml valid-memsafety symex 3 UNKNOWN - - - 0 1.58 172976 +array-memsafety/lis_unsafe.yml valid-memsafety symex 4 UNKNOWN - - - 0 1.48 172932 +array-memsafety/lis_unsafe.yml valid-memsafety symex 5 UNKNOWN - - - 0 1.43 173044 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.48 156448 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.37 156472 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.36 156248 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.37 156608 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.42 166712 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 1 FAILED FALSE-FREE 46 main 0 1.40 167056 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 2 FAILED FALSE-FREE 46 main 0 1.39 156656 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 3 FAILED FALSE-FREE 46 main 0 1.40 166804 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 4 FAILED FALSE-FREE 46 main 0 1.38 156880 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 5 FAILED FALSE-FREE 46 main 0 1.38 156768 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 1.39 165244 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 1.35 155136 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 1.35 155136 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 1.36 154780 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 1.36 155724 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 1 SUCCEEDED - - - 0 20.08 157112 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 2 SUCCEEDED - - - 0 20.57 157660 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 3 SUCCEEDED - - - 0 20.87 157536 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 4 SUCCEEDED - - - 0 20.60 156952 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 5 SUCCEEDED - - - 0 19.56 158040 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.32 157232 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.35 155648 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.37 157124 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.36 157036 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.36 156184 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 1.68 164192 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 1.67 167496 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 1.60 165896 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 1.62 164944 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 1.66 165456 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 2.34 165980 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 2.32 167504 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 2.41 166108 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 2.27 165988 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 2.31 165840 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 779 free_17 0 2.66 167252 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 779 free_17 0 2.67 167372 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 779 free_17 0 2.69 167076 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 779 free_17 0 2.64 167188 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 779 free_17 0 2.72 167888 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.61 165720 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.62 165068 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.62 164252 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.69 165232 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.68 164884 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.34 155332 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.38 155912 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.34 156212 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.38 155908 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.37 155828 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 533 main 0 1.53 173048 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 533 main 0 1.55 173252 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 533 main 0 1.54 172800 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 533 main 0 1.55 172176 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 533 main 0 1.55 173048 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.93 173684 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.97 172928 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.93 173900 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 4.09 164948 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.91 165244 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 1 FAILED FALSE-FREE 536 main 0 1.54 172412 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 2 FAILED FALSE-FREE 536 main 0 1.57 172328 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 3 FAILED FALSE-FREE 536 main 0 1.56 172712 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 4 FAILED FALSE-FREE 536 main 0 1.53 173140 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 5 FAILED FALSE-FREE 536 main 0 1.59 172932 +list-ext-properties/list-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 556 main 0 1.50 166172 +list-ext-properties/list-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 556 main 0 1.52 166452 +list-ext-properties/list-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 556 main 0 1.50 172356 +list-ext-properties/list-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 556 main 0 1.51 165164 +list-ext-properties/list-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 556 main 0 1.48 165580 +list-ext-properties/list-ext.yml valid-memsafety symex 1 FAILED FALSE-DEREF 558 main 0 6.22 174248 +list-ext-properties/list-ext.yml valid-memsafety symex 2 FAILED FALSE-DEREF 558 main 0 6.56 168228 +list-ext-properties/list-ext.yml valid-memsafety symex 3 FAILED FALSE-DEREF 558 main 0 6.62 167960 +list-ext-properties/list-ext.yml valid-memsafety symex 4 FAILED FALSE-DEREF 558 main 0 6.52 176644 +list-ext-properties/list-ext.yml valid-memsafety symex 5 FAILED FALSE-DEREF 558 main 0 6.49 167436 +list-ext-properties/simple-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 540 main 0 1.44 162916 +list-ext-properties/simple-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 540 main 0 1.41 165244 +list-ext-properties/simple-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 540 main 0 1.43 162688 +list-ext-properties/simple-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 540 main 0 1.42 163680 +list-ext-properties/simple-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 540 main 0 1.47 162788 +list-ext-properties/simple-ext.yml valid-memcleanup symex 1 UNKNOWN - - - 0 1.52 162836 +list-ext-properties/simple-ext.yml valid-memcleanup symex 2 UNKNOWN - - - 0 1.52 163460 +list-ext-properties/simple-ext.yml valid-memcleanup symex 3 UNKNOWN - - - 0 1.58 163724 +list-ext-properties/simple-ext.yml valid-memcleanup symex 4 UNKNOWN - - - 0 1.55 171836 +list-ext-properties/simple-ext.yml valid-memcleanup symex 5 UNKNOWN - - - 0 1.57 163576 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 1.44 156960 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 1.40 156508 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 1.41 157092 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 1.40 168888 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 1.43 159220 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.38 163912 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.42 164156 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.39 164080 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.42 172680 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.40 172856 +map2check-assert/array_bug.yml unreach-call symex 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.40 163752 +map2check-assert/array_bug.yml unreach-call symex 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.36 163816 +map2check-assert/array_bug.yml unreach-call symex 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.40 163004 +map2check-assert/array_bug.yml unreach-call symex 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.38 163468 +map2check-assert/array_bug.yml unreach-call symex 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.36 163700 +map2check-assert/byte_add_bug.yml unreach-call symex 1 SUCCEEDED - - - 0 1.32 155760 +map2check-assert/byte_add_bug.yml unreach-call symex 2 SUCCEEDED - - - 0 1.34 155828 +map2check-assert/byte_add_bug.yml unreach-call symex 3 SUCCEEDED - - - 0 1.37 155308 +map2check-assert/byte_add_bug.yml unreach-call symex 4 SUCCEEDED - - - 0 1.35 158528 +map2check-assert/byte_add_bug.yml unreach-call symex 5 SUCCEEDED - - - 0 1.38 155868 +map2check-assert/check_if_bug.yml unreach-call symex 1 UNKNOWN - - - 0 32.96 208548 +map2check-assert/check_if_bug.yml unreach-call symex 2 UNKNOWN - - - 0 32.81 210100 +map2check-assert/check_if_bug.yml unreach-call symex 3 UNKNOWN - - - 0 32.88 210860 +map2check-assert/check_if_bug.yml unreach-call symex 4 UNKNOWN - - - 0 32.89 210624 +map2check-assert/check_if_bug.yml unreach-call symex 5 UNKNOWN - - - 0 32.88 206772 +map2check-assert/ex01_false.yml unreach-call symex 1 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 2.99 171952 +map2check-assert/ex01_false.yml unreach-call symex 2 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 3.08 172292 +map2check-assert/ex01_false.yml unreach-call symex 3 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 3.00 172088 +map2check-assert/ex01_false.yml unreach-call symex 4 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 2.95 171892 +map2check-assert/ex01_false.yml unreach-call symex 5 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 2.99 172100 +map2check-assert/ex02_false.yml unreach-call symex 1 UNKNOWN - - - 0 32.39 207772 +map2check-assert/ex02_false.yml unreach-call symex 2 UNKNOWN - - - 0 32.41 207624 +map2check-assert/ex02_false.yml unreach-call symex 3 UNKNOWN - - - 0 32.35 207188 +map2check-assert/ex02_false.yml unreach-call symex 4 UNKNOWN - - - 0 32.39 210016 +map2check-assert/ex02_false.yml unreach-call symex 5 UNKNOWN - - - 0 32.35 207744 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 33.80 201364 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 33.96 201188 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 33.94 206540 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 33.80 206864 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 33.82 201788 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.67 244192 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.66 247596 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.71 244184 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.71 244892 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.66 244356 +memsafety-ext/tree_stack.yml valid-memsafety symex 1 UNKNOWN - - - 0 33.05 282904 +memsafety-ext/tree_stack.yml valid-memsafety symex 2 UNKNOWN - - - 0 33.04 281920 +memsafety-ext/tree_stack.yml valid-memsafety symex 3 UNKNOWN - - - 0 33.00 283976 +memsafety-ext/tree_stack.yml valid-memsafety symex 4 UNKNOWN - - - 0 33.00 283912 +memsafety-ext/tree_stack.yml valid-memsafety symex 5 UNKNOWN - - - 0 33.02 283452 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.36 173904 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.36 173472 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.36 173644 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.37 176272 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.34 176780 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 33.74 445396 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 33.75 443952 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 33.73 443568 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 33.69 442876 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 33.76 443648 +memsafety/960521-1-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 532 main 0 1.48 157108 +memsafety/960521-1-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 532 main 0 1.49 156932 +memsafety/960521-1-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 532 main 0 1.45 156568 +memsafety/960521-1-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 532 main 0 1.44 156420 +memsafety/960521-1-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 532 main 0 1.49 156984 +memsafety/960521-1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 27.02 156344 +memsafety/960521-1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 27.23 157812 +memsafety/960521-1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 27.05 167368 +memsafety/960521-1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 25.56 157724 +memsafety/960521-1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 25.93 156576 +memsafety/960521-1-3.yml valid-memsafety symex 1 FAILED FALSE-DEREF 529 main 0 1.47 166892 +memsafety/960521-1-3.yml valid-memsafety symex 2 FAILED FALSE-DEREF 529 main 0 1.49 157004 +memsafety/960521-1-3.yml valid-memsafety symex 3 FAILED FALSE-DEREF 529 main 0 1.50 157872 +memsafety/960521-1-3.yml valid-memsafety symex 4 FAILED FALSE-DEREF 529 main 0 1.47 157236 +memsafety/960521-1-3.yml valid-memsafety symex 5 FAILED FALSE-DEREF 529 main 0 1.48 157312 +memsafety/test-0102-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.53 240364 +memsafety/test-0102-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.49 240192 +memsafety/test-0102-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.53 240600 +memsafety/test-0102-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.52 240936 +memsafety/test-0102-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.53 240944 diff --git a/tests/cutover/baseline-rust-v2.tsv b/tests/cutover/baseline-rust-v2.tsv new file mode 100644 index 000000000..6535d76a1 --- /dev/null +++ b/tests/cutover/baseline-rust-v2.tsv @@ -0,0 +1,411 @@ +task prp gen rep verdict tag line function witness wall_s maxrss_kb +array-examples/relax-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.60 92376 +array-examples/relax-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.61 92200 +array-examples/relax-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.60 92280 +array-examples/relax-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.62 91984 +array-examples/relax-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.62 92292 +array-examples/standard_sentinel-2.yml unreach-call afl 1 UNKNOWN - - - 0 9.44 340960 +array-examples/standard_sentinel-2.yml unreach-call afl 2 UNKNOWN - - - 0 9.44 340724 +array-examples/standard_sentinel-2.yml unreach-call afl 3 UNKNOWN - - - 0 9.44 340924 +array-examples/standard_sentinel-2.yml unreach-call afl 4 UNKNOWN - - - 0 9.44 341064 +array-examples/standard_sentinel-2.yml unreach-call afl 5 UNKNOWN - - - 0 9.45 340992 +array-examples/standard_two_index_04.yml unreach-call afl 1 UNKNOWN - - - 0 9.45 340996 +array-examples/standard_two_index_04.yml unreach-call afl 2 UNKNOWN - - - 0 9.43 340984 +array-examples/standard_two_index_04.yml unreach-call afl 3 UNKNOWN - - - 0 9.44 341364 +array-examples/standard_two_index_04.yml unreach-call afl 4 UNKNOWN - - - 0 9.45 340864 +array-examples/standard_two_index_04.yml unreach-call afl 5 UNKNOWN - - - 0 9.44 340900 +array-examples/standard_two_index_05.yml unreach-call afl 1 UNKNOWN - - - 0 9.44 341016 +array-examples/standard_two_index_05.yml unreach-call afl 2 UNKNOWN - - - 0 9.44 340944 +array-examples/standard_two_index_05.yml unreach-call afl 3 UNKNOWN - - - 0 9.43 340928 +array-examples/standard_two_index_05.yml unreach-call afl 4 UNKNOWN - - - 0 9.44 341204 +array-examples/standard_two_index_05.yml unreach-call afl 5 UNKNOWN - - - 0 9.46 341212 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 0.61 92192 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.59 91832 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.60 92108 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.60 92280 +array-memsafety/add_last_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.59 92028 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91788 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 91876 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 92148 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.46 92004 +array-memsafety/array01-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.45 92240 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.90 340820 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 0.76 341148 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 0.76 341056 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 0.76 340828 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 0.76 341056 +array-memsafety/lis_unsafe.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91876 +array-memsafety/lis_unsafe.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 91660 +array-memsafety/lis_unsafe.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 91904 +array-memsafety/lis_unsafe.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 91852 +array-memsafety/lis_unsafe.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 91668 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.43 340980 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 340772 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 340900 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341432 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 340964 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 1 FAILED FALSE-FREE 46 main 0 0.61 91428 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 2 FAILED FALSE-FREE 46 main 0 0.59 92228 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 3 FAILED FALSE-FREE 46 main 0 0.60 91428 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 4 FAILED FALSE-FREE 46 main 0 0.60 91556 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety afl 5 FAILED FALSE-FREE 46 main 0 0.59 91240 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 340784 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 340948 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.43 341176 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 341272 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 341288 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 341132 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 341012 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.45 341116 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 341420 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 341164 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91448 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 91176 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 91672 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.48 90948 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.46 91672 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.67 92496 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.67 91944 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.68 92420 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.70 92432 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.70 93132 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.56 341196 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.55 341132 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.53 340604 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.54 340808 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.55 341076 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 779 free_17 0 0.72 92688 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 779 free_17 0 0.69 92540 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 779 free_17 0 0.71 93060 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 779 free_17 0 0.71 93024 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 779 free_17 0 0.70 92632 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.53 341144 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.52 341132 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.53 340956 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.55 340836 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.54 340592 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.44 340996 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.44 340508 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 340720 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.43 341112 +ldv-memsafety/memsetNonZero.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 340772 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 1 FAILED FALSE-DEREF 533 main 0 0.61 92052 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 2 FAILED FALSE-DEREF 533 main 0 0.60 91640 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 3 FAILED FALSE-DEREF 533 main 0 0.59 92072 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 4 FAILED FALSE-DEREF 533 main 0 0.61 91812 +list-ext-properties/960521-1_1-1.yml valid-memsafety afl 5 FAILED FALSE-DEREF 533 main 0 0.61 91772 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 340940 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.51 341372 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.48 341244 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.46 340832 +list-ext-properties/960521-1_1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 340904 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 1 FAILED FALSE-FREE 536 main 0 0.59 92476 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 2 FAILED FALSE-FREE 536 main 0 0.61 91664 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 3 FAILED FALSE-FREE 536 main 0 0.59 91472 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 4 FAILED FALSE-FREE 536 main 0 0.61 91736 +list-ext-properties/960521-1_1-3.yml valid-memsafety afl 5 FAILED FALSE-FREE 536 main 0 0.59 91660 +list-ext-properties/list-ext.yml unreach-call afl 1 FAILED TARGET-REACHED 556 main 0 0.78 340928 +list-ext-properties/list-ext.yml unreach-call afl 2 FAILED TARGET-REACHED 556 main 0 0.81 341184 +list-ext-properties/list-ext.yml unreach-call afl 3 FAILED TARGET-REACHED 556 main 0 0.76 340552 +list-ext-properties/list-ext.yml unreach-call afl 4 FAILED TARGET-REACHED 556 main 0 0.77 340568 +list-ext-properties/list-ext.yml unreach-call afl 5 FAILED TARGET-REACHED 556 main 0 0.78 340540 +list-ext-properties/list-ext.yml valid-memsafety afl 1 FAILED FALSE-DEREF 558 main 0 0.61 92284 +list-ext-properties/list-ext.yml valid-memsafety afl 2 FAILED FALSE-DEREF 558 main 0 0.63 92044 +list-ext-properties/list-ext.yml valid-memsafety afl 3 FAILED FALSE-DEREF 558 main 0 0.61 92360 +list-ext-properties/list-ext.yml valid-memsafety afl 4 FAILED FALSE-DEREF 558 main 0 0.61 91680 +list-ext-properties/list-ext.yml valid-memsafety afl 5 FAILED FALSE-DEREF 558 main 0 0.59 91956 +list-ext-properties/simple-ext.yml unreach-call afl 1 FAILED TARGET-REACHED 540 main 0 0.61 91960 +list-ext-properties/simple-ext.yml unreach-call afl 2 FAILED TARGET-REACHED 540 main 0 0.59 92076 +list-ext-properties/simple-ext.yml unreach-call afl 3 FAILED TARGET-REACHED 540 main 0 0.60 91704 +list-ext-properties/simple-ext.yml unreach-call afl 4 FAILED TARGET-REACHED 540 main 0 0.60 92000 +list-ext-properties/simple-ext.yml unreach-call afl 5 FAILED TARGET-REACHED 540 main 0 0.59 92044 +list-ext-properties/simple-ext.yml valid-memcleanup afl 1 UNKNOWN - - - 0 9.46 341140 +list-ext-properties/simple-ext.yml valid-memcleanup afl 2 UNKNOWN - - - 0 9.46 340876 +list-ext-properties/simple-ext.yml valid-memcleanup afl 3 UNKNOWN - - - 0 9.46 341088 +list-ext-properties/simple-ext.yml valid-memcleanup afl 4 UNKNOWN - - - 0 9.45 341028 +list-ext-properties/simple-ext.yml valid-memcleanup afl 5 UNKNOWN - - - 0 9.46 341316 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 1 FAILED FALSE-MEMTRACK - - 0 0.60 91780 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 2 FAILED FALSE-MEMTRACK - - 0 0.60 92380 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 3 FAILED FALSE-MEMTRACK - - 0 0.60 92068 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 4 FAILED FALSE-MEMTRACK - - 0 0.59 92616 +list-ext-properties/test-0019_1-1.yml valid-memsafety afl 5 FAILED FALSE-MEMTRACK - - 0 0.58 92540 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.47 340712 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 340788 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.44 340624 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.44 341140 +list-ext-properties/test-0158_1-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 340860 +map2check-assert/array_bug.yml unreach-call afl 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.60 90700 +map2check-assert/array_bug.yml unreach-call afl 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.58 91468 +map2check-assert/array_bug.yml unreach-call afl 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.57 90796 +map2check-assert/array_bug.yml unreach-call afl 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.59 90764 +map2check-assert/array_bug.yml unreach-call afl 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 0.58 91564 +map2check-assert/byte_add_bug.yml unreach-call afl 1 UNKNOWN - - - 0 9.45 340932 +map2check-assert/byte_add_bug.yml unreach-call afl 2 UNKNOWN - - - 0 9.46 341136 +map2check-assert/byte_add_bug.yml unreach-call afl 3 UNKNOWN - - - 0 9.46 340744 +map2check-assert/byte_add_bug.yml unreach-call afl 4 UNKNOWN - - - 0 9.47 341032 +map2check-assert/byte_add_bug.yml unreach-call afl 5 UNKNOWN - - - 0 9.46 341080 +map2check-assert/check_if_bug.yml unreach-call afl 1 UNKNOWN - - - 0 1.45 90736 +map2check-assert/check_if_bug.yml unreach-call afl 2 UNKNOWN - - - 0 1.45 91656 +map2check-assert/check_if_bug.yml unreach-call afl 3 UNKNOWN - - - 0 1.47 90976 +map2check-assert/check_if_bug.yml unreach-call afl 4 UNKNOWN - - - 0 1.45 90984 +map2check-assert/check_if_bug.yml unreach-call afl 5 UNKNOWN - - - 0 1.45 91308 +map2check-assert/ex01_false.yml unreach-call afl 1 UNKNOWN - - - 0 1.46 91304 +map2check-assert/ex01_false.yml unreach-call afl 2 UNKNOWN - - - 0 1.45 91368 +map2check-assert/ex01_false.yml unreach-call afl 3 UNKNOWN - - - 0 1.45 91208 +map2check-assert/ex01_false.yml unreach-call afl 4 UNKNOWN - - - 0 1.44 90676 +map2check-assert/ex01_false.yml unreach-call afl 5 UNKNOWN - - - 0 1.46 90744 +map2check-assert/ex02_false.yml unreach-call afl 1 UNKNOWN - - - 0 1.44 91132 +map2check-assert/ex02_false.yml unreach-call afl 2 UNKNOWN - - - 0 1.44 90824 +map2check-assert/ex02_false.yml unreach-call afl 3 UNKNOWN - - - 0 1.44 90572 +map2check-assert/ex02_false.yml unreach-call afl 4 UNKNOWN - - - 0 1.45 90536 +map2check-assert/ex02_false.yml unreach-call afl 5 UNKNOWN - - - 0 1.44 91140 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.46 341004 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.45 340788 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.46 340864 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 340544 +memory-alloca/c.03-alloca-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.45 340976 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 91820 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 92232 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.46 91864 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 91804 +memsafety-ext/dll_extends_pointer.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 92524 +memsafety-ext/tree_stack.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.47 91908 +memsafety-ext/tree_stack.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.47 91664 +memsafety-ext/tree_stack.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.48 91760 +memsafety-ext/tree_stack.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.48 91980 +memsafety-ext/tree_stack.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.47 91968 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 91732 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.46 92008 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.47 92460 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.47 91736 +memsafety-ext2/length_test03-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.48 92048 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.50 92108 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.48 92220 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.49 92452 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.50 92732 +memsafety-ext2/split_list_test05-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.49 92076 +memsafety/960521-1-1.yml valid-memsafety afl 1 FAILED FALSE-FREE 532 main 0 0.59 91732 +memsafety/960521-1-1.yml valid-memsafety afl 2 FAILED FALSE-FREE 532 main 0 0.59 92744 +memsafety/960521-1-1.yml valid-memsafety afl 3 FAILED FALSE-FREE 532 main 0 0.57 91732 +memsafety/960521-1-1.yml valid-memsafety afl 4 FAILED FALSE-FREE 532 main 0 0.58 91472 +memsafety/960521-1-1.yml valid-memsafety afl 5 FAILED FALSE-FREE 532 main 0 0.61 91548 +memsafety/960521-1-2.yml valid-memsafety afl 1 UNKNOWN - - - 0 9.45 340752 +memsafety/960521-1-2.yml valid-memsafety afl 2 UNKNOWN - - - 0 9.46 340852 +memsafety/960521-1-2.yml valid-memsafety afl 3 UNKNOWN - - - 0 9.45 340984 +memsafety/960521-1-2.yml valid-memsafety afl 4 UNKNOWN - - - 0 9.45 341216 +memsafety/960521-1-2.yml valid-memsafety afl 5 UNKNOWN - - - 0 9.44 340784 +memsafety/960521-1-3.yml valid-memsafety afl 1 FAILED FALSE-DEREF 529 main 0 0.61 92324 +memsafety/960521-1-3.yml valid-memsafety afl 2 FAILED FALSE-DEREF 529 main 0 0.61 91776 +memsafety/960521-1-3.yml valid-memsafety afl 3 FAILED FALSE-DEREF 529 main 0 0.60 91828 +memsafety/960521-1-3.yml valid-memsafety afl 4 FAILED FALSE-DEREF 529 main 0 0.62 92420 +memsafety/960521-1-3.yml valid-memsafety afl 5 FAILED FALSE-DEREF 529 main 0 0.60 91888 +memsafety/test-0102-1.yml valid-memsafety afl 1 UNKNOWN - - - 0 1.48 91960 +memsafety/test-0102-1.yml valid-memsafety afl 2 UNKNOWN - - - 0 1.49 91744 +memsafety/test-0102-1.yml valid-memsafety afl 3 UNKNOWN - - - 0 1.48 92908 +memsafety/test-0102-1.yml valid-memsafety afl 4 UNKNOWN - - - 0 1.50 92740 +memsafety/test-0102-1.yml valid-memsafety afl 5 UNKNOWN - - - 0 1.48 92220 +array-examples/relax-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.73 173312 +array-examples/relax-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.68 174236 +array-examples/relax-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.72 174264 +array-examples/relax-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.73 174372 +array-examples/relax-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 570 is_relaxed_prefix 0 1.73 173644 +array-examples/standard_sentinel-2.yml unreach-call symex 1 UNKNOWN - - - 0 32.52 207684 +array-examples/standard_sentinel-2.yml unreach-call symex 2 UNKNOWN - - - 0 32.52 208052 +array-examples/standard_sentinel-2.yml unreach-call symex 3 UNKNOWN - - - 0 32.50 210292 +array-examples/standard_sentinel-2.yml unreach-call symex 4 UNKNOWN - - - 0 32.47 207876 +array-examples/standard_sentinel-2.yml unreach-call symex 5 UNKNOWN - - - 0 32.46 208272 +array-examples/standard_two_index_04.yml unreach-call symex 1 UNKNOWN - - - 0 32.50 208936 +array-examples/standard_two_index_04.yml unreach-call symex 2 UNKNOWN - - - 0 32.51 211456 +array-examples/standard_two_index_04.yml unreach-call symex 3 UNKNOWN - - - 0 32.49 210104 +array-examples/standard_two_index_04.yml unreach-call symex 4 UNKNOWN - - - 0 32.52 209684 +array-examples/standard_two_index_04.yml unreach-call symex 5 UNKNOWN - - - 0 32.52 208500 +array-examples/standard_two_index_05.yml unreach-call symex 1 UNKNOWN - - - 0 32.46 208960 +array-examples/standard_two_index_05.yml unreach-call symex 2 UNKNOWN - - - 0 32.52 208820 +array-examples/standard_two_index_05.yml unreach-call symex 3 UNKNOWN - - - 0 32.45 209412 +array-examples/standard_two_index_05.yml unreach-call symex 4 UNKNOWN - - - 0 32.48 208460 +array-examples/standard_two_index_05.yml unreach-call symex 5 UNKNOWN - - - 0 32.48 209004 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 1 FAILED FALSE-DEREF 522 main 0 1.53 172764 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 2 FAILED FALSE-DEREF 522 main 0 1.55 172712 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 3 FAILED FALSE-DEREF 522 main 0 1.54 172372 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 4 FAILED FALSE-DEREF 522 main 0 1.56 174524 +array-memsafety/add_last_unsafe.yml valid-memsafety symex 5 FAILED FALSE-DEREF 522 main 0 1.58 171772 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.59 192832 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.56 197836 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.58 192304 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.52 198024 +array-memsafety/array01-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.64 199776 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.54 172988 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.58 172652 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.58 172780 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.52 172816 +array-memsafety/insertionsort-alloca-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.52 172516 +array-memsafety/lis_unsafe.yml valid-memsafety symex 1 UNKNOWN - - - 0 1.49 172324 +array-memsafety/lis_unsafe.yml valid-memsafety symex 2 UNKNOWN - - - 0 1.50 172840 +array-memsafety/lis_unsafe.yml valid-memsafety symex 3 UNKNOWN - - - 0 1.58 172976 +array-memsafety/lis_unsafe.yml valid-memsafety symex 4 UNKNOWN - - - 0 1.48 172932 +array-memsafety/lis_unsafe.yml valid-memsafety symex 5 UNKNOWN - - - 0 1.43 173044 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.48 156448 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.37 156472 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.36 156248 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.37 156608 +ldv-memsafety-bitfields/test-bitfields-1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.42 166712 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 1 FAILED FALSE-FREE 46 main 0 1.40 167056 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 2 FAILED FALSE-FREE 46 main 0 1.39 156656 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 3 FAILED FALSE-FREE 46 main 0 1.40 166804 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 4 FAILED FALSE-FREE 46 main 0 1.38 156880 +ldv-memsafety-bitfields/test-bitfields-2.1-2.yml valid-memsafety symex 5 FAILED FALSE-FREE 46 main 0 1.38 156768 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 1.39 165244 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 1.35 155136 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 1.35 155136 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 1.36 154780 +ldv-memsafety-bitfields/test-bitfields-3.1-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 1.36 155724 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 1 SUCCEEDED - - - 0 20.08 157112 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 2 SUCCEEDED - - - 0 20.57 157660 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 3 SUCCEEDED - - - 0 20.87 157536 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 4 SUCCEEDED - - - 0 20.60 156952 +ldv-memsafety/ArraysOfVariableLength.yml valid-memsafety symex 5 SUCCEEDED - - - 0 19.56 158040 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.32 157232 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.35 155648 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.37 157124 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.36 157036 +ldv-memsafety/ArraysOfVariableLength2.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.36 156184 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 1.68 164192 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 1.67 167496 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 1.60 165896 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 1.62 164944 +ldv-memsafety/memleaks_test1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 1.66 165456 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 2.34 165980 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 2.32 167504 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 2.41 166108 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 2.27 165988 +ldv-memsafety/memleaks_test10-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 2.31 165840 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 779 free_17 0 2.66 167252 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 779 free_17 0 2.67 167372 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 779 free_17 0 2.69 167076 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 779 free_17 0 2.64 167188 +ldv-memsafety/memleaks_test17_2-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 779 free_17 0 2.72 167888 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.61 165720 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.62 165068 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.62 164252 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.69 165232 +ldv-memsafety/memleaks_test3-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.68 164884 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.34 155332 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.38 155912 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.34 156212 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.38 155908 +ldv-memsafety/memsetNonZero.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.37 155828 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 1 FAILED FALSE-DEREF 533 main 0 1.53 173048 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 2 FAILED FALSE-DEREF 533 main 0 1.55 173252 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 3 FAILED FALSE-DEREF 533 main 0 1.54 172800 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 4 FAILED FALSE-DEREF 533 main 0 1.55 172176 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex 5 FAILED FALSE-DEREF 533 main 0 1.55 173048 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 3.93 173684 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 3.97 172928 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 3.93 173900 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 4.09 164948 +list-ext-properties/960521-1_1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 3.91 165244 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 1 FAILED FALSE-FREE 536 main 0 1.54 172412 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 2 FAILED FALSE-FREE 536 main 0 1.57 172328 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 3 FAILED FALSE-FREE 536 main 0 1.56 172712 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 4 FAILED FALSE-FREE 536 main 0 1.53 173140 +list-ext-properties/960521-1_1-3.yml valid-memsafety symex 5 FAILED FALSE-FREE 536 main 0 1.59 172932 +list-ext-properties/list-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 556 main 0 1.50 166172 +list-ext-properties/list-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 556 main 0 1.52 166452 +list-ext-properties/list-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 556 main 0 1.50 172356 +list-ext-properties/list-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 556 main 0 1.51 165164 +list-ext-properties/list-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 556 main 0 1.48 165580 +list-ext-properties/list-ext.yml valid-memsafety symex 1 FAILED FALSE-DEREF 558 main 0 6.22 174248 +list-ext-properties/list-ext.yml valid-memsafety symex 2 FAILED FALSE-DEREF 558 main 0 6.56 168228 +list-ext-properties/list-ext.yml valid-memsafety symex 3 FAILED FALSE-DEREF 558 main 0 6.62 167960 +list-ext-properties/list-ext.yml valid-memsafety symex 4 FAILED FALSE-DEREF 558 main 0 6.52 176644 +list-ext-properties/list-ext.yml valid-memsafety symex 5 FAILED FALSE-DEREF 558 main 0 6.49 167436 +list-ext-properties/simple-ext.yml unreach-call symex 1 FAILED TARGET-REACHED 540 main 0 1.44 162916 +list-ext-properties/simple-ext.yml unreach-call symex 2 FAILED TARGET-REACHED 540 main 0 1.41 165244 +list-ext-properties/simple-ext.yml unreach-call symex 3 FAILED TARGET-REACHED 540 main 0 1.43 162688 +list-ext-properties/simple-ext.yml unreach-call symex 4 FAILED TARGET-REACHED 540 main 0 1.42 163680 +list-ext-properties/simple-ext.yml unreach-call symex 5 FAILED TARGET-REACHED 540 main 0 1.47 162788 +list-ext-properties/simple-ext.yml valid-memcleanup symex 1 UNKNOWN - - - 0 1.52 162836 +list-ext-properties/simple-ext.yml valid-memcleanup symex 2 UNKNOWN - - - 0 1.52 163460 +list-ext-properties/simple-ext.yml valid-memcleanup symex 3 UNKNOWN - - - 0 1.58 163724 +list-ext-properties/simple-ext.yml valid-memcleanup symex 4 UNKNOWN - - - 0 1.55 171836 +list-ext-properties/simple-ext.yml valid-memcleanup symex 5 UNKNOWN - - - 0 1.57 163576 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 1 FAILED FALSE-MEMTRACK - - 0 1.44 156960 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 2 FAILED FALSE-MEMTRACK - - 0 1.40 156508 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 3 FAILED FALSE-MEMTRACK - - 0 1.41 157092 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 4 FAILED FALSE-MEMTRACK - - 0 1.40 168888 +list-ext-properties/test-0019_1-1.yml valid-memsafety symex 5 FAILED FALSE-MEMTRACK - - 0 1.43 159220 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 1 SUCCEEDED - - - 0 1.38 163912 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 2 SUCCEEDED - - - 0 1.42 164156 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 3 SUCCEEDED - - - 0 1.39 164080 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 4 SUCCEEDED - - - 0 1.42 172680 +list-ext-properties/test-0158_1-1.yml valid-memsafety symex 5 SUCCEEDED - - - 0 1.40 172856 +map2check-assert/array_bug.yml unreach-call symex 1 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.40 163752 +map2check-assert/array_bug.yml unreach-call symex 2 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.36 163816 +map2check-assert/array_bug.yml unreach-call symex 3 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.40 163004 +map2check-assert/array_bug.yml unreach-call symex 4 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.38 163468 +map2check-assert/array_bug.yml unreach-call symex 5 FAILED TARGET-REACHED 7 __VERIFIER_assert 0 1.36 163700 +map2check-assert/byte_add_bug.yml unreach-call symex 1 SUCCEEDED - - - 0 1.32 155760 +map2check-assert/byte_add_bug.yml unreach-call symex 2 SUCCEEDED - - - 0 1.34 155828 +map2check-assert/byte_add_bug.yml unreach-call symex 3 SUCCEEDED - - - 0 1.37 155308 +map2check-assert/byte_add_bug.yml unreach-call symex 4 SUCCEEDED - - - 0 1.35 158528 +map2check-assert/byte_add_bug.yml unreach-call symex 5 SUCCEEDED - - - 0 1.38 155868 +map2check-assert/check_if_bug.yml unreach-call symex 1 UNKNOWN - - - 0 32.96 208548 +map2check-assert/check_if_bug.yml unreach-call symex 2 UNKNOWN - - - 0 32.81 210100 +map2check-assert/check_if_bug.yml unreach-call symex 3 UNKNOWN - - - 0 32.88 210860 +map2check-assert/check_if_bug.yml unreach-call symex 4 UNKNOWN - - - 0 32.89 210624 +map2check-assert/check_if_bug.yml unreach-call symex 5 UNKNOWN - - - 0 32.88 206772 +map2check-assert/ex01_false.yml unreach-call symex 1 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 2.99 171952 +map2check-assert/ex01_false.yml unreach-call symex 2 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 3.08 172292 +map2check-assert/ex01_false.yml unreach-call symex 3 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 3.00 172088 +map2check-assert/ex01_false.yml unreach-call symex 4 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 2.95 171892 +map2check-assert/ex01_false.yml unreach-call symex 5 FAILED TARGET-REACHED 5 __VERIFIER_assert 0 2.99 172100 +map2check-assert/ex02_false.yml unreach-call symex 1 UNKNOWN - - - 0 32.39 207772 +map2check-assert/ex02_false.yml unreach-call symex 2 UNKNOWN - - - 0 32.41 207624 +map2check-assert/ex02_false.yml unreach-call symex 3 UNKNOWN - - - 0 32.35 207188 +map2check-assert/ex02_false.yml unreach-call symex 4 UNKNOWN - - - 0 32.39 210016 +map2check-assert/ex02_false.yml unreach-call symex 5 UNKNOWN - - - 0 32.35 207744 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 1 UNKNOWN - - - 0 33.80 201364 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 2 UNKNOWN - - - 0 33.96 201188 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 3 UNKNOWN - - - 0 33.94 206540 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 4 UNKNOWN - - - 0 33.80 206864 +memory-alloca/c.03-alloca-2.yml valid-memsafety symex 5 UNKNOWN - - - 0 33.82 201788 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.67 244192 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.66 247596 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.71 244184 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.71 244892 +memsafety-ext/dll_extends_pointer.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.66 244356 +memsafety-ext/tree_stack.yml valid-memsafety symex 1 UNKNOWN - - - 0 33.05 282904 +memsafety-ext/tree_stack.yml valid-memsafety symex 2 UNKNOWN - - - 0 33.04 281920 +memsafety-ext/tree_stack.yml valid-memsafety symex 3 UNKNOWN - - - 0 33.00 283976 +memsafety-ext/tree_stack.yml valid-memsafety symex 4 UNKNOWN - - - 0 33.00 283912 +memsafety-ext/tree_stack.yml valid-memsafety symex 5 UNKNOWN - - - 0 33.02 283452 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.36 173904 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.36 173472 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.36 173644 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.37 176272 +memsafety-ext2/length_test03-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.34 176780 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 33.74 445396 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 33.75 443952 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 33.73 443568 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 33.69 442876 +memsafety-ext2/split_list_test05-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 33.76 443648 +memsafety/960521-1-1.yml valid-memsafety symex 1 FAILED FALSE-FREE 532 main 0 1.48 157108 +memsafety/960521-1-1.yml valid-memsafety symex 2 FAILED FALSE-FREE 532 main 0 1.49 156932 +memsafety/960521-1-1.yml valid-memsafety symex 3 FAILED FALSE-FREE 532 main 0 1.45 156568 +memsafety/960521-1-1.yml valid-memsafety symex 4 FAILED FALSE-FREE 532 main 0 1.44 156420 +memsafety/960521-1-1.yml valid-memsafety symex 5 FAILED FALSE-FREE 532 main 0 1.49 156984 +memsafety/960521-1-2.yml valid-memsafety symex 1 SUCCEEDED - - - 0 27.02 156344 +memsafety/960521-1-2.yml valid-memsafety symex 2 SUCCEEDED - - - 0 27.23 157812 +memsafety/960521-1-2.yml valid-memsafety symex 3 SUCCEEDED - - - 0 27.05 167368 +memsafety/960521-1-2.yml valid-memsafety symex 4 SUCCEEDED - - - 0 25.56 157724 +memsafety/960521-1-2.yml valid-memsafety symex 5 SUCCEEDED - - - 0 25.93 156576 +memsafety/960521-1-3.yml valid-memsafety symex 1 FAILED FALSE-DEREF 529 main 0 1.47 166892 +memsafety/960521-1-3.yml valid-memsafety symex 2 FAILED FALSE-DEREF 529 main 0 1.49 157004 +memsafety/960521-1-3.yml valid-memsafety symex 3 FAILED FALSE-DEREF 529 main 0 1.50 157872 +memsafety/960521-1-3.yml valid-memsafety symex 4 FAILED FALSE-DEREF 529 main 0 1.47 157236 +memsafety/960521-1-3.yml valid-memsafety symex 5 FAILED FALSE-DEREF 529 main 0 1.48 157312 +memsafety/test-0102-1.yml valid-memsafety symex 1 UNKNOWN - - - 0 32.53 240364 +memsafety/test-0102-1.yml valid-memsafety symex 2 UNKNOWN - - - 0 32.49 240192 +memsafety/test-0102-1.yml valid-memsafety symex 3 UNKNOWN - - - 0 32.53 240600 +memsafety/test-0102-1.yml valid-memsafety symex 4 UNKNOWN - - - 0 32.52 240936 +memsafety/test-0102-1.yml valid-memsafety symex 5 UNKNOWN - - - 0 32.53 240944 diff --git a/tests/cutover/gate-report.md b/tests/cutover/gate-report.md index 59b9299b1..3acc4076c 100644 --- a/tests/cutover/gate-report.md +++ b/tests/cutover/gate-report.md @@ -351,3 +351,37 @@ R−C is the difference of the median wall times. "profiled" marks a row with it - Every profiled exploration phase is as fast as C's or faster. **Criterion 9:** criteria 6 and 7 pass, so none of the 18 rows blocks. All 18 now have a recorded cause. The plan names `docs/cutover/perf.md` as the place for these profiles. That file does not exist yet in either repository, so the profiles are recorded here. + +## Re-execução symex com runtime KLEE reduzido (2026-10-16) + +Only the Rust symex side was re-run. The runtime bitcode is now slimmer (std's backtrace symbolizer stubbed out). The afl rows and the C tables are unchanged. + +### Setup + +- map2check-library `94a17ec` (`ef166d1` + `94a17ec`), built from a `git archive` with a fresh `CARGO_TARGET_DIR`: `cargo build --profile runtime --features libfuzzer,wasm`, and `scripts/build-klee-runtime.sh` (rustc 1.72.1, LLVM 16.0.5) inside `map2check-dev:cutover-klee-rust`. +- Map2Check-rust `33e3b005`, installed into fresh `build-gate3/` and `release-gate3/` with the same CMake flags as `release-gate2`, pointing `MAP2CHECK_RUST_LIB_DIR` and `MAP2CHECK_RUST_KLEE_BC` at the new artifacts. `cmp` confirms the installed `.a` and `.bc` are the ones built. +- Installed `map2check-klee.bc`: 1 241 728 bytes (1.24 MB), against 2 296 020 bytes in `release-gate2`. +- Same image (`cutover-klee-rust-time`), same caps (`--memory 3g --memory-swap 3g --cpus 4`, KLEE `--max-memory=2000` through the overlay `bin/klee` wrapper, confirmed in the process list), `GENS=symex REPS=5 TIMEOUT=45`, and `free -g` showed 4 GB available before the container started. +- Output: `baseline-rust-symex-slim.tsv` (205 rows). `baseline-rust-v2.tsv` is the afl rows of `baseline-rust.tsv` plus these symex rows (410 rows). + +### compare.py (C gate baseline vs v2, with `deltas-aceitos.tsv`) + +``` +median wall ratio: 1.011 median rss ratio: 1.081 + +gate: PASS +``` + +No field divergence outside the accepted deltas. Against the first run, no symex row changed verdict, tag, line, function or witness. + +### Before and after (Rust/C) + +| gen | median wall before → after | median RSS before → after | Σ median wall Rust (C = 617.0 s symex) | rows >1.5 wall | TIMEOUT / OOM | +|---|---|---|---|---|---| +| afl | 1.003 → 1.003 | 0.987 → 0.987 | 167.5 s (unchanged) | 3 → 3 | 0 / 0 | +| symex | 1.091 → 1.035 | 1.582 → 1.224 | 599.7 s → 523.0 s | 15 → 10 | 0 / 0 | +| all | 1.015 → 1.011 | 1.360 → 1.081 | 767.2 s → 690.6 s (C 782.2 s) | 18 → 13 | 0 / 0 | + +- Criterion 6 passes (1.011 ≤ 1.10), criterion 7 passes (0 TIMEOUT, 0 Rust OOM), criterion 8 passes (1.081 ≤ 1.36, and also ≤ 1.25). +- Symex median peak RSS: C 143.7 MB, Rust 225.5 MB → 168.2 MB. Largest Rust peak: 443.6 MB (split_list_test05-1). +- Criterion 9: 13 rows above 1.5 wall (10 symex, 3 afl), all with C under 1 s and Rust 0.8–1.55 s. The symex ones are the short tasks (C 0.35–0.96 s, Rust 1.35–1.55 s), so the fixed start-up cost of about +1 s remains. From 9f040730718e57dcb9dc81adcd15ee6f01fc64b0 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 01:16:56 -0400 Subject: [PATCH 33/44] test: cite SD-20 and SD-21 in the accepted deltas --- tests/cutover/deltas-aceitos.tsv | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/cutover/deltas-aceitos.tsv b/tests/cutover/deltas-aceitos.tsv index 4bab5ec10..4fa02dbd8 100644 --- a/tests/cutover/deltas-aceitos.tsv +++ b/tests/cutover/deltas-aceitos.tsv @@ -5,16 +5,16 @@ list-ext-properties/list-ext.yml unreach-call afl verdict UNKNOWN FAILED UB-BENC list-ext-properties/list-ext.yml unreach-call afl tag - TARGET-REACHED UB-BENCHMARK-list-ext list-ext-properties/list-ext.yml unreach-call afl line - 556 UB-BENCHMARK-list-ext list-ext-properties/list-ext.yml unreach-call afl function - main UB-BENCHMARK-list-ext -array-examples/standard_sentinel-2.yml unreach-call afl verdict OOM UNKNOWN C-BUG-oom-afl-nondet -array-examples/standard_two_index_04.yml unreach-call afl verdict OOM UNKNOWN C-BUG-oom-afl-nondet -array-examples/standard_two_index_05.yml unreach-call afl verdict OOM UNKNOWN C-BUG-oom-afl-nondet -list-ext-properties/960521-1_1-1.yml valid-memsafety symex line 0 533 C-BUG-property-race -list-ext-properties/960521-1_1-1.yml valid-memsafety symex function - main C-BUG-property-race -list-ext-properties/simple-ext.yml unreach-call symex verdict UNKNOWN FAILED C-BUG-property-race -list-ext-properties/simple-ext.yml unreach-call symex tag - TARGET-REACHED C-BUG-property-race -list-ext-properties/simple-ext.yml unreach-call symex line - 540 C-BUG-property-race -list-ext-properties/simple-ext.yml unreach-call symex function - main C-BUG-property-race -map2check-assert/ex01_false.yml unreach-call symex verdict UNKNOWN FAILED C-BUG-property-race -map2check-assert/ex01_false.yml unreach-call symex tag - TARGET-REACHED C-BUG-property-race -map2check-assert/ex01_false.yml unreach-call symex line - 5 C-BUG-property-race -map2check-assert/ex01_false.yml unreach-call symex function - __VERIFIER_assert C-BUG-property-race +array-examples/standard_sentinel-2.yml unreach-call afl verdict OOM UNKNOWN SD-21 +array-examples/standard_two_index_04.yml unreach-call afl verdict OOM UNKNOWN SD-21 +array-examples/standard_two_index_05.yml unreach-call afl verdict OOM UNKNOWN SD-21 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex line 0 533 SD-20 +list-ext-properties/960521-1_1-1.yml valid-memsafety symex function - main SD-20 +list-ext-properties/simple-ext.yml unreach-call symex verdict UNKNOWN FAILED SD-20 +list-ext-properties/simple-ext.yml unreach-call symex tag - TARGET-REACHED SD-20 +list-ext-properties/simple-ext.yml unreach-call symex line - 540 SD-20 +list-ext-properties/simple-ext.yml unreach-call symex function - main SD-20 +map2check-assert/ex01_false.yml unreach-call symex verdict UNKNOWN FAILED SD-20 +map2check-assert/ex01_false.yml unreach-call symex tag - TARGET-REACHED SD-20 +map2check-assert/ex01_false.yml unreach-call symex line - 5 SD-20 +map2check-assert/ex01_false.yml unreach-call symex function - __VERIFIER_assert SD-20 From db52895492894bfe1998958663225ddafcb6e468 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 11:27:40 -0400 Subject: [PATCH 34/44] build: link libmap2check_runtime.a from the lib/ of the release archive The map2check-library release archive ships three builds in lib/; the one Map2Check links is libmap2check_runtime.a (profile runtime, features libfuzzer,wasm), while its libmap2check.a is the featureless core build. With MAP2CHECK_RUST_LIB_DIR pointing at that lib/, prefer the runtime build and install it as lib/libmap2check.a, the name the frontend uses. The three cache variables now default to the environment variables of the same name, so an image can carry them. The resolved path is exported as MAP2CHECK_RUST_RUNTIME_LIB and the module is included before the tests, so EndToEndLinkTest links the same file that is installed. --- CMakeLists.txt | 6 ++++-- cmake/Map2CheckRustRuntime.cmake | 27 ++++++++++++++++++------ tests/cutover/test_rust_runtime_cmake.sh | 13 +++++++++++- tests/unit/pass/CMakeLists.txt | 12 ++++------- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f149a5c93..e9113917f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,10 @@ endif() include_directories(${PROJECT_SOURCE_DIR}) +# Before the tests: they link the runtime library this module resolves +# (MAP2CHECK_RUST_RUNTIME_LIB). +include(cmake/Map2CheckRustRuntime.cmake) + if(ENABLE_TEST) # include(CTest) em vez de enable_testing(): gera DartConfiguration.tcl, # necessário para `ctest -T memcheck` (job Valgrind no CI). @@ -87,8 +91,6 @@ if(ENABLE_TEST) add_subdirectory(tests) endif() -include(cmake/Map2CheckRustRuntime.cmake) - add_subdirectory(modules) if(BUILD_DOC) diff --git a/cmake/Map2CheckRustRuntime.cmake b/cmake/Map2CheckRustRuntime.cmake index 5474239a7..68093e4dd 100644 --- a/cmake/Map2CheckRustRuntime.cmake +++ b/cmake/Map2CheckRustRuntime.cmake @@ -3,16 +3,28 @@ # # Installs ${prefix}/lib/libmap2check.a and, when available, # ${prefix}/lib/map2check-klee.bc (KLEE runtime bitcode, LLVM 16). -set(MAP2CHECK_RUST_LIB_DIR "" CACHE PATH "Directory with a prebuilt libmap2check.a (empty = build from MAP2CHECK_RUST_SRC)") -set(MAP2CHECK_RUST_SRC "" CACHE PATH "map2check-library checkout used when MAP2CHECK_RUST_LIB_DIR is empty") -set(MAP2CHECK_RUST_KLEE_BC "" CACHE FILEPATH "Prebuilt KLEE runtime bitcode (empty = none, or built from MAP2CHECK_RUST_SRC when rustc 1.72.1 is available)") +# +# The defaults come from the environment variables of the same name, which the +# map2check-dev image sets (Dockerfile.dev); -D on the command line wins. +set(MAP2CHECK_RUST_LIB_DIR "$ENV{MAP2CHECK_RUST_LIB_DIR}" CACHE PATH "Directory with a prebuilt libmap2check.a (empty = build from MAP2CHECK_RUST_SRC)") +set(MAP2CHECK_RUST_SRC "$ENV{MAP2CHECK_RUST_SRC}" CACHE PATH "map2check-library checkout used when MAP2CHECK_RUST_LIB_DIR is empty") +set(MAP2CHECK_RUST_KLEE_BC "$ENV{MAP2CHECK_RUST_KLEE_BC}" CACHE FILEPATH "Prebuilt KLEE runtime bitcode (empty = none, or built from MAP2CHECK_RUST_SRC when rustc 1.72.1 is available)") # --- Static library --- if(MAP2CHECK_RUST_LIB_DIR) - set(_m2c_rust_lib "${MAP2CHECK_RUST_LIB_DIR}/libmap2check.a") + # The release archive (lib/ of map2check-library--.tar.gz) + # ships three builds; the one Map2Check links is libmap2check_runtime.a + # (profile runtime, features libfuzzer,wasm). Its libmap2check.a is the + # featureless core build. A directory without libmap2check_runtime.a is a + # local `cargo build --profile runtime` output (target/runtime). + if(EXISTS "${MAP2CHECK_RUST_LIB_DIR}/libmap2check_runtime.a") + set(_m2c_rust_lib "${MAP2CHECK_RUST_LIB_DIR}/libmap2check_runtime.a") + else() + set(_m2c_rust_lib "${MAP2CHECK_RUST_LIB_DIR}/libmap2check.a") + endif() if(NOT EXISTS "${_m2c_rust_lib}") message(FATAL_ERROR "libmap2check.a not found in ${MAP2CHECK_RUST_LIB_DIR} " - "(build it with: cargo build --profile runtime --features libfuzzer,wasm)") + "(nor libmap2check_runtime.a; build it with: cargo build --profile runtime --features libfuzzer,wasm)") endif() elseif(MAP2CHECK_RUST_SRC) find_program(M2C_CARGO cargo REQUIRED) @@ -26,7 +38,10 @@ elseif(MAP2CHECK_RUST_SRC) else() message(FATAL_ERROR "Set MAP2CHECK_RUST_LIB_DIR or MAP2CHECK_RUST_SRC to provide the Rust runtime") endif() -install(FILES "${_m2c_rust_lib}" DESTINATION lib) +# The path the tests link (tests/unit/pass); installed under the name the +# frontend expects (kRustRuntimeLibrary). +set(MAP2CHECK_RUST_RUNTIME_LIB "${_m2c_rust_lib}") +install(FILES "${_m2c_rust_lib}" DESTINATION lib RENAME libmap2check.a) message(STATUS "Rust runtime: ${_m2c_rust_lib}") # --- KLEE bitcode (optional) --- diff --git a/tests/cutover/test_rust_runtime_cmake.sh b/tests/cutover/test_rust_runtime_cmake.sh index 04b3aaad7..a5fb5a173 100755 --- a/tests/cutover/test_rust_runtime_cmake.sh +++ b/tests/cutover/test_rust_runtime_cmake.sh @@ -3,7 +3,8 @@ # map2check-klee.bc) is installed, no C runtime bitcode; configure fails loudly # without a library or with an unreadable bitcode. # -# Env: MAP2CHECK_RUST_LIB_DIR directory with libmap2check.a (required) +# Env: MAP2CHECK_RUST_LIB_DIR directory with libmap2check.a, or the lib/ of +# the release archive (required) # CMAKE_ARGS extra configure flags (e.g. -G Ninja -DLLVM_DIR=...) set -euo pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)" @@ -29,6 +30,16 @@ if find "$P" -name '*.bc' | grep -E 'map2check|memtrack|bbtrack|nondet|caller|co fail "C runtime bitcode still installed" fi +# 1b. Release archive layout (lib/ of the map2check-library tarball): the +# runtime build, libmap2check_runtime.a, is the one installed as +# libmap2check.a; the featureless core libmap2check.a next to it is not. +R="$W/release-lib"; mkdir "$R" +cp "$LIB/libmap2check.a" "$R/libmap2check_runtime.a" +echo 'not the runtime' >"$R/libmap2check.a" +install_tree release -DMAP2CHECK_RUST_LIB_DIR="$R" +cmp -s "$W/release-p/lib/libmap2check.a" "$R/libmap2check_runtime.a" || + fail "release layout: libmap2check_runtime.a not installed as libmap2check.a" + # 2. A readable KLEE bitcode is installed as lib/map2check-klee.bc. LLVM_DIS="${LLVM_DIS:-llvm-dis-16}"; LLVM_AS="${LLVM_AS:-llvm-as-16}" echo 'define i32 @f() { ret i32 0 }' >"$W/ok.ll" diff --git a/tests/unit/pass/CMakeLists.txt b/tests/unit/pass/CMakeLists.txt index 2948b38f3..400d5acba 100644 --- a/tests/unit/pass/CMakeLists.txt +++ b/tests/unit/pass/CMakeLists.txt @@ -64,18 +64,14 @@ else() # Steps 5 and 5b of Task 3.2: every input, instrumented with all passes of # each analysis mode, links against the Rust runtime; an assume rejection # unwinds at -O2 under the libFuzzer driver. - if(MAP2CHECK_RUST_LIB_DIR) - set(M2C_E2E_RUST_LIB "${MAP2CHECK_RUST_LIB_DIR}/libmap2check.a") - elseif(MAP2CHECK_RUST_SRC) - set(M2C_E2E_RUST_LIB "${MAP2CHECK_RUST_SRC}/target/runtime/libmap2check.a") - endif() - if(M2C_E2E_RUST_LIB) + # MAP2CHECK_RUST_RUNTIME_LIB: resolved by cmake/Map2CheckRustRuntime.cmake. + if(MAP2CHECK_RUST_RUNTIME_LIB) m2c_pass_test(EndToEndLinkTest EndToEndLinkTest.cpp) target_compile_definitions(EndToEndLinkTest PRIVATE - M2C_RUST_LIB="${M2C_E2E_RUST_LIB}") + M2C_RUST_LIB="${MAP2CHECK_RUST_RUNTIME_LIB}") add_dependencies(EndToEndLinkTest NonDetPass MemoryTrackPass OverflowPass AssertPass TargetPass Map2CheckLibrary) - if(NOT MAP2CHECK_RUST_LIB_DIR) + if(TARGET Map2CheckRustRuntime) add_dependencies(EndToEndLinkTest Map2CheckRustRuntime) endif() else() From 8e8a0230acce68bad1c083af6c8192b8f5e27818 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 11:27:40 -0400 Subject: [PATCH 35/44] ci: build and test against the released Rust runtime Fetch map2check-library v1.1.0-rc1 (SHA-256 pinned in scripts/runtime/fetch-map2check-library.sh) into /opt/map2check-library and configure every CMake build with -DMAP2CHECK_RUST_LIB_DIR. The KLEE runtime bitcode is not in the archive: a new job builds it from the same tag (commit pinned) with rustc 1.72.1 and hands it to the Docker jobs as -DMAP2CHECK_RUST_KLEE_BC, so the symex steps keep running. Dockerfile.dev does the same: the archive in /opt/map2check-library, the KLEE bitcode built and the Rust toolchain removed, and both paths set as environment defaults for CMake. Drop the cppcheck pass over modules/backend/library: the C runtime is out of the build and stays in the tree only until it is removed. --- .github/workflows/ci.yml | 158 ++++++++++++++++++--- Dockerfile.dev | 23 +++ scripts/runtime/fetch-map2check-library.sh | 37 +++++ 3 files changed, 197 insertions(+), 21 deletions(-) create mode 100755 scripts/runtime/fetch-map2check-library.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95fb3c08c..bb11b1f45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,11 @@ # Unit tests use -DSKIP_KLEE=ON -DSKIP_AFL_PLUS_PLUS=ON, # so the full Dockerfile.dev dependencies are not needed. # +# Runtime: map2check-library (Rust), the pinned release fetched by +# scripts/runtime/fetch-map2check-library.sh into /opt/map2check-library +# (-DMAP2CHECK_RUST_LIB_DIR). The C runtime (modules/backend/library) is out +# of the build and is no longer compiled or analysed here. +# # Phase 1.5 — OpenSSF Best Practices Badge (Analysis section) ############################################################ name: CI @@ -54,6 +59,9 @@ jobs: sudo tar xzf /tmp/wabt.tar.gz -C /opt sudo ln -sf /opt/wabt-1.0.41/bin/wasm2c /usr/local/bin/wasm2c + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + - name: Configure CMake run: | mkdir -p build && cd build @@ -61,6 +69,7 @@ jobs: -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ -DSKIP_AFL_PLUS_PLUS=ON \ -DSKIP_KLEE=ON \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ -DENABLE_TEST=ON env: CC: /usr/bin/clang-16 @@ -99,6 +108,9 @@ jobs: sudo tar xzf /tmp/wabt.tar.gz -C /opt sudo ln -sf /opt/wabt-1.0.41/bin/wasm2c /usr/local/bin/wasm2c + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + - name: Generate compile_commands.json run: | mkdir -p build && cd build @@ -106,6 +118,7 @@ jobs: -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ -DSKIP_AFL_PLUS_PLUS=ON \ -DSKIP_KLEE=ON \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ -DENABLE_TEST=ON \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON env: @@ -129,23 +142,6 @@ jobs: modules/frontend/ \ tests/unit/ - - name: Run cppcheck (C backend) - # Blocking since the backend was cleared of all findings - # (migration-schedule item 2.0.12 / OpenSSF static_analysis_fixed) - run: | - cppcheck \ - --enable=warning,portability \ - --suppress=missingIncludeSystem \ - --suppress=unknownMacro \ - --suppress=unusedFunction \ - --suppressions-list=.cppcheck-suppressions.txt \ - --inline-suppr \ - --error-exitcode=1 \ - --std=c11 \ - --language=c \ - -I modules/ \ - modules/backend/library/ - - name: Build (for clang-tidy) run: cd build && ninja env: @@ -186,6 +182,9 @@ jobs: sudo tar xzf /tmp/wabt.tar.gz -C /opt sudo ln -sf /opt/wabt-1.0.41/bin/wasm2c /usr/local/bin/wasm2c + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + - name: Configure CMake with Sanitizers run: | mkdir -p build && cd build @@ -193,6 +192,7 @@ jobs: -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ -DSKIP_AFL_PLUS_PLUS=ON \ -DSKIP_KLEE=ON \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ -DENABLE_TEST=ON \ -DMAP2CHECK_ENABLE_SANITIZERS=ON env: @@ -214,6 +214,50 @@ jobs: UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1" run: cd build && ctest --output-on-failure + # =========================================================== + # Job: KLEE runtime bitcode of map2check-library + # =========================================================== + # The release archive does not ship the symex (KLEE) runtime; it is built + # from the same pinned tag with rustc 1.72.1 (LLVM 16) and handed to the + # Docker jobs below as -DMAP2CHECK_RUST_KLEE_BC. Cached on the script, + # which holds the pin. + klee-runtime: + name: KLEE Runtime Bitcode + runs-on: ubuntu-22.04 + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache the bitcode + id: cache + uses: actions/cache@v4 + with: + path: m2c-klee/map2check-klee.bc + key: map2check-klee-bc-${{ hashFiles('scripts/runtime/build-map2check-klee-bc.sh') }} + + - name: Install LLVM 16 tools + rustc 1.72.1 + if: steps.cache.outputs.cache-hit != 'true' + run: | + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc + echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" | sudo tee /etc/apt/sources.list.d/llvm-16.list + sudo apt-get update + sudo apt-get install -y llvm-16 + rustup toolchain install 1.72.1 --profile minimal + + - name: Build map2check-klee.bc + if: steps.cache.outputs.cache-hit != 'true' + run: bash scripts/runtime/build-map2check-klee-bc.sh m2c-klee/map2check-klee.bc + + - name: Upload the bitcode + uses: actions/upload-artifact@v4 + with: + name: map2check-klee-bc + path: m2c-klee/map2check-klee.bc + if-no-files-found: error + retention-days: 7 + # =========================================================== # Job 4: WASM End-to-End Tests (Docker) # =========================================================== @@ -225,7 +269,7 @@ jobs: name: WASM E2E Tests (Docker) runs-on: ubuntu-22.04 timeout-minutes: 45 - needs: [build-and-test] + needs: [build-and-test, klee-runtime] steps: - name: Checkout @@ -241,11 +285,26 @@ jobs: - name: Pull map2check-dev image run: docker pull ghcr.io/hbgit/map2check-dev:latest + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + + - name: Download KLEE runtime bitcode + uses: actions/download-artifact@v4 + with: + name: map2check-klee-bc + path: ${{ runner.temp }}/m2c-klee + + - name: Stage KLEE runtime bitcode + run: | + sudo install -D -m 644 "${{ runner.temp }}/m2c-klee/map2check-klee.bc" \ + /opt/map2check-library/klee/map2check-klee.bc + - name: Build + install Map2Check in container run: | docker run --rm \ -u root \ -v "${{ github.workspace }}:/workspace" \ + -v /opt/map2check-library:/opt/map2check-library:ro \ -w /workspace \ -e CC=/usr/bin/clang-16 \ -e CXX=/usr/bin/clang++-16 \ @@ -266,6 +325,8 @@ jobs: mkdir -p build_e2e && cd build_e2e cmake .. -G Ninja \ -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ + -DMAP2CHECK_RUST_KLEE_BC=/opt/map2check-library/klee/map2check-klee.bc \ -DENABLE_TEST=ON \ -DMAP2CHECK_DYNAMIC_LINK=ON \ -DCMAKE_INSTALL_PREFIX=/workspace/install_e2e @@ -310,7 +371,7 @@ jobs: name: CASTLE Regression runs-on: ubuntu-22.04 timeout-minutes: 20 - needs: [build-and-test] + needs: [build-and-test, klee-runtime] steps: - name: Checkout @@ -326,11 +387,26 @@ jobs: - name: Pull map2check-dev image run: docker pull ghcr.io/hbgit/map2check-dev:latest + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + + - name: Download KLEE runtime bitcode + uses: actions/download-artifact@v4 + with: + name: map2check-klee-bc + path: ${{ runner.temp }}/m2c-klee + + - name: Stage KLEE runtime bitcode + run: | + sudo install -D -m 644 "${{ runner.temp }}/m2c-klee/map2check-klee.bc" \ + /opt/map2check-library/klee/map2check-klee.bc + - name: Build + install Map2Check in container run: | docker run --rm \ -u root \ -v "${{ github.workspace }}:/workspace" \ + -v /opt/map2check-library:/opt/map2check-library:ro \ -w /workspace \ -e CC=/usr/bin/clang-16 \ -e CXX=/usr/bin/clang++-16 \ @@ -339,6 +415,8 @@ jobs: mkdir -p build_castle_ci && cd build_castle_ci cmake .. -G Ninja \ -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ + -DMAP2CHECK_RUST_KLEE_BC=/opt/map2check-library/klee/map2check-klee.bc \ -DENABLE_TEST=ON \ -DMAP2CHECK_DYNAMIC_LINK=ON \ -DCMAKE_INSTALL_PREFIX=/workspace/install_castle_ci @@ -387,7 +465,7 @@ jobs: name: Invariants (Clam) runs-on: ubuntu-22.04 timeout-minutes: 25 - needs: [build-and-test] + needs: [build-and-test, klee-runtime] steps: - name: Checkout @@ -403,11 +481,26 @@ jobs: - name: Pull map2check-dev image run: docker pull ghcr.io/hbgit/map2check-dev:latest + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + + - name: Download KLEE runtime bitcode + uses: actions/download-artifact@v4 + with: + name: map2check-klee-bc + path: ${{ runner.temp }}/m2c-klee + + - name: Stage KLEE runtime bitcode + run: | + sudo install -D -m 644 "${{ runner.temp }}/m2c-klee/map2check-klee.bc" \ + /opt/map2check-library/klee/map2check-klee.bc + - name: Build with -DENABLE_CLAM=ON run: | docker run --rm \ -u root \ -v "${{ github.workspace }}:/workspace" \ + -v /opt/map2check-library:/opt/map2check-library:ro \ -w /workspace \ -e CC=/usr/bin/clang-16 \ -e CXX=/usr/bin/clang++-16 \ @@ -416,6 +509,8 @@ jobs: mkdir -p build_clam_ci && cd build_clam_ci cmake .. -G Ninja \ -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ + -DMAP2CHECK_RUST_KLEE_BC=/opt/map2check-library/klee/map2check-klee.bc \ -DENABLE_CLAM=ON \ -DMAP2CHECK_DYNAMIC_LINK=ON \ -DCMAKE_INSTALL_PREFIX=/workspace/install_clam_ci @@ -452,7 +547,7 @@ jobs: name: Test-Comp Validation (TestCov) runs-on: ubuntu-22.04 timeout-minutes: 25 - needs: [build-and-test] + needs: [build-and-test, klee-runtime] steps: - name: Checkout @@ -468,11 +563,26 @@ jobs: - name: Pull map2check-dev image run: docker pull ghcr.io/hbgit/map2check-dev:latest + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + + - name: Download KLEE runtime bitcode + uses: actions/download-artifact@v4 + with: + name: map2check-klee-bc + path: ${{ runner.temp }}/m2c-klee + + - name: Stage KLEE runtime bitcode + run: | + sudo install -D -m 644 "${{ runner.temp }}/m2c-klee/map2check-klee.bc" \ + /opt/map2check-library/klee/map2check-klee.bc + - name: Build + install Map2Check in container run: | docker run --rm \ -u root \ -v "${{ github.workspace }}:/workspace" \ + -v /opt/map2check-library:/opt/map2check-library:ro \ -w /workspace \ -e CC=/usr/bin/clang-16 \ -e CXX=/usr/bin/clang++-16 \ @@ -481,6 +591,8 @@ jobs: mkdir -p build_testcov_ci && cd build_testcov_ci cmake .. -G Ninja \ -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ + -DMAP2CHECK_RUST_KLEE_BC=/opt/map2check-library/klee/map2check-klee.bc \ -DMAP2CHECK_DYNAMIC_LINK=ON \ -DCMAKE_INSTALL_PREFIX=/workspace/install_testcov_ci ninja @@ -547,6 +659,9 @@ jobs: sudo tar xzf /tmp/wabt.tar.gz -C /opt sudo ln -sf /opt/wabt-1.0.41/bin/wasm2c /usr/local/bin/wasm2c + - name: Fetch map2check-library (Rust runtime) + run: sudo bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library + - name: Configure CMake (Debug, sem sanitizers) run: | mkdir -p build && cd build @@ -554,6 +669,7 @@ jobs: -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ -DSKIP_AFL_PLUS_PLUS=ON \ -DSKIP_KLEE=ON \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ -DENABLE_TEST=ON \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_C_FLAGS="-gdwarf-4" \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 9a8080ba2..3f428564a 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -392,6 +392,29 @@ ENV PATH="${WASI_SDK_PATH}/bin:${PATH}" RUN ${WASI_SDK_PATH}/bin/clang --version && \ ${WASI_SDK_PATH}/bin/wasm-ld --version +# ============================================================ +# 9b. Map2Check runtime: map2check-library (Rust), pinned release +# ============================================================ +# The release archive (SHA-256 pinned in the script) holds the static library +# Map2Check links (lib/libmap2check_runtime.a). The KLEE runtime bitcode is +# not in the archive: it is built from the same tag (commit pinned in the +# script) with rustc 1.72.1, whose LLVM is 16, and the LLVM 16 tools above. +# The Rust toolchain only serves this build and is removed afterwards. +# Map2Check's CMake reads MAP2CHECK_RUST_LIB_DIR / MAP2CHECK_RUST_KLEE_BC +# from the environment (cmake/Map2CheckRustRuntime.cmake). +COPY scripts/runtime/fetch-map2check-library.sh scripts/runtime/build-map2check-klee-bc.sh /tmp/m2c-runtime/ +RUN bash /tmp/m2c-runtime/fetch-map2check-library.sh /opt/map2check-library && \ + export RUSTUP_HOME=/tmp/m2c-rustup CARGO_HOME=/tmp/m2c-cargo && \ + curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal \ + --default-toolchain 1.72.1 --no-modify-path && \ + PATH="/tmp/m2c-cargo/bin:${PATH}" bash /tmp/m2c-runtime/build-map2check-klee-bc.sh \ + /opt/map2check-library/klee/map2check-klee.bc && \ + llvm-dis-16 /opt/map2check-library/klee/map2check-klee.bc -o /dev/null && \ + rm -rf /tmp/m2c-runtime /tmp/m2c-rustup /tmp/m2c-cargo + +ENV MAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib +ENV MAP2CHECK_RUST_KLEE_BC=/opt/map2check-library/klee/map2check-klee.bc + # ============================================================ # 10. User setup # ============================================================ diff --git a/scripts/runtime/fetch-map2check-library.sh b/scripts/runtime/fetch-map2check-library.sh new file mode 100755 index 000000000..c75ace0b5 --- /dev/null +++ b/scripts/runtime/fetch-map2check-library.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Downloads the pinned map2check-library release (the Rust runtime Map2Check +# links), checks its SHA-256 and extracts it into DEST (default +# /opt/map2check-library): DEST/include/map2check.h and DEST/lib/*.a. +# Configure Map2Check with -DMAP2CHECK_RUST_LIB_DIR=DEST/lib. +# +# The pin lives here only; CI (.github/workflows/ci.yml) and Dockerfile.dev +# both call this script. +# +# Usage: scripts/runtime/fetch-map2check-library.sh [DEST] +set -euo pipefail + +M2C_LIB_VERSION="1.1.0-rc1" +M2C_LIB_TARGET="x86_64-unknown-linux-gnu" +M2C_LIB_SHA256="dd90e8885288a0de03d4d2b8624b6cb4a8ebee9f53ed9adcbf42501910209666" +M2C_LIB_NAME="map2check-library-${M2C_LIB_VERSION}-${M2C_LIB_TARGET}" +M2C_LIB_URL="https://github.com/hbgit/map2check-library/releases/download/v${M2C_LIB_VERSION}/${M2C_LIB_NAME}.tar.gz" + +dest="${1:-/opt/map2check-library}" +die() { echo "fetch-map2check-library: $*" >&2; exit 1; } + +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT +archive="$work/${M2C_LIB_NAME}.tar.gz" + +wget -q "$M2C_LIB_URL" -O "$archive" || die "download failed: $M2C_LIB_URL" +echo "${M2C_LIB_SHA256} ${archive}" | sha256sum -c --quiet - || + die "SHA-256 mismatch for ${M2C_LIB_NAME}.tar.gz" + +mkdir -p "$dest" +tar xzf "$archive" -C "$dest" --strip-components=1 --no-same-owner +for f in include/map2check.h lib/libmap2check_runtime.a; do + [ -f "$dest/$f" ] || die "$dest/$f missing after extraction" +done +grep -qxF "#define MAP2CHECK_VERSION \"${M2C_LIB_VERSION}\"" "$dest/include/map2check.h" || + die "$dest/include/map2check.h is not version ${M2C_LIB_VERSION}" +echo "fetch-map2check-library: ${M2C_LIB_NAME} -> $dest" From 7f348f79c9d3d6b74e71bd4f974b12a552fdda71 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 11:39:05 -0400 Subject: [PATCH 36/44] ci: commit the KLEE bitcode script and suppress a fixture finding scripts/runtime/build-map2check-klee-bc.sh matched the *build-* pattern of .gitignore and never reached the branch; it is now map2check-klee-bc.sh. cppcheck over tests/unit flags memleakOnRealloc in tests/unit/pass/inputs/memtrack.c, a PassIRTest input whose 'p = realloc(p, ...)' is the pattern the realloc instrumentation is tested on. Suppress that id for that file only. --- .cppcheck-suppressions.txt | 1 + .github/workflows/ci.yml | 4 ++-- Dockerfile.dev | 4 ++-- scripts/runtime/map2check-klee-bc.sh | 29 ++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100755 scripts/runtime/map2check-klee-bc.sh diff --git a/.cppcheck-suppressions.txt b/.cppcheck-suppressions.txt index b8fb28cd1..40f1679e6 100644 --- a/.cppcheck-suppressions.txt +++ b/.cppcheck-suppressions.txt @@ -6,3 +6,4 @@ unusedFunction:modules/backend/pass/* unusedFunction:modules/backend/library/* uninitMemberVar missingReturn:modules/frontend/counter_example/* +memleakOnRealloc:tests/unit/pass/inputs/memtrack.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb11b1f45..de9997750 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -235,7 +235,7 @@ jobs: uses: actions/cache@v4 with: path: m2c-klee/map2check-klee.bc - key: map2check-klee-bc-${{ hashFiles('scripts/runtime/build-map2check-klee-bc.sh') }} + key: map2check-klee-bc-${{ hashFiles('scripts/runtime/map2check-klee-bc.sh') }} - name: Install LLVM 16 tools + rustc 1.72.1 if: steps.cache.outputs.cache-hit != 'true' @@ -248,7 +248,7 @@ jobs: - name: Build map2check-klee.bc if: steps.cache.outputs.cache-hit != 'true' - run: bash scripts/runtime/build-map2check-klee-bc.sh m2c-klee/map2check-klee.bc + run: bash scripts/runtime/map2check-klee-bc.sh m2c-klee/map2check-klee.bc - name: Upload the bitcode uses: actions/upload-artifact@v4 diff --git a/Dockerfile.dev b/Dockerfile.dev index 3f428564a..27f2ec724 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -402,12 +402,12 @@ RUN ${WASI_SDK_PATH}/bin/clang --version && \ # The Rust toolchain only serves this build and is removed afterwards. # Map2Check's CMake reads MAP2CHECK_RUST_LIB_DIR / MAP2CHECK_RUST_KLEE_BC # from the environment (cmake/Map2CheckRustRuntime.cmake). -COPY scripts/runtime/fetch-map2check-library.sh scripts/runtime/build-map2check-klee-bc.sh /tmp/m2c-runtime/ +COPY scripts/runtime/fetch-map2check-library.sh scripts/runtime/map2check-klee-bc.sh /tmp/m2c-runtime/ RUN bash /tmp/m2c-runtime/fetch-map2check-library.sh /opt/map2check-library && \ export RUSTUP_HOME=/tmp/m2c-rustup CARGO_HOME=/tmp/m2c-cargo && \ curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal \ --default-toolchain 1.72.1 --no-modify-path && \ - PATH="/tmp/m2c-cargo/bin:${PATH}" bash /tmp/m2c-runtime/build-map2check-klee-bc.sh \ + PATH="/tmp/m2c-cargo/bin:${PATH}" bash /tmp/m2c-runtime/map2check-klee-bc.sh \ /opt/map2check-library/klee/map2check-klee.bc && \ llvm-dis-16 /opt/map2check-library/klee/map2check-klee.bc -o /dev/null && \ rm -rf /tmp/m2c-runtime /tmp/m2c-rustup /tmp/m2c-cargo diff --git a/scripts/runtime/map2check-klee-bc.sh b/scripts/runtime/map2check-klee-bc.sh new file mode 100755 index 000000000..9411ef4fd --- /dev/null +++ b/scripts/runtime/map2check-klee-bc.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Builds the KLEE (symex) runtime bitcode of the pinned map2check-library +# release, which the release archive does not ship: a checkout of the tag, +# verified against its commit, then the library's own +# scripts/build-klee-runtime.sh. Configure Map2Check with +# -DMAP2CHECK_RUST_KLEE_BC=. +# +# Needs rustup with the 1.72.1 toolchain installed (its LLVM is 16), the LLVM +# 16 tools (opt-16, llvm-dis-16, llvm-nm-16, llvm-as-16, lli-16), python3, git. +# +# Usage: scripts/runtime/map2check-klee-bc.sh +set -euo pipefail + +M2C_LIB_TAG="v1.1.0-rc1" +M2C_LIB_COMMIT="49a25e40fe8b52932db1f0adfdfa896bac65fb5c" +M2C_LIB_REPO="https://github.com/hbgit/map2check-library.git" + +die() { echo "map2check-klee-bc: $*" >&2; exit 1; } +[ $# -eq 1 ] || die "usage: $0 " +out="$(realpath -m "$1")" + +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT +git -c advice.detachedHead=false clone -q --depth 1 --branch "$M2C_LIB_TAG" "$M2C_LIB_REPO" "$work/src" +got="$(git -C "$work/src" rev-parse HEAD)" +[ "$got" = "$M2C_LIB_COMMIT" ] || die "$M2C_LIB_TAG is $got, expected $M2C_LIB_COMMIT" + +mkdir -p "$(dirname "$out")" +CARGO_TARGET_DIR="$work/target" "$work/src/scripts/build-klee-runtime.sh" "$out" From 0fa359a74d1620a6044f0ef2ffee1c0c9ef63c44 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 11:54:38 -0400 Subject: [PATCH 37/44] test(testcomp): loop_reads.c is COVERED under the Rust runtime The TestCov gate observed COVERED where expected.txt said NOT_COVERED (finding K). The cause is the runtime: the C one formatted each symbolic nondet value in uClibc's vfprintf, forking on every digit, while the Rust KLEE runtime concretizes the value before writing it (D1 condition 7), so the test vector comes out within the budget. --- tests/testcomp/README.md | 6 ++++-- tests/testcomp/expected.txt | 25 ++++++++++--------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/tests/testcomp/README.md b/tests/testcomp/README.md index f74f5aa84..b1c1d08f5 100644 --- a/tests/testcomp/README.md +++ b/tests/testcomp/README.md @@ -76,8 +76,10 @@ Results: 5 passed, 1 failed (exit 1) The gate goes red, as it must. But note **which** program caught it: only `two_guards.c`. The others are structurally insensitive to ordering — one input each, -or none — and `loop_reads.c`, which has four and would also have caught it, is -currently undecided by the tool (finding K). +or none — and `loop_reads.c`, which has four and would also have caught it, was +then undecided by the tool (finding K). It is COVERED since the Rust runtime +(see `expected.txt`), so it is now the second witness the next paragraph asks +for; the run above predates it. So the ordering guarantee rests on a single program today. Two consequences worth keeping in mind: do not remove `two_guards.c` without adding another multi-input diff --git a/tests/testcomp/expected.txt b/tests/testcomp/expected.txt index 38b0185a6..4973667e9 100644 --- a/tests/testcomp/expected.txt +++ b/tests/testcomp/expected.txt @@ -17,20 +17,15 @@ no_input.c COVERED char_input.c COVERED unreachable.c NOT_COVERED -# loop_reads.c -- NOT_COVERED, and the reason is now known (finding K). +# loop_reads.c -- COVERED since the Rust runtime (map2check-library +# v1.1.0-rc1, feat/rust-runtime). # -# Map2Check DOES find the violation here. Running with --debug shows -# "TARGET-REACHED found" -- the property file is written -- and then KLEE is -# killed by the timeout while still exploring other states, at which point -# map2check.cpp forces the verdict to UNKNOWN and throws the violation away: -# -# if (caller->isTimeout()) { propertyViolated = UNKNOWN; } -# -# So no suite is emitted and the suite cannot cover anything. The emitter is -# never reached, and the emitter is not at fault. -# -# This line becomes COVERED once the verdict logic consults the property before -# forcing UNKNOWN on timeout. The gate will insist on the update, which is the -# point of keeping the case here instead of deleting it. +# It was NOT_COVERED from finding K until then. KLEE reached the target, but +# the C runtime formatted every symbolic nondet value inside uClibc's +# vfprintf, where each digit forks, so the run spent its budget there and no +# test vector came out. The Rust KLEE runtime concretizes each value +# (klee_get_value + klee_assume) before writing it (D1 condition 7; see +# docs/klee-feasibility.md of map2check-library), which removes the +# explosion. Observed COVERED at BUDGET=120 in the CI run of PR #76. # See docs/reports/2026-08-12-castle-juliet-findings.md, finding K. -loop_reads.c NOT_COVERED +loop_reads.c COVERED From d2820f836818b7f1a8a48febdf9f21234e923e04 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 11:54:38 -0400 Subject: [PATCH 38/44] fix(invariants): run Clam on bitcode input too With --add-invariants and a .bc input the frontend still took compileCFile, so Clam never ran. test_add_invariants.sh passed anyway: it matched the name map2check_crab_assume anywhere in the scratch bitcode, and the C runtime linked into the result bitcode defines it. With the Rust runtime that definition is gone and the check failed. compileWithClam now takes the bitcode as Clam's input as is, and the test requires a call to verifier.assume or map2check_crab_assume, not just the name. --- modules/frontend/caller.cpp | 72 ++++++++++++++---------- modules/frontend/caller.hpp | 5 +- modules/frontend/map2check.cpp | 10 +++- tests/integration/test_add_invariants.sh | 7 ++- 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/modules/frontend/caller.cpp b/modules/frontend/caller.cpp index a13f397ff..0407c2e2d 100644 --- a/modules/frontend/caller.cpp +++ b/modules/frontend/caller.cpp @@ -1081,39 +1081,43 @@ void Caller::compileCFile(bool is_llvm_bc) { // TODO(hbgit): (3) Check for overflow errors on compilation } -void Caller::compileWithClam() { +void Caller::compileWithClam(bool is_llvm_bc) { Map2Check::Log::Info("Compiling with Clam (invariants) in " + this->pathprogram); + // Bitcode input skips the C clean-up and the clang step below: the module + // goes to clam.py as is (clamInput), which skips its own clang step for + // bitcode. // (1) Remove unsupported functions and clean the C code - // TODO(hbgit): improve regex to the next line - std::ostringstream commandRemoveExternMalloc; - commandRemoveExternMalloc.str(""); - commandRemoveExternMalloc << "cat " << this->pathprogram << " | "; - commandRemoveExternMalloc << "sed -e 's/extern void [*].[^_]*lloc.*/ / g' " - << " > " << programHash << "-preprocessed.c "; - system(commandRemoveExternMalloc.str().c_str()); - - std::ostringstream commandRemoveExternMemset; - commandRemoveExternMemset.str(""); - commandRemoveExternMemset << "sed -i 's/extern void [*]memset.*/ / g' " - << " " << programHash << "-preprocessed.c "; - // Map2Check::Log::Info(commandRemoveExternMemset.str().c_str()); - system(commandRemoveExternMemset.str().c_str()); - - std::ostringstream commandRemoveVoidMemset; - commandRemoveVoidMemset.str(""); - commandRemoveVoidMemset << "sed -i 's/void [*]memset(void[*], int, size_t);/ / g' " - << " " << programHash << "-preprocessed.c "; - // Map2Check::Log::Info(commandRemoveExternMemset.str().c_str()); - system(commandRemoveVoidMemset.str().c_str()); - - std::ostringstream commandRemoveVoidMemcpy; - commandRemoveVoidMemcpy.str(""); - commandRemoveVoidMemcpy << "sed -i 's/void [*]memcpy(void[*], const void [*], size_t);/ / g' " - << " " << programHash << "-preprocessed.c "; - // Map2Check::Log::Info(commandRemoveExternMemset.str().c_str()); - system(commandRemoveVoidMemcpy.str().c_str()); + if (!is_llvm_bc) { + // TODO(hbgit): improve regex to the next line + std::ostringstream commandRemoveExternMalloc; + commandRemoveExternMalloc.str(""); + commandRemoveExternMalloc << "cat " << this->pathprogram << " | "; + commandRemoveExternMalloc << "sed -e 's/extern void [*].[^_]*lloc.*/ / g' " + << " > " << programHash << "-preprocessed.c "; + system(commandRemoveExternMalloc.str().c_str()); + + std::ostringstream commandRemoveExternMemset; + commandRemoveExternMemset.str(""); + commandRemoveExternMemset << "sed -i 's/extern void [*]memset.*/ / g' " + << " " << programHash << "-preprocessed.c "; + // Map2Check::Log::Info(commandRemoveExternMemset.str().c_str()); + system(commandRemoveExternMemset.str().c_str()); + + std::ostringstream commandRemoveVoidMemset; + commandRemoveVoidMemset.str(""); + commandRemoveVoidMemset << "sed -i 's/void [*]memset(void[*], int, size_t);/ / g' " + << " " << programHash << "-preprocessed.c "; + // Map2Check::Log::Info(commandRemoveExternMemset.str().c_str()); + system(commandRemoveVoidMemset.str().c_str()); + std::ostringstream commandRemoveVoidMemcpy; + commandRemoveVoidMemcpy.str(""); + commandRemoveVoidMemcpy << "sed -i 's/void [*]memcpy(void[*], const void [*], size_t);/ / g' " + << " " << programHash << "-preprocessed.c "; + // Map2Check::Log::Info(commandRemoveExternMemset.str().c_str()); + system(commandRemoveVoidMemcpy.str().c_str()); + } // (2) Generate .bc file from code // TODO(hbgit): -Winteger-overflow should be called only if is on overflow @@ -1198,8 +1202,14 @@ void Caller::compileWithClam() { << " -I" << clamRoot << "/include" << " -o " << clamInput << " " << programHash << "-preprocessed.c"; - Map2Check::Log::Debug(compileForClam.str()); - system(compileForClam.str().c_str()); + if (is_llvm_bc) { + std::ostringstream copyForClam; + copyForClam << "cp " << this->pathprogram << " " << clamInput; + system(copyForClam.str().c_str()); + } else { + Map2Check::Log::Debug(compileForClam.str()); + system(compileForClam.str().c_str()); + } command << Map2Check::clamBinary() << " -o " << compiledFile << " -m 64 -g" << " --crab-inter" diff --git a/modules/frontend/caller.hpp b/modules/frontend/caller.hpp index 4624fa0c8..c460f66a8 100644 --- a/modules/frontend/caller.hpp +++ b/modules/frontend/caller.hpp @@ -138,8 +138,9 @@ class Caller { /** Compiles the input through Clam so the emitted bitcode carries * verifier.assume(invariant) calls. Requires Clam dev16 installed; callers - * must have checked availability first (main() refuses the run otherwise). */ - void compileWithClam(); + * must have checked availability first (main() refuses the run otherwise). + * Bitcode input (is_llvm_bc) is handed to Clam as is. */ + void compileWithClam(bool is_llvm_bc); /** @brief Function to call pass for current verification mode * (for REACHABILITY mode) diff --git a/modules/frontend/map2check.cpp b/modules/frontend/map2check.cpp index 100d5db21..b19487fec 100644 --- a/modules/frontend/map2check.cpp +++ b/modules/frontend/map2check.cpp @@ -489,9 +489,13 @@ int map2check_execution(map2check_args args) { // generator is installed. The old code branched on !is_llvmir_in and so // never even looked at the flag for bitcode input -- how the baselines, the // CASTLE harness and the BenchExec wrappers all invoke the tool -- which is - // why it was ignored without a trace (issue #54). - if (!is_llvmir_in && args.invCrabLlvm) { - caller->compileWithClam(); + // why it was ignored without a trace (issue #54). The run was no longer + // refused, but bitcode input still took compileCFile and Clam never ran: + // test_add_invariants.sh passed only because the C runtime, linked into + // the result bitcode, defined map2check_crab_assume. Bitcode input goes + // through Clam too. + if (args.invCrabLlvm) { + caller->compileWithClam(is_llvmir_in); } else { caller->compileCFile(is_llvmir_in); } diff --git a/tests/integration/test_add_invariants.sh b/tests/integration/test_add_invariants.sh index 581250cfd..88ab7b63a 100644 --- a/tests/integration/test_add_invariants.sh +++ b/tests/integration/test_add_invariants.sh @@ -139,11 +139,14 @@ case "$CAPABILITY" in # The scratch directory (.map2check/) holds every intermediate: the # Clam-compiled bitcode carrying verifier.assume, and the instrumented one # where NonDetPass has rewritten it to map2check_crab_assume. Either symbol - # proves the invariants reached the pipeline. + # proves the invariants reached the pipeline -- as a CALL. A bare name + # match is not evidence: the C runtime, linked into the result bitcode, + # DEFINES map2check_crab_assume, and that definition alone made this + # check pass while bitcode input never went through Clam. found="" while IFS= read -r bc; do if llvm-dis-16 -o - "$bc" 2>/dev/null \ - | grep -q 'verifier\.assume\|map2check_crab_assume'; then + | grep -qE 'call [^@]*@(verifier\.assume|map2check_crab_assume)\('; then found="$bc" break fi From c57a4e8c15ed09dcc5f201358ac99447656d58ed Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 12:19:44 -0400 Subject: [PATCH 39/44] build(docker): pin and verify rustup-init instead of piping sh.rustup.rs The KLEE runtime layer ran 'curl https://sh.rustup.rs | sh' as root: the toolchain was pinned, the installer was not. Download rustup-init 1.28.2 for x86_64-unknown-linux-gnu from static.rust-lang.org/rustup/archive, check it against the SHA-256 of the .sha256 file published next to it, and run it with the same options; a mismatch stops the build. --- Dockerfile.dev | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index 27f2ec724..dae54e594 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -402,10 +402,20 @@ RUN ${WASI_SDK_PATH}/bin/clang --version && \ # The Rust toolchain only serves this build and is removed afterwards. # Map2Check's CMake reads MAP2CHECK_RUST_LIB_DIR / MAP2CHECK_RUST_KLEE_BC # from the environment (cmake/Map2CheckRustRuntime.cmake). +# rustup-init is pinned by version and SHA-256 (the value of the .sha256 file +# published next to it on static.rust-lang.org) and checked before it runs; +# a mismatch stops the build. +ARG RUSTUP_INIT_VERSION=1.28.2 +ARG RUSTUP_INIT_SHA256=20a06e644b0d9bd2fbdbfd52d42540bdde820ea7df86e92e533c073da0cdd43c COPY scripts/runtime/fetch-map2check-library.sh scripts/runtime/map2check-klee-bc.sh /tmp/m2c-runtime/ -RUN bash /tmp/m2c-runtime/fetch-map2check-library.sh /opt/map2check-library && \ +RUN set -eu && \ + bash /tmp/m2c-runtime/fetch-map2check-library.sh /opt/map2check-library && \ export RUSTUP_HOME=/tmp/m2c-rustup CARGO_HOME=/tmp/m2c-cargo && \ - curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal \ + wget -q "https://static.rust-lang.org/rustup/archive/${RUSTUP_INIT_VERSION}/x86_64-unknown-linux-gnu/rustup-init" \ + -O /tmp/m2c-runtime/rustup-init && \ + echo "${RUSTUP_INIT_SHA256} /tmp/m2c-runtime/rustup-init" | sha256sum -c --quiet - && \ + chmod +x /tmp/m2c-runtime/rustup-init && \ + /tmp/m2c-runtime/rustup-init -y --profile minimal \ --default-toolchain 1.72.1 --no-modify-path && \ PATH="/tmp/m2c-cargo/bin:${PATH}" bash /tmp/m2c-runtime/map2check-klee-bc.sh \ /opt/map2check-library/klee/map2check-klee.bc && \ From 58c2b0882a5888a984e7a316d499c6a1dae697b0 Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 12:19:44 -0400 Subject: [PATCH 40/44] fix: correct the loop_reads.c claim and two review minors loop_reads.c checks sum == 10, which any order of its reads satisfies, so it witnesses the count of the input sequence, not its order. The README, its table and the program comment said otherwise. Note that the environment defaults of the runtime cache variables apply only on the first configure of a build directory, and raise the Valgrind job timeout from 30 to 45 minutes: its ctest step now takes about 15. --- .github/workflows/ci.yml | 2 +- cmake/Map2CheckRustRuntime.cmake | 2 ++ tests/testcomp/README.md | 11 ++++++----- tests/testcomp/programs/loop_reads.c | 7 ++++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de9997750..fcb448530 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -637,7 +637,7 @@ jobs: valgrind-memcheck: name: Valgrind Memcheck (ctest) runs-on: ubuntu-22.04 - timeout-minutes: 30 + timeout-minutes: 45 steps: - name: Checkout diff --git a/cmake/Map2CheckRustRuntime.cmake b/cmake/Map2CheckRustRuntime.cmake index 68093e4dd..05c3a1f14 100644 --- a/cmake/Map2CheckRustRuntime.cmake +++ b/cmake/Map2CheckRustRuntime.cmake @@ -6,6 +6,8 @@ # # The defaults come from the environment variables of the same name, which the # map2check-dev image sets (Dockerfile.dev); -D on the command line wins. +# Being CACHE defaults, they are read only on the first configure of a build +# directory: after the environment changes, reconfigure in a fresh one. set(MAP2CHECK_RUST_LIB_DIR "$ENV{MAP2CHECK_RUST_LIB_DIR}" CACHE PATH "Directory with a prebuilt libmap2check.a (empty = build from MAP2CHECK_RUST_SRC)") set(MAP2CHECK_RUST_SRC "$ENV{MAP2CHECK_RUST_SRC}" CACHE PATH "map2check-library checkout used when MAP2CHECK_RUST_LIB_DIR is empty") set(MAP2CHECK_RUST_KLEE_BC "$ENV{MAP2CHECK_RUST_KLEE_BC}" CACHE FILEPATH "Prebuilt KLEE runtime bitcode (empty = none, or built from MAP2CHECK_RUST_SRC when rustc 1.72.1 is available)") diff --git a/tests/testcomp/README.md b/tests/testcomp/README.md index b1c1d08f5..d4f7ca3aa 100644 --- a/tests/testcomp/README.md +++ b/tests/testcomp/README.md @@ -38,7 +38,7 @@ Each program isolates one thing the emitter can get wrong: | `two_guards.c` | Ordering of two inputs — right values, wrong order reaches nothing | | `no_input.c` | The empty test vector, which a naive emitter drops entirely | | `char_input.c` | A non-`int` nondet type, i.e. a different branch of the value serializer | -| `loop_reads.c` | Four reads, where an off-by-one in count or order becomes visible | +| `loop_reads.c` | Four reads summed, where an off-by-one in count becomes visible (order does not: the sum is commutative) | | `unreachable.c` | **Negative control** — the error cannot be reached by any input | `unreachable.c` earns its place: if it ever reports `COVERED`, the harness is lying @@ -76,10 +76,11 @@ Results: 5 passed, 1 failed (exit 1) The gate goes red, as it must. But note **which** program caught it: only `two_guards.c`. The others are structurally insensitive to ordering — one input each, -or none — and `loop_reads.c`, which has four and would also have caught it, was -then undecided by the tool (finding K). It is COVERED since the Rust runtime -(see `expected.txt`), so it is now the second witness the next paragraph asks -for; the run above predates it. +or none — and `loop_reads.c` was then undecided by the tool (finding K). It is COVERED +since the Rust runtime (see `expected.txt`), but it is not a second witness +of ordering: it checks `sum == 10`, which any order of its four reads +satisfies. It witnesses the count of the input sequence (a dropped or +duplicated value), not its order. So the ordering guarantee rests on a single program today. Two consequences worth keeping in mind: do not remove `two_guards.c` without adding another multi-input diff --git a/tests/testcomp/programs/loop_reads.c b/tests/testcomp/programs/loop_reads.c index e88e47f16..19b29490c 100644 --- a/tests/testcomp/programs/loop_reads.c +++ b/tests/testcomp/programs/loop_reads.c @@ -1,6 +1,7 @@ -// Four reads inside a loop. A suite that recovers the values but drops one, or -// reorders them, cannot reach the error -- so this checks the ordering -// contract at a length where an off-by-one is visible. +// Four reads inside a loop. A suite that recovers the values but drops or +// duplicates one cannot reach the error -- so this checks the count of the +// input sequence at a length where an off-by-one is visible. It does not +// check ordering: any order of the same four values gives the same sum. extern int __VERIFIER_nondet_int(void); extern void reach_error(void); From 490a676bcc6d603328eea258d3cafcc4c0f51bcb Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 12:53:39 -0400 Subject: [PATCH 41/44] docs: document the Rust runtime build variables and the cutover in the changelog README build section: MAP2CHECK_RUST_LIB_DIR, MAP2CHECK_RUST_SRC and MAP2CHECK_RUST_KLEE_BC, and map2check-library 1.1.0-rc1 as the minimum version. CHANGELOG: "Runtime replaced by map2check-library (Rust)". --- CHANGELOG.md | 7 +++++++ README.md | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff411b8a9..d2b9dd7a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ The format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.0. ### Changed +- Runtime replaced by map2check-library (Rust). The C runtime of + `modules/backend/library` is no longer built or installed; Map2Check links + map2check-library 1.1.0-rc1 or later (`libmap2check.a`, plus + `map2check-klee.bc` for symex), selected with `MAP2CHECK_RUST_LIB_DIR`, + `MAP2CHECK_RUST_SRC` and `MAP2CHECK_RUST_KLEE_BC` (see the README build + section). The verdict differences from the C runtime are listed in + `tests/cutover/deltas-aceitos.tsv`. - Replaced LibFuzzer with AFL++ 4.40c (persistent, PCGUARD) as the fuzzing engine. - tacasv2a: `--slice` no longer crashes KLEE and its test suites stay valid on the original program. The slicer runs with `-cutoff-diverging=false` diff --git a/README.md b/README.md index 9fcf74bfe..275d27838 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,20 @@ $ ninja && ninja install The `Dockerfile.dev` image already builds and installs KLEE 3.1 (to `/opt/klee`) and installs AFL++ 4.40c as a standalone toolchain (found at run time under `/usr/local/bin`), so **do not** pass `-DSKIP_KLEE=ON` or `-DSKIP_AFL_PLUS_PLUS=ON` — those flags skip the `cmake/FindKlee.cmake` / `cmake/FindAFLPlusPlus.cmake` modules entirely. Only pass them `ON` if you deliberately want a build without KLEE/AFL++ support (e.g. `-DSKIP_AFL_PLUS_PLUS=ON -DSKIP_KLEE=ON` for a minimal/CI build). +**Runtime library.** The runtime that Map2Check links into the analysed program is [map2check-library](https://github.com/hbgit/map2check-library) (Rust, C ABI); it replaced the C runtime of `modules/backend/library`. The **minimum supported version is 1.1.0-rc1** (the version pinned in [scripts/runtime/fetch-map2check-library.sh](scripts/runtime/fetch-map2check-library.sh)). CMake takes it from one of these variables (each defaults to the environment variable of the same name, which `Dockerfile.dev` sets, so the build above needs no extra flag): + +- `MAP2CHECK_RUST_LIB_DIR`: a directory with a prebuilt library. Use the `lib/` of the release archive `map2check-library--x86_64-unknown-linux-gnu.tar.gz` (`scripts/runtime/fetch-map2check-library.sh ` downloads and verifies it; pass `/lib`), whose `libmap2check_runtime.a` is the one linked. A local build directory (`target/runtime` of `cargo build --profile runtime --features libfuzzer,wasm`) also works. Configure fails if the directory only has the featureless core `libmap2check.a`. +- `MAP2CHECK_RUST_SRC`: a map2check-library checkout, built by the Map2Check build with `cargo build --profile runtime --features libfuzzer,wasm`. Used only when `MAP2CHECK_RUST_LIB_DIR` is empty. +- `MAP2CHECK_RUST_KLEE_BC` (optional, needed for `--nondet-generator symex`): the KLEE runtime bitcode (LLVM 16). The release archive does not ship it; build it with `scripts/runtime/map2check-klee-bc.sh ` (needs rustc 1.72.1 and the LLVM 16 tools). + +``` bash +$ bash scripts/runtime/fetch-map2check-library.sh /opt/map2check-library +$ bash scripts/runtime/map2check-klee-bc.sh /opt/map2check-library/klee/map2check-klee.bc +$ cmake .. -G Ninja -DLLVM_DIR=/usr/lib/llvm-16/lib/cmake/llvm \ + -DMAP2CHECK_RUST_LIB_DIR=/opt/map2check-library/lib \ + -DMAP2CHECK_RUST_KLEE_BC=/opt/map2check-library/klee/map2check-klee.bc +``` + **Building with WASM support** requires **no additional CMake flag** — the `WasmLifter` frontend module is always compiled. The only extra build-time dependency is the WABT 1.0.41 header `wasm-rt.h`: when CMake finds it (searched at `/opt/wabt-1.0.41/include`, `/usr/include`, `/usr/local/include`), it compiles the KLEE-compatible wasm2c runtime `WasmRuntimeStubs.c` to bitcode and installs it as `release/lib/WasmRuntimeStubs.bc`, which is linked into the lifted module when `--wasm` is used. If `wasm-rt.h` is not found, CMake prints a warning and the build proceeds **without** WASM support (the recommended way to get a WASM-enabled build is the Docker image above, which ships WABT and the wasi-sdk out of the box). Minor test: From f7f15e3bc10cc40ec3eb89f2fb8ddc1b0e1d86ab Mon Sep 17 00:00:00 2001 From: Herbert Rocha Date: Sat, 17 Oct 2026 12:59:08 -0400 Subject: [PATCH 42/44] build: refuse the core libmap2check.a when the runtime build is missing MAP2CHECK_RUST_LIB_DIR without libmap2check_runtime.a used to fall back to libmap2check.a silently. In the release archive that name is the featureless core build, which lacks the libfuzzer and wasm entry points. The fallback now requires the archive to define LLVMFuzzerTestOneInput and map2check_wasm_malloc, as a local target/runtime build does, and configure fails with a clear message otherwise. llvm-nm-16 cannot read the members (rustc's newer bitcode), so every nm on the PATH is tried. test_rust_runtime_cmake.sh: cases for the local layout (accepted) and for a directory holding only a core build, synthetic and the release one (rejected). --- cmake/Map2CheckRustRuntime.cmake | 47 +++++++++++++++++++++--- tests/cutover/test_rust_runtime_cmake.sh | 40 ++++++++++++++++++-- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/cmake/Map2CheckRustRuntime.cmake b/cmake/Map2CheckRustRuntime.cmake index 05c3a1f14..4feb505f1 100644 --- a/cmake/Map2CheckRustRuntime.cmake +++ b/cmake/Map2CheckRustRuntime.cmake @@ -17,16 +17,51 @@ if(MAP2CHECK_RUST_LIB_DIR) # The release archive (lib/ of map2check-library--.tar.gz) # ships three builds; the one Map2Check links is libmap2check_runtime.a # (profile runtime, features libfuzzer,wasm). Its libmap2check.a is the - # featureless core build. A directory without libmap2check_runtime.a is a - # local `cargo build --profile runtime` output (target/runtime). + # featureless core build. A directory without libmap2check_runtime.a must + # be a local `cargo build --profile runtime --features libfuzzer,wasm` + # output (target/runtime), whose libmap2check.a is the runtime build under + # the plain name. That fallback is accepted only when the archive defines + # the symbols of both features (LLVMFuzzerTestOneInput: libfuzzer; + # map2check_wasm_malloc: wasm), so the core build, which defines neither, + # is never picked by accident. if(EXISTS "${MAP2CHECK_RUST_LIB_DIR}/libmap2check_runtime.a") set(_m2c_rust_lib "${MAP2CHECK_RUST_LIB_DIR}/libmap2check_runtime.a") else() set(_m2c_rust_lib "${MAP2CHECK_RUST_LIB_DIR}/libmap2check.a") - endif() - if(NOT EXISTS "${_m2c_rust_lib}") - message(FATAL_ERROR "libmap2check.a not found in ${MAP2CHECK_RUST_LIB_DIR} " - "(nor libmap2check_runtime.a; build it with: cargo build --profile runtime --features libfuzzer,wasm)") + if(NOT EXISTS "${_m2c_rust_lib}") + message(FATAL_ERROR "libmap2check.a not found in ${MAP2CHECK_RUST_LIB_DIR} " + "(nor libmap2check_runtime.a; build it with: cargo build --profile runtime --features libfuzzer,wasm)") + endif() + # Any nm that can read the archive will do. The members carry bitcode + # from rustc's LLVM, newer than 16, which llvm-nm-16 (the CMAKE_NM of a + # clang-16 toolchain) rejects, so the other nm programs are tried too. + find_program(M2C_NM nm) + find_program(M2C_LLVM_NM llvm-nm) + set(_m2c_nms ${CMAKE_NM} ${M2C_NM} ${M2C_LLVM_NM}) + list(REMOVE_DUPLICATES _m2c_nms) + set(_m2c_missing LLVMFuzzerTestOneInput map2check_wasm_malloc) + foreach(_m2c_nm IN LISTS _m2c_nms) + execute_process(COMMAND "${_m2c_nm}" -g --defined-only "${_m2c_rust_lib}" + OUTPUT_VARIABLE _m2c_nm_out ERROR_QUIET) + set(_m2c_missing_here "") + foreach(_m2c_sym LLVMFuzzerTestOneInput map2check_wasm_malloc) + if(NOT _m2c_nm_out MATCHES " T ${_m2c_sym}(\n|$)") + list(APPEND _m2c_missing_here ${_m2c_sym}) + endif() + endforeach() + if(NOT _m2c_missing_here) + set(_m2c_missing "") + break() + endif() + endforeach() + if(_m2c_missing) + list(JOIN _m2c_missing ", " _m2c_missing) + message(FATAL_ERROR "${_m2c_rust_lib} is not the Map2Check runtime build: " + "it does not define ${_m2c_missing} (the featureless core libmap2check.a " + "defines neither). Point MAP2CHECK_RUST_LIB_DIR at the lib/ of the " + "map2check-library release archive (it has libmap2check_runtime.a), or at " + "the target/runtime of: cargo build --profile runtime --features libfuzzer,wasm") + endif() endif() elseif(MAP2CHECK_RUST_SRC) find_program(M2C_CARGO cargo REQUIRED) diff --git a/tests/cutover/test_rust_runtime_cmake.sh b/tests/cutover/test_rust_runtime_cmake.sh index a5fb5a173..a755877d0 100755 --- a/tests/cutover/test_rust_runtime_cmake.sh +++ b/tests/cutover/test_rust_runtime_cmake.sh @@ -3,8 +3,9 @@ # map2check-klee.bc) is installed, no C runtime bitcode; configure fails loudly # without a library or with an unreadable bitcode. # -# Env: MAP2CHECK_RUST_LIB_DIR directory with libmap2check.a, or the lib/ of -# the release archive (required) +# Env: MAP2CHECK_RUST_LIB_DIR directory with the runtime-profile libmap2check.a +# (target/runtime), or the lib/ of the release +# archive (required) # CMAKE_ARGS extra configure flags (e.g. -G Ninja -DLLVM_DIR=...) set -euo pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)" @@ -22,6 +23,8 @@ install_tree() { # ; prints nothing, installs to $W } # 1. Only the Rust static library is installed; no C runtime .bc. +# The runtime build (features libfuzzer,wasm) in $LIB, whatever its layout. +if [ -f "$LIB/libmap2check_runtime.a" ]; then RT="$LIB/libmap2check_runtime.a"; else RT="$LIB/libmap2check.a"; fi install_tree plain -DMAP2CHECK_RUST_LIB_DIR="$LIB" P="$W/plain-p" test -f "$P/lib/libmap2check.a" || fail "libmap2check.a not installed" @@ -34,12 +37,43 @@ fi # runtime build, libmap2check_runtime.a, is the one installed as # libmap2check.a; the featureless core libmap2check.a next to it is not. R="$W/release-lib"; mkdir "$R" -cp "$LIB/libmap2check.a" "$R/libmap2check_runtime.a" +cp "$RT" "$R/libmap2check_runtime.a" echo 'not the runtime' >"$R/libmap2check.a" install_tree release -DMAP2CHECK_RUST_LIB_DIR="$R" cmp -s "$W/release-p/lib/libmap2check.a" "$R/libmap2check_runtime.a" || fail "release layout: libmap2check_runtime.a not installed as libmap2check.a" +# 1c. Local build layout (target/runtime): only libmap2check.a, and it is the +# runtime build, so it is accepted under the plain name. +T="$W/local-lib"; mkdir "$T" +cp "$RT" "$T/libmap2check.a" +install_tree local -DMAP2CHECK_RUST_LIB_DIR="$T" +cmp -s "$W/local-p/lib/libmap2check.a" "$RT" || + fail "local layout: the runtime-profile libmap2check.a not installed" + +# 1d. Only a featureless core libmap2check.a (no libmap2check_runtime.a next +# to it): configure must fail instead of linking a runtime without the +# libfuzzer and wasm entry points. +check_core_rejected() { #