This guide covers what a C program or an instrumentation pass needs to use
the Rust map2check-library: the release contents, how to link, call
order, the JSON report and the known gaps. Compatibility details are in
api-deltas.md (symbols and signatures) and
semantic-deltas.md (behaviour).
A release archive map2check-library-<version>-<target>.tar.gz (see
release.md) unpacks to:
map2check-library-<version>-<target>/
├── include/map2check.h # C header; MAP2CHECK_VERSION == <version>
├── lib/libmap2check.a # plain C programs (no features)
├── lib/libmap2check_libfuzzer.a # LibFuzzer targets (feature libfuzzer)
├── lib/libmap2check_runtime.a # runtime profile, features libfuzzer,wasm
├── docs/integration-guide.md
├── docs/api-deltas.md
├── docs/semantic-deltas.md
├── CHANGELOG.md
└── LICENSE # GPL-3.0-only
A SHA256SUMS file next to the archive covers it.
Without a release archive, run this from the repository root:
cargo build --release # plain C programs
cargo build --release --features libfuzzer # LibFuzzer targets (overwrites the same .a)The build Map2Check links is the runtime profile (release optimisations
with panic = "unwind", so the FFI guard can recover panics):
cargo build --profile runtime --features libfuzzer,wasm # target/runtime/libmap2check.aThe runtime of Map2Check's KLEE (symex) generator is one LLVM 16 bitcode
module built from klee/Cargo.toml with rustc 1.72.1 and the LLVM 16 tools
(opt-16, llvm-dis-16, ...). It is not part of the release archive:
scripts/build-klee-runtime.sh out/map2check_klee.bcbuild.rs regenerates include/map2check.h on every build. The header is
not committed (.gitignore), so always take it from the same build as the
library.
cc -I include my_program.c lib/libmap2check.a -ldl -lpthread -lm -o my_program-
-ldl -lpthread -lmare the system libraries that the Rust standard library needs. -
Use
lib/libmap2check.afor ordinary programs. It does not define the__VERIFIER_*functions orLLVMFuzzerTestOneInput, even though the header declares them. -
Use
lib/libmap2check_libfuzzer.afor LibFuzzer targets. It definesLLVMFuzzerTestOneInput, which callsint __map2check_main__(void). The program must define that function and be built withclang -fsanitize=fuzzer. Without that function, the link fails withundefined reference to '__map2check_main__'. -
The header and the library must come from the same build. The header carries the version as a string,
MAP2CHECK_VERSION(for example"1.1.0-rc1"), so you can log it or check it in your build:#include "map2check.h" #ifndef MAP2CHECK_VERSION #error "map2check.h is older than 1.1.0-rc1" #endif
map2check_init()once, before any other call.- Tracking calls as the program runs:
map2check_save_basic_block_log,map2check_save_nondet_log_*,map2check_map_*. - Check calls next to the operation they guard:
map2check_check_load,map2check_check_free,map2check_check_deref,map2check_binop_*,map2check_is_valid_assert. - Optionally,
map2check_set_memcleanup()and thenmap2check_check_mem_endprog()at exit. map2check_success()orprint_all_containers_as_json()to emit the report;get_current_property()reads the verdict without printing.map2check_reset()to analyse another input in the same process. LibFuzzer builds do this on every iteration.
A violation does not stop the program, but the first violation is final:
later checks, safe or not, and later set_false_result calls leave it in
place (SD-03). Only map2check_init(), map2check_reset() and
vcc_reset_meta_data() clear it.
print_all_containers_as_json() prints one pretty-printed JSON object on
stdout when no analysis mode is set (with a mode set, a Map2Check run, it
prints nothing; see below). Whitespace is not part of the contract; parse it. The examples
below are checked against the real serializer by
tests/compat_docs.rs::integration_guide_json_examples_match_the_serializer.
Calls map2check_save_basic_block_log(10, "main") and then
map2check_save_nondet_log_int(11, 0, INT_ID, &seven, "main") print:
{
"map2check_log": {
"result": "TRUE",
"step": 2,
"Container_TrackBBLog": [
{ "step": 1, "line": 10, "function_name": "main" }
],
"Container_NonDetLog": [
{
"step": 2,
"line": 11,
"scope": 0,
"function_name": "main",
"value": { "type": "INT", "value": 7 }
}
]
}
}The same calls followed by set_false_result(5 /* Reachability */, 12, "main")
print:
{
"map2check_log": {
"result": "FALSE",
"step": 2,
"property": "REACHABILITY",
"line_number": 12,
"function_name": "main",
"Container_TrackBBLog": [
{ "step": 1, "line": 10, "function_name": "main" }
],
"Container_NonDetLog": [
{
"step": 2,
"line": 11,
"scope": 0,
"function_name": "main",
"value": { "type": "INT", "value": 7 }
}
]
}
}Container_AllocationLog appears only for memory-safety violations (SD-02).
map2check_map_malloc((void *)0x1000, 16) followed by
map2check_check_free("p", (void *)0x10, (void *)0x2000, 0, 20, "main")
(free of p, at 0x10, holding 0x2000) prints:
{
"map2check_log": {
"result": "FALSE",
"step": 1,
"property": "MEMSAFETY_FREE",
"line_number": 20,
"function_name": "main",
"Container_TrackBBLog": [],
"Container_NonDetLog": [],
"Container_AllocationLog": [
{
"step": 1,
"line": 0,
"scope": 0,
"var_mem_address": 4096,
"mem_address_points_to": 4096,
"is_dynamic": true,
"is_free": false,
"ptr_name": "",
"function_name": "",
"size_destiny": 16,
"size_primitive": 1,
"is_null_valid": false
}
]
}
}property takes one of OVERFLOW, MEMSAFETY_FREE, MEMSAFETY_DEREF,
MEMSAFETY_MEMTRACK, MEMSAFETY_MEMCLEANUP, REACHABILITY,
CONCURRENCY, ASSERT and UNKNOWN. Nondet type takes one of INT, UINT, LONG, CHAR,
FLOAT and DOUBLE. Map2Check does not read this JSON: it reads the
result files described below. The JSON is an additional channel with its
own schema, pinned by a snapshot test (#14, SD-01).
A Map2Check-instrumented program calls map2check_set_mode() before
map2check_init(), and the witness binary also calls
map2check_enable_witness(). With a mode set, the library writes into the
current directory the files the Map2Check frontend reads, byte for byte as
the C runtime of Map2Check develop does: map2check_property*, and with
witness on track_bb_log.st, heap_log.csv, allocation_log.csv,
list_log.csv, klee_log.csv and map2check_checked_error. The first
violation ends the process with abort(); map2check_success() returns
when the end-of-program verdict holds. Without a mode nothing is written
and nothing aborts. See “Result files” in api-deltas.md.
- Map2Check passes: the passes of
hbgit/Map2Check@developinsert a different symbol family (map2check_track_bb,map2check_alloca, …) and cannot link against this library yet. See the pass matrix inapi-deltas.mdand #21. - KLEE: no KLEE build exists yet; the decision is #20.
- Thread safety: the state sits behind one global mutex. The calls are safe from any thread but serialise, and a callback must not re-enter the library while a call is running.