From 7892fb8428c25f21ce40e7ca70d00319e4d562c5 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 14 Mar 2025 09:58:46 +0100 Subject: [PATCH 01/64] WIP: Start working on Miri-GenMC interop. - Add genmc-sys crate for building GenMC C++ code. - Implemented program features: - Handling of atomic loads, stores, allocations and deallocations. - Implement consistent address allocations for globals - Non-global addresses allocated by GenMC. - Limitation: No address randomization. - Limitation: No address reuse. - Handling of non-atomic memory accesses. - Limitation: need to split up NA reads and stores into max 8 byte chunks. - Limitation: no mixed size access support. - Limitation: Incomplete (unsound) handling of uninitialized memory. - Implement Pointer conversions to and from GenMC - Limitation: Aliasing model checking must be disabled. - Handling of Read-Modify-Write, Compare-Exchange and Atomic Exchange operations. - Limitation: Compare-Exchange currently ignores possibility of spurious failures. - Limitation: Compare-Exchange failure memory ordering is ignored. - Handling of thread creation and finishing. - Added Miri to GenMC thread id mapping. - Implement mutex lock, try_lock and unlock. - Make use of annotations to reduce number of blocked executions for programs with mutexes. - Add estimation mode for Miri-GenMC. - Limitation: Printing currently handled on C++ side (Should be moved once VerificationResult is available to Rust code) - Thread scheduling in Miri done through GenMC, add loop over eval_entry function. - Rebase GenMC to use new scheduler. - Added GenMC `__VERIFIER_assume` equivalent for Miri (`miri_genmc_verifier_assume`) - Add warnings for GenMC mode for unsupported features. - Add a lot of test, including translation of GenMC litmus tests. - Only run tests if 'genmc' feature enabled. - WIP: try implementing NonNullUniquePtr wrapper for CXX. - WIP: work on mixed atomic/non-atomics. - Partially working, some issues with globals - FIX: Make naming consistent with GenMC for blocked execution - Add git support to build, move C++ files into genmc-sys crate - Implement building GenMC-Miri after GenMC codebase split. - WIP: temporarily point GenMC repo to private branch. --- Cargo.lock | 560 ++++++++ Cargo.toml | 8 +- genmc-sys/.gitignore | 3 + genmc-sys/Cargo.lock | 788 ++++++++++++ genmc-sys/Cargo.toml | 17 + genmc-sys/build.rs | 184 +++ genmc-sys/src/lib.rs | 304 +++++ genmc-sys/src_cpp/MiriInterface.cpp | 524 ++++++++ genmc-sys/src_cpp/MiriInterface.hpp | 232 ++++ src/alloc_addresses/mod.rs | 26 +- src/bin/miri.rs | 42 +- src/concurrency/data_race.rs | 73 +- src/concurrency/genmc/config.rs | 51 +- src/concurrency/genmc/cxx_extra.rs | 48 + src/concurrency/genmc/dummy.rs | 84 +- src/concurrency/genmc/global_allocations.rs | 145 +++ src/concurrency/genmc/helper.rs | 230 ++++ src/concurrency/genmc/mapping.rs | 83 ++ src/concurrency/genmc/miri_genmc.rs | 73 ++ src/concurrency/genmc/mod.rs | 1130 ++++++++++++++++- src/concurrency/genmc/thread_info_manager.rs | 95 ++ src/concurrency/genmc/warnings.rs | 66 + src/concurrency/mod.rs | 4 +- src/concurrency/thread.rs | 91 +- src/concurrency/weak_memory.rs | 3 + src/diagnostics.rs | 13 +- src/eval.rs | 3 +- src/lib.rs | 2 +- src/machine.rs | 29 +- src/shims/foreign_items.rs | 16 + .../_disabled/fail/weak_memory/weak_uninit.rs | 57 + tests/genmc/fail/simple/2w2w_acq_rel.rs | 44 + tests/genmc/fail/simple/2w2w_acq_rel.stderr | 15 + tests/genmc/fail/simple/2w2w_relaxed.rs | 44 + tests/genmc/fail/simple/2w2w_relaxed.stderr | 15 + .../read_global_init.rs | 20 + .../read_global_init.stderr | 15 + .../wna_wrlx_rrlx.return1234.stderr | 15 + .../wna_wrlx_rrlx.return42.stderr | 15 + .../mixed-atomic-non-atomic/wna_wrlx_rrlx.rs | 58 + .../basics/mutex/TODO_mutex_get_mut.rs.txt | 0 tests/genmc/pass/basics/mutex/mutex_simple.c | 72 ++ .../mutex/mutex_simple.order12reps1.stderr | 3 + .../mutex/mutex_simple.order12reps2.stderr | 3 + .../mutex/mutex_simple.order21reps1.stderr | 3 + .../mutex/mutex_simple.order21reps2.stderr | 3 + tests/genmc/pass/basics/mutex/mutex_simple.rs | 73 ++ .../basics/rmw/rmw_edge_cases.i16_.stderr | 3 + .../basics/rmw/rmw_edge_cases.i32_.stderr | 3 + .../basics/rmw/rmw_edge_cases.i64_.stderr | 3 + .../pass/basics/rmw/rmw_edge_cases.i8_.stderr | 3 + .../basics/rmw/rmw_edge_cases.isize_.stderr | 3 + tests/genmc/pass/basics/rmw/rmw_edge_cases.rs | 89 ++ .../basics/rmw/rmw_edge_cases.u16_.stderr | 3 + .../basics/rmw/rmw_edge_cases.u32_.stderr | 3 + .../basics/rmw/rmw_edge_cases.u64_.stderr | 3 + .../pass/basics/rmw/rmw_edge_cases.u8_.stderr | 3 + .../basics/rmw/rmw_edge_cases.usize_.stderr | 3 + tests/genmc/pass/basics/rmw/rmw_simple.rs | 29 + tests/genmc/pass/basics/rmw/rmw_simple.stderr | 3 + .../pass/data-structures/ms_queue_dynamic.rs | 224 ++++ .../data-structures/ms_queue_dynamic.stderr | 3 + .../data-structures/treiber_stack_dynamic.rs | 211 +++ .../treiber_stack_dynamic.stderr | 3 + .../2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr | 3 + .../2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr | 3 + .../pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs | 43 + .../litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs | 33 + .../litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr | 3 + tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs | 33 + .../pass/litmus/2+2W+4sc/2_2w_4sc.stderr | 3 + .../genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs | 35 + .../pass/litmus/2+2W+scfs/2_2w_scfs.stderr | 3 + .../pass/litmus/2+2w/2W2W.order12.stderr | 3 + .../pass/litmus/2+2w/2W2W.order21.stderr | 3 + tests/genmc/pass/litmus/2+2w/2W2W.rs | 42 + .../pass/litmus/2CoWR/2cowr.order1234.stderr | 3 + .../pass/litmus/2CoWR/2cowr.order2341.stderr | 3 + .../pass/litmus/2CoWR/2cowr.order3412.stderr | 3 + .../pass/litmus/2CoWR/2cowr.order4123.stderr | 3 + .../pass/litmus/2CoWR/2cowr.order4321.stderr | 3 + tests/genmc/pass/litmus/2CoWR/2cowr.rs | 57 + .../pass/litmus/CoRR/corr.order12.stderr | 3 + .../pass/litmus/CoRR/corr.order21.stderr | 3 + tests/genmc/pass/litmus/CoRR/corr.rs | 41 + .../pass/litmus/CoRR0/corr0.order123.stderr | 3 + .../pass/litmus/CoRR0/corr0.order231.stderr | 3 + .../pass/litmus/CoRR0/corr0.order312.stderr | 3 + .../pass/litmus/CoRR0/corr0.order321.stderr | 3 + tests/genmc/pass/litmus/CoRR0/corr0.rs | 48 + .../pass/litmus/CoRR1/corr1.order1234.stderr | 3 + .../pass/litmus/CoRR1/corr1.order2341.stderr | 3 + .../pass/litmus/CoRR1/corr1.order3412.stderr | 3 + .../pass/litmus/CoRR1/corr1.order4123.stderr | 3 + .../pass/litmus/CoRR1/corr1.order4321.stderr | 3 + tests/genmc/pass/litmus/CoRR1/corr1.rs | 57 + .../pass/litmus/CoRR2/corr2.order1234.stderr | 3 + .../pass/litmus/CoRR2/corr2.order2341.stderr | 3 + .../pass/litmus/CoRR2/corr2.order3412.stderr | 3 + .../pass/litmus/CoRR2/corr2.order4123.stderr | 3 + .../pass/litmus/CoRR2/corr2.order4321.stderr | 3 + tests/genmc/pass/litmus/CoRR2/corr2.rs | 57 + .../pass/litmus/CoRW/corw.order12.stderr | 3 + .../pass/litmus/CoRW/corw.order21.stderr | 3 + tests/genmc/pass/litmus/CoRW/corw.rs | 40 + .../pass/litmus/CoWR/cowr.order12.stderr | 3 + .../pass/litmus/CoWR/cowr.order21.stderr | 3 + tests/genmc/pass/litmus/CoWR/cowr.rs | 40 + .../pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs | 45 + .../litmus/IRIW-acq-sc/IRIW-acq-sc.stderr | 3 + tests/genmc/pass/litmus/IRIWish/IRIWish.rs | 48 + .../genmc/pass/litmus/IRIWish/IRIWish.stderr | 3 + .../genmc/pass/litmus/LB+incMPs/LB_incMPs.rs | 48 + .../pass/litmus/LB+incMPs/LB_incMPs.stderr | 3 + tests/genmc/pass/litmus/LB/LB.order12.stderr | 3 + tests/genmc/pass/litmus/LB/LB.order21.stderr | 3 + tests/genmc/pass/litmus/LB/LB.rs | 42 + .../genmc/pass/litmus/MP+incMPs/MP_incMPs.rs | 41 + .../pass/litmus/MP+incMPs/MP_incMPs.stderr | 3 + .../pass/litmus/MP+rels+acqf/MP_rels_acqf.rs | 40 + .../litmus/MP+rels+acqf/MP_rels_acqf.stderr | 3 + tests/genmc/pass/litmus/MP/MP.order12.stderr | 3 + tests/genmc/pass/litmus/MP/MP.order21.stderr | 3 + tests/genmc/pass/litmus/MP/MP.rs | 42 + .../pass/litmus/MPU+rels+acq/MPU_rels_acq.rs | 43 + .../litmus/MPU+rels+acq/MPU_rels_acq.stderr | 3 + .../litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs | 51 + .../MPU2+rels+acqf/MPU2_rels_acqf.stderr | 3 + .../pass/litmus/SB+2sc+scf/SB_2sc_scf.rs | 35 + .../pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr | 3 + tests/genmc/pass/litmus/SB/SB.order12.stderr | 3 + tests/genmc/pass/litmus/SB/SB.order21.stderr | 3 + tests/genmc/pass/litmus/SB/SB.rs | 42 + .../pass/litmus/Z6+acq/Z6_acq.order123.stderr | 3 + .../pass/litmus/Z6+acq/Z6_acq.order321.stderr | 3 + tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs | 51 + tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs | 40 + tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr | 3 + .../pass/litmus/assume-ctrl/assume-ctrl.rs | 42 + .../litmus/assume-ctrl/assume-ctrl.stderr | 4 + tests/genmc/pass/litmus/atomicpo/atomicpo.rs | 34 + .../pass/litmus/atomicpo/atomicpo.stderr | 3 + tests/genmc/pass/litmus/casdep/casdep.rs | 34 + tests/genmc/pass/litmus/casdep/casdep.stderr | 3 + tests/genmc/pass/litmus/ccr/ccr.rs | 33 + tests/genmc/pass/litmus/ccr/ccr.stderr | 3 + tests/genmc/pass/litmus/cii/cii.rs | 36 + tests/genmc/pass/litmus/cii/cii.stderr | 3 + .../litmus/cumul-release/cumul-release.rs | 42 + .../litmus/cumul-release/cumul-release.stderr | 3 + .../litmus/default/default.order123.stderr | 3 + .../litmus/default/default.order231.stderr | 3 + .../litmus/default/default.order312.stderr | 3 + .../litmus/default/default.order321.stderr | 3 + tests/genmc/pass/litmus/default/default.rs | 49 + tests/genmc/pass/litmus/detour/detour.rs | 42 + tests/genmc/pass/litmus/detour/detour.stderr | 3 + .../litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs | 45 + .../fr_w_w_w_reads/fr_w_w_w_reads.stderr | 3 + tests/genmc/pass/litmus/inc2w/inc2w.rs | 37 + tests/genmc/pass/litmus/inc2w/inc2w.stderr | 3 + .../litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs | 63 + .../inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr | 3 + tests/genmc/pass/litmus/riwi/riwi.rs | 34 + tests/genmc/pass/litmus/riwi/riwi.stderr | 3 + .../litmus/viktor-relseq/viktor-relseq.rs | 43 + .../litmus/viktor-relseq/viktor-relseq.stderr | 3 + .../simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs | 52 + .../simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr | 3 + tests/genmc/pass/simple/2w2w_seqcst.rs | 46 + tests/genmc/pass/simple/2w2w_seqcst.stderr | 3 + tests/genmc/pass/simple/atomic_ptr.rs | 83 ++ tests/genmc/pass/simple/atomic_ptr.stderr | 3 + tests/genmc/pass/simple/atomic_simple.rs | 17 + tests/genmc/pass/simple/atomic_simple.stderr | 3 + tests/genmc/pass/simple/cas_simple.rs | 47 + tests/genmc/pass/simple/cas_simple.stderr | 3 + tests/genmc/pass/simple/simple_main.rs | 3 + tests/genmc/pass/simple/simple_main.stderr | 7 + .../pass/simple/simple_main_spawn_threads.rs | 10 + .../simple/simple_main_spawn_threads.stderr | 9 + .../simple/simple_miri_main_spawn_pthreads.rs | 35 + .../simple_miri_main_spawn_pthreads.stderr | 3 + .../simple/simple_miri_main_spawn_threads.rs | 15 + .../simple_miri_main_spawn_threads.stderr | 9 + tests/genmc/pass/simple/stack_alloc_atomic.rs | 18 + .../pass/simple/stack_alloc_atomic.stderr | 3 + tests/genmc/pass/simple/thread_locals.rs | 54 + tests/genmc/pass/simple/thread_locals.stderr | 3 + tests/genmc/pass/simple/thread_simple.rs | 34 + tests/genmc/pass/simple/thread_simple.stderr | 3 + tests/ui.rs | 4 + tests/utils-dep/genmc.rs | 27 + tests/utils-dep/miri_extern.rs | 2 + tests/utils-dep/mod.rs | 8 + tests/utils/miri_extern.rs | 3 + 196 files changed, 8132 insertions(+), 176 deletions(-) create mode 100644 genmc-sys/.gitignore create mode 100644 genmc-sys/Cargo.lock create mode 100644 genmc-sys/Cargo.toml create mode 100644 genmc-sys/build.rs create mode 100644 genmc-sys/src/lib.rs create mode 100644 genmc-sys/src_cpp/MiriInterface.cpp create mode 100644 genmc-sys/src_cpp/MiriInterface.hpp create mode 100644 src/concurrency/genmc/cxx_extra.rs create mode 100644 src/concurrency/genmc/global_allocations.rs create mode 100644 src/concurrency/genmc/helper.rs create mode 100644 src/concurrency/genmc/mapping.rs create mode 100644 src/concurrency/genmc/miri_genmc.rs create mode 100644 src/concurrency/genmc/thread_info_manager.rs create mode 100644 src/concurrency/genmc/warnings.rs create mode 100644 tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs create mode 100644 tests/genmc/fail/simple/2w2w_acq_rel.rs create mode 100644 tests/genmc/fail/simple/2w2w_acq_rel.stderr create mode 100644 tests/genmc/fail/simple/2w2w_relaxed.rs create mode 100644 tests/genmc/fail/simple/2w2w_relaxed.stderr create mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs create mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr create mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr create mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr create mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs create mode 100644 tests/genmc/pass/basics/mutex/TODO_mutex_get_mut.rs.txt create mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.c create mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr create mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr create mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr create mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr create mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.rs create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.rs create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr create mode 100644 tests/genmc/pass/basics/rmw/rmw_simple.rs create mode 100644 tests/genmc/pass/basics/rmw/rmw_simple.stderr create mode 100644 tests/genmc/pass/data-structures/ms_queue_dynamic.rs create mode 100644 tests/genmc/pass/data-structures/ms_queue_dynamic.stderr create mode 100644 tests/genmc/pass/data-structures/treiber_stack_dynamic.rs create mode 100644 tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr create mode 100644 tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr create mode 100644 tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr create mode 100644 tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs create mode 100644 tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs create mode 100644 tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr create mode 100644 tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs create mode 100644 tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr create mode 100644 tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs create mode 100644 tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr create mode 100644 tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr create mode 100644 tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr create mode 100644 tests/genmc/pass/litmus/2+2w/2W2W.rs create mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr create mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr create mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr create mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr create mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr create mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.rs create mode 100644 tests/genmc/pass/litmus/CoRR/corr.order12.stderr create mode 100644 tests/genmc/pass/litmus/CoRR/corr.order21.stderr create mode 100644 tests/genmc/pass/litmus/CoRR/corr.rs create mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr create mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr create mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr create mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr create mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.rs create mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr create mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr create mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr create mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr create mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr create mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.rs create mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr create mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr create mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr create mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr create mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr create mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.rs create mode 100644 tests/genmc/pass/litmus/CoRW/corw.order12.stderr create mode 100644 tests/genmc/pass/litmus/CoRW/corw.order21.stderr create mode 100644 tests/genmc/pass/litmus/CoRW/corw.rs create mode 100644 tests/genmc/pass/litmus/CoWR/cowr.order12.stderr create mode 100644 tests/genmc/pass/litmus/CoWR/cowr.order21.stderr create mode 100644 tests/genmc/pass/litmus/CoWR/cowr.rs create mode 100644 tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs create mode 100644 tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr create mode 100644 tests/genmc/pass/litmus/IRIWish/IRIWish.rs create mode 100644 tests/genmc/pass/litmus/IRIWish/IRIWish.stderr create mode 100644 tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs create mode 100644 tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr create mode 100644 tests/genmc/pass/litmus/LB/LB.order12.stderr create mode 100644 tests/genmc/pass/litmus/LB/LB.order21.stderr create mode 100644 tests/genmc/pass/litmus/LB/LB.rs create mode 100644 tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs create mode 100644 tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr create mode 100644 tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs create mode 100644 tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr create mode 100644 tests/genmc/pass/litmus/MP/MP.order12.stderr create mode 100644 tests/genmc/pass/litmus/MP/MP.order21.stderr create mode 100644 tests/genmc/pass/litmus/MP/MP.rs create mode 100644 tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs create mode 100644 tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr create mode 100644 tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs create mode 100644 tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr create mode 100644 tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs create mode 100644 tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr create mode 100644 tests/genmc/pass/litmus/SB/SB.order12.stderr create mode 100644 tests/genmc/pass/litmus/SB/SB.order21.stderr create mode 100644 tests/genmc/pass/litmus/SB/SB.rs create mode 100644 tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr create mode 100644 tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr create mode 100644 tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs create mode 100644 tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs create mode 100644 tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr create mode 100644 tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs create mode 100644 tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr create mode 100644 tests/genmc/pass/litmus/atomicpo/atomicpo.rs create mode 100644 tests/genmc/pass/litmus/atomicpo/atomicpo.stderr create mode 100644 tests/genmc/pass/litmus/casdep/casdep.rs create mode 100644 tests/genmc/pass/litmus/casdep/casdep.stderr create mode 100644 tests/genmc/pass/litmus/ccr/ccr.rs create mode 100644 tests/genmc/pass/litmus/ccr/ccr.stderr create mode 100644 tests/genmc/pass/litmus/cii/cii.rs create mode 100644 tests/genmc/pass/litmus/cii/cii.stderr create mode 100644 tests/genmc/pass/litmus/cumul-release/cumul-release.rs create mode 100644 tests/genmc/pass/litmus/cumul-release/cumul-release.stderr create mode 100644 tests/genmc/pass/litmus/default/default.order123.stderr create mode 100644 tests/genmc/pass/litmus/default/default.order231.stderr create mode 100644 tests/genmc/pass/litmus/default/default.order312.stderr create mode 100644 tests/genmc/pass/litmus/default/default.order321.stderr create mode 100644 tests/genmc/pass/litmus/default/default.rs create mode 100644 tests/genmc/pass/litmus/detour/detour.rs create mode 100644 tests/genmc/pass/litmus/detour/detour.stderr create mode 100644 tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs create mode 100644 tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr create mode 100644 tests/genmc/pass/litmus/inc2w/inc2w.rs create mode 100644 tests/genmc/pass/litmus/inc2w/inc2w.stderr create mode 100644 tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs create mode 100644 tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr create mode 100644 tests/genmc/pass/litmus/riwi/riwi.rs create mode 100644 tests/genmc/pass/litmus/riwi/riwi.stderr create mode 100644 tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs create mode 100644 tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr create mode 100644 tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs create mode 100644 tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr create mode 100644 tests/genmc/pass/simple/2w2w_seqcst.rs create mode 100644 tests/genmc/pass/simple/2w2w_seqcst.stderr create mode 100644 tests/genmc/pass/simple/atomic_ptr.rs create mode 100644 tests/genmc/pass/simple/atomic_ptr.stderr create mode 100644 tests/genmc/pass/simple/atomic_simple.rs create mode 100644 tests/genmc/pass/simple/atomic_simple.stderr create mode 100644 tests/genmc/pass/simple/cas_simple.rs create mode 100644 tests/genmc/pass/simple/cas_simple.stderr create mode 100644 tests/genmc/pass/simple/simple_main.rs create mode 100644 tests/genmc/pass/simple/simple_main.stderr create mode 100644 tests/genmc/pass/simple/simple_main_spawn_threads.rs create mode 100644 tests/genmc/pass/simple/simple_main_spawn_threads.stderr create mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs create mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr create mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs create mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr create mode 100644 tests/genmc/pass/simple/stack_alloc_atomic.rs create mode 100644 tests/genmc/pass/simple/stack_alloc_atomic.stderr create mode 100644 tests/genmc/pass/simple/thread_locals.rs create mode 100644 tests/genmc/pass/simple/thread_locals.stderr create mode 100644 tests/genmc/pass/simple/thread_simple.rs create mode 100644 tests/genmc/pass/simple/thread_simple.stderr create mode 100644 tests/utils-dep/genmc.rs create mode 100644 tests/utils-dep/miri_extern.rs create mode 100644 tests/utils-dep/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 0af4181dc1..82287fee05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,6 +170,8 @@ version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -214,6 +216,52 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width 0.2.1", +] + [[package]] name = "color-eyre" version = "0.6.5" @@ -313,6 +361,68 @@ dependencies = [ "typenum", ] +[[package]] +name = "cxx" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df" +dependencies = [ + "cc", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "directories" version = "6.0.0" @@ -334,12 +444,29 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "encode_unicode" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.13" @@ -372,6 +499,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -382,6 +524,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "genmc-sys" +version = "0.11.0" +dependencies = [ + "cmake", + "cxx", + "cxx-build", + "git2", +] + [[package]] name = "getrandom" version = "0.2.16" @@ -411,12 +563,150 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + [[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "indicatif" version = "0.17.11" @@ -463,6 +753,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -510,6 +810,20 @@ dependencies = [ "cc", ] +[[package]] +name = "libgit2-sys" +version = "0.18.2+1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + [[package]] name = "libloading" version = "0.8.8" @@ -530,12 +844,53 @@ dependencies = [ "libc", ] +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "lock_api" version = "0.4.13" @@ -611,7 +966,9 @@ dependencies = [ "chrono", "chrono-tz", "colored 3.0.0", + "cxx", "directories", + "genmc-sys", "getrandom 0.3.3", "ipc-channel", "libc", @@ -672,6 +1029,24 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -722,6 +1097,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "perf-event-open-sys" version = "3.0.0" @@ -755,12 +1136,27 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "portable-atomic" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -946,6 +1342,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scratch" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" + [[package]] name = "semver" version = "1.0.26" @@ -1025,6 +1427,18 @@ dependencies = [ "color-eyre", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.104" @@ -1036,6 +1450,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tempfile" version = "3.20.0" @@ -1049,6 +1474,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -1108,6 +1542,16 @@ dependencies = [ "libc", ] +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tracing" version = "0.1.41" @@ -1199,6 +1643,23 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "uuid" version = "1.17.0" @@ -1216,6 +1677,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -1305,6 +1772,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "windows" version = "0.58.0" @@ -1524,6 +2000,36 @@ dependencies = [ "bitflags", ] +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.26" @@ -1543,3 +2049,57 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index d293af5cea..e35619b3ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,8 @@ chrono-tz = "0.10" directories = "6" bitflags = "2.6" serde_json = { version = "1.0", optional = true } +cxx = { version = "1.0.143", features = ["c++20"], optional = true } +genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } # Copied from `compiler/rustc/Cargo.toml`. # But only for some targets, it fails for others. Rustc configures this in its CI, but we can't @@ -65,8 +67,10 @@ name = "ui" harness = false [features] -default = ["stack-cache", "native-lib"] -genmc = [] +# TODO GENMC (DEBUGGING): `genmc` feature should be turned off in upstream repo for now +default = ["stack-cache", "genmc"] +# default = ["stack-cache", "native-lib"] +genmc = ["dep:cxx", "dep:genmc-sys"] stack-cache = [] stack-cache-consistency-check = ["stack-cache"] tracing = ["serde_json"] diff --git a/genmc-sys/.gitignore b/genmc-sys/.gitignore new file mode 100644 index 0000000000..f35ff32fdf --- /dev/null +++ b/genmc-sys/.gitignore @@ -0,0 +1,3 @@ +genmc/ +genmc-*/ +vendored/ diff --git a/genmc-sys/Cargo.lock b/genmc-sys/Cargo.lock new file mode 100644 index 0000000000..5efeb8f27a --- /dev/null +++ b/genmc-sys/Cargo.lock @@ -0,0 +1,788 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "clap" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + +[[package]] +name = "cxx" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1149bab7a5580cb267215751389597c021bfad13c0bb00c54e19559333764c" +dependencies = [ + "cc", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeeaf1aefae8e0f5141920a7ecbc64a22ab038d4b4ac59f2d19e0effafd5b53" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36ac1f9a72064b1f41fd7b49a4c1b3bf33b9ccb1274874dda6d264f57c55964" +dependencies = [ + "clap", + "codespan-reporting", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170c6ff5d009663866857a91ebee55b98ea4d4b34e7d7aba6dc4a4c95cc7b748" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4984a142211026786011a7e79fa22faa1eca1e9cbf0e60bffecfd57fd3db88f1" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "genmc-sys" +version = "0.11.0" +dependencies = [ + "cmake", + "cxx", + "cxx-build", + "git2", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libgit2-sys" +version = "0.18.2+1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +dependencies = [ + "cc", +] + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "scratch" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml new file mode 100644 index 0000000000..d5085c7eab --- /dev/null +++ b/genmc-sys/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "genmc-sys" +version = "0.11.0" # NOTE: should match the GenMC version +edition = "2024" + +[features] +default = ["vendor_genmc"] +# If vendoring is disabled, a local GenMC repo must be available in the "./genmc" path. +vendor_genmc = ["dep:git2"] + +[dependencies] +cxx = { version = "1.0.160", features = ["c++20"] } + +[build-dependencies] +cmake = "0.1.54" +git2 = { version = "0.20.2", optional = true } +cxx-build = { version = "1.0.160", features = ["parallel"] } diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs new file mode 100644 index 0000000000..1cfbbba682 --- /dev/null +++ b/genmc-sys/build.rs @@ -0,0 +1,184 @@ +use std::path::{Path, PathBuf}; +use std::str::FromStr; + +const GENMC_LOCAL_PATH_STR: &str = "./genmc/"; + +/// Name of the library of the GenMC model checker. +const GENMC_MODEL_CHECKER: &str = "model_checker"; + +const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; + +// FIXME(genmc,cmake): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB) +const ENABLE_GENMC_DEBUG: bool = true; + +#[cfg(feature = "vendor_genmc")] +mod vendoring { + use std::path::PathBuf; + use std::str::FromStr; + + use git2::{Oid, Repository}; + + use super::GENMC_LOCAL_PATH_STR; + + pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; + pub(crate) const GENMC_COMMIT: &str = "338a44e65c8c737fcf4443a1fde241c4afcde278"; + pub(crate) const GENMC_VENDORED_PATH_STR: &str = "./vendored/genmc/"; + + pub(crate) fn vendor_genmc() -> PathBuf { + let Ok(genmc_vendored_path) = PathBuf::from_str(GENMC_VENDORED_PATH_STR); + + let repo = Repository::open(&genmc_vendored_path).unwrap_or_else(|open_err| { + match Repository::clone(GENMC_GITHUB_URL, &genmc_vendored_path) { + Ok(repo) => { + repo + } + Err(clone_err) => { + println!("cargo::error=Cannot open GenMC repo at path '{GENMC_LOCAL_PATH_STR}': {open_err:?}"); + println!("cargo::error=Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {clone_err:?}"); + std::process::exit(1); + } + } + }); + + // Check if there are any updates: + let commit = if let Ok(oid) = Oid::from_str(GENMC_COMMIT) + && let Ok(commit) = repo.find_commit(oid) + { + commit + } else { + match repo.find_remote("origin") { + Ok(mut remote) => + match remote.fetch(&[GENMC_COMMIT], None, None) { + Ok(_) => + println!( + "cargo::warning=Successfully fetched commit '{GENMC_COMMIT:?}'" + ), + Err(e) => panic!("Failed to fetch from remote: {e}"), + }, + Err(e) => println!("cargo::warning=Could not find remote 'origin': {e}"), + } + let oid = Oid::from_str(GENMC_COMMIT).unwrap(); + repo.find_commit(oid).unwrap() + }; + + // Set the repo to the correct branch: + checkout_commit(&repo, GENMC_COMMIT); + + let head_commit = repo.head().unwrap().peel_to_commit().unwrap(); + assert_eq!(head_commit.id(), commit.id()); + println!("cargo::warning=Successfully set checked out commit {head_commit:?}"); + + genmc_vendored_path + } + + fn checkout_commit(repo: &Repository, refname: &str) { + let (object, reference) = repo.revparse_ext(refname).expect("Object not found"); + + repo.checkout_tree(&object, None).expect("Failed to checkout"); + + match reference { + // `gref` is an actual reference like branches or tags. + Some(gref) => repo.set_head(gref.name().unwrap()), + // This is a commit, not a reference. + None => repo.set_head_detached(object.id()), + } + .expect("Failed to set HEAD"); + } +} + +/// Build the Rust-C++ interop library with cxx.rs +fn build_cxx_bridge(genmc_path: &Path) { + // Paths for include directories: + let model_checker_include_path = genmc_path.join(GENMC_MODEL_CHECKER).join("include"); + let genmc_common_include_path = genmc_path.join("common").join("include"); + + let mut bridge = cxx_build::bridge("src/lib.rs"); + + // TODO GENMC: make sure GenMC uses the same compiler / settings as the cxx_bridge + // TODO GENMC: can we use c++23? Does CXX support that? Does rustc CI support that? + bridge + .opt_level(2) + .debug(true) + .warnings(false) // TODO GENMC: try to fix some of those warnings + .std("c++20") + .include(genmc_common_include_path) + .include(model_checker_include_path) + .include("./src_cpp") + .define("PACKAGE_BUGREPORT", "\"FIXME(GenMC) determine what to do with this!!\"") // FIXME(GenMC): HACK to get stuff to compile + .file("./src_cpp/MiriInterface.hpp") + .file("./src_cpp/MiriInterface.cpp"); + + // NOTE: It is very important to ensure that this and similar flags are set/unset both here and + // for the cmake build below, otherwise, certain structs/classes can have different + // sizes and field offsets in the cxx bridge library compared to the model_checker library. + // This will lead to data corruption in these fields, which can be hard to debug (fields change values randomly). + if ENABLE_GENMC_DEBUG { + bridge.define("ENABLE_GENMC_DEBUG", "1"); + } + + bridge.compile("genmc_interop"); + + // Link the Rust-C++ interface library generated by cxx_build: + println!("cargo::rustc-link-lib=static=genmc_interop"); +} + +/// Build the GenMC model checker library. +/// Returns the path +fn build_genmc_model_checker(genmc_path: &Path) { + let cmakelists_path = genmc_path.join("CMakeLists.txt"); + + let mut config = cmake::Config::new(cmakelists_path); + config.profile("RelWithDebInfo"); // FIXME(genmc,cmake): decide on profile to use + if ENABLE_GENMC_DEBUG { + config.define("GENMC_DEBUG", "ON"); + } + + // FIXME(HACK): Required for unknown reasons on older cmake (version 3.22.1, works without this with version 3.31.6) + // Without this, the files are written into the source directory by the cmake configure step, and then + // the build step cannot find these files, because it correctly tries using the `target` directory. + let out_dir = std::env::var("OUT_DIR").unwrap(); + config.configure_arg(format!("-B {out_dir}/build")); + + // Enable only the components of GenMC that we need: + config.define("BUILD_LLI", "OFF"); + config.define("BUILD_INSTRUMENTATION", "OFF"); + config.define("BUILD_MODEL_CHECKER", "ON"); + + config.build_target(GENMC_MODEL_CHECKER); + let dst = config.build(); + + println!("cargo::rustc-link-search=native={}/build/{GENMC_MODEL_CHECKER}", dst.display()); + println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); +} + +fn main() { + // Select between local GenMC repo, or vendoring GenMC from a specific commit. + let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH_STR); + let genmc_path = if genmc_local_path.exists() { + genmc_local_path + } else { + #[cfg(not(feature = "vendor_genmc"))] + panic!( + "GenMC not found in path '{}', and vendoring GenMC is disabled.", + genmc_local_path.to_string_lossy() + ); + + #[cfg(feature = "vendor_genmc")] + vendoring::vendor_genmc() + }; + + // FIXME(genmc, performance): these *should* be able to build in parallel: + // Build all required components: + build_cxx_bridge(&genmc_path); + build_genmc_model_checker(&genmc_path); + + // FIXME(build): Cloning the GenMC repo triggers a rebuild on the next build (since the directory changed during the first build) + + // Only rebuild if anything changes: + println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); + println!("cargo::rerun-if-changed=./src_cpp"); + let genmc_src_paths = [genmc_path.join("model_checker"), genmc_path.join("common")]; + for genmc_src_path in genmc_src_paths { + println!("cargo::rerun-if-changed={}", genmc_src_path.display()); + } +} diff --git a/genmc-sys/src/lib.rs b/genmc-sys/src/lib.rs new file mode 100644 index 0000000000..a4dc5c2aa2 --- /dev/null +++ b/genmc-sys/src/lib.rs @@ -0,0 +1,304 @@ +pub use self::ffi::*; + +/// Defined in "genmc/src/Support/SAddr.hpp" +/// FIXME: currently we use `getGlobalAllocStaticMask()` to ensure the constant is consistent between Miri and GenMC, +/// but if https://github.com/dtolnay/cxx/issues/1051 is fixed we could share the constant directly. +pub const GENMC_GLOBAL_ADDRESSES_MASK: u64 = 1 << 63; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct GenmcThreadId(pub i32); + +pub const GENMC_MAIN_THREAD_ID: GenmcThreadId = GenmcThreadId(0); + +impl GenmcScalar { + pub const UNINIT: Self = Self { value: 0, extra: 0, is_init: false }; + pub const DUMMY: Self = Self::from_u64(0xDEADBEEF); + + pub const MUTEX_LOCKED_STATE: Self = Self::from_u64(1); + pub const MUTEX_UNLOCKED_STATE: Self = Self::from_u64(0); + + pub const fn from_u64(value: u64) -> Self { + Self { value, extra: 0, is_init: true } + } +} + +impl Default for GenmcParams { + fn default() -> Self { + Self { + print_random_schedule_seed: false, + quiet: true, + log_level_trace: false, + do_symmetry_reduction: false, // TODO GENMC (PERFORMANCE): maybe make this default `true` + estimation_max: 1000, + } + } +} + +#[cxx::bridge] +mod ffi { + /// Parameters that will be given to GenMC for setting up the model checker. + /// (The fields of this struct are visible to both Rust and C++) + #[derive(Clone, Debug)] + struct GenmcParams { + // pub genmc_seed: u64; // OR: Option + pub print_random_schedule_seed: bool, + pub quiet: bool, // TODO GENMC: maybe make log-level more fine grained + pub log_level_trace: bool, + pub do_symmetry_reduction: bool, + pub estimation_max: u32, + } + + #[derive(Debug)] + enum ActionKind { + /// Any Mir terminator that's atomic and has load semantics. + Load, + /// Anything that's not a `Load`. + NonLoad, + } + + #[derive(Debug)] + enum MemOrdering { + NotAtomic = 0, + Relaxed = 1, + // In case we support consume + Acquire = 3, + Release = 4, + AcquireRelease = 5, + SequentiallyConsistent = 6, + } + + #[derive(Debug)] + enum RMWBinOp { + Xchg = 0, + Add = 1, + Sub = 2, + And = 3, + Nand = 4, + Or = 5, + Xor = 6, + Max = 7, + Min = 8, + UMax = 9, + UMin = 10, + } + + // TODO GENMC: do these have to be shared with the Rust side? + #[derive(Debug)] + enum StoreEventType { + Normal, + ReadModifyWrite, + CompareExchange, + MutexUnlockWrite, + } + + #[derive(Debug, Clone, Copy)] + struct GenmcScalar { + value: u64, + extra: u64, + is_init: bool, + } + + /**** \/ Result & Error types \/ ****/ + + #[must_use] + #[derive(Debug)] + struct ReadModifyWriteResult { + old_value: GenmcScalar, + new_value: GenmcScalar, + isCoMaxWrite: bool, + error: UniquePtr, // TODO GENMC: pass more error info here + } + + #[must_use] + #[derive(Debug)] + struct MutexLockResult { + is_lock_acquired: bool, + error: UniquePtr, // TODO GENMC: pass more error info here + } + + #[must_use] + #[derive(Debug)] + struct CompareExchangeResult { + old_value: GenmcScalar, // TODO GENMC: handle bigger values + is_success: bool, + isCoMaxWrite: bool, + error: UniquePtr, // TODO GENMC: pass more error info here + } + + #[must_use] + #[derive(Debug)] + struct LoadResult { + is_read_opt: bool, + read_value: GenmcScalar, // TODO GENMC: handle bigger values + error: UniquePtr, // TODO GENMC: pass more error info here + } + + #[must_use] + #[derive(Debug)] + struct StoreResult { + error: UniquePtr, // TODO GENMC: pass more error info here + isCoMaxWrite: bool, + } + + #[must_use] + #[derive(Debug)] + enum VerificationError { + VE_NonErrorBegin, + VE_OK, + VE_WWRace, + VE_UnfreedMemory, + VE_NonErrorLast, + VE_Safety, + VE_Recovery, + VE_Liveness, + VE_RaceNotAtomic, + VE_RaceFreeMalloc, + VE_FreeNonMalloc, + VE_DoubleFree, + VE_Allocation, + + VE_InvalidAccessBegin, + VE_UninitializedMem, + VE_AccessNonMalloc, + VE_AccessFreed, + VE_InvalidAccessEnd, + + VE_InvalidCreate, + VE_InvalidJoin, + VE_InvalidUnlock, + VE_InvalidBInit, + VE_InvalidRecoveryCall, + VE_InvalidTruncate, + VE_Annotation, + VE_MixedSize, + VE_LinearizabilityError, + VE_SystemError, + } + + /**** /\ Result & Error types /\ ****/ + + unsafe extern "C++" { + include!("MiriInterface.hpp"); + + type MemOrdering; + type RMWBinOp; + type StoreEventType; + + // Types for Scheduling queries: + type ActionKind; + + // Result / Error types: + type LoadResult; + type StoreResult; + type ReadModifyWriteResult; + type CompareExchangeResult; + type MutexLockResult; + type VerificationError; + + type GenmcScalar; + + // type OperatingMode; // Estimation(budget) or Verification + + type MiriGenMCShim; + + fn createGenmcHandle(config: &GenmcParams, do_estimation: bool) + -> UniquePtr; + fn getGlobalAllocStaticMask() -> u64; + + fn handleExecutionStart(self: Pin<&mut MiriGenMCShim>); + fn handleExecutionEnd(self: Pin<&mut MiriGenMCShim>) -> UniquePtr; + + fn handleLoad( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + memory_ordering: MemOrdering, + old_value: GenmcScalar, + ) -> LoadResult; + fn handleReadModifyWrite( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + load_ordering: MemOrdering, + store_ordering: MemOrdering, + rmw_op: RMWBinOp, + rhs_value: GenmcScalar, + old_value: GenmcScalar, + ) -> ReadModifyWriteResult; + fn handleCompareExchange( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + expected_value: GenmcScalar, + new_value: GenmcScalar, + old_value: GenmcScalar, + success_load_ordering: MemOrdering, + success_store_ordering: MemOrdering, + fail_load_ordering: MemOrdering, + can_fail_spuriously: bool, + ) -> CompareExchangeResult; + fn handleStore( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + value: GenmcScalar, + old_value: GenmcScalar, + memory_ordering: MemOrdering, + store_event_type: StoreEventType, + ) -> StoreResult; + fn handleFence(self: Pin<&mut MiriGenMCShim>, thread_id: i32, memory_ordering: MemOrdering); + + fn handleMalloc( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + size: u64, + alignment: u64, + ) -> u64; + fn handleFree(self: Pin<&mut MiriGenMCShim>, thread_id: i32, address: u64, size: u64); + + fn handleThreadCreate(self: Pin<&mut MiriGenMCShim>, thread_id: i32, parent_id: i32); + fn handleThreadJoin(self: Pin<&mut MiriGenMCShim>, thread_id: i32, child_id: i32); + fn handleThreadFinish(self: Pin<&mut MiriGenMCShim>, thread_id: i32, ret_val: u64); + + /**** Blocking instructions ****/ + fn handleUserBlock(self: Pin<&mut MiriGenMCShim>, thread_id: i32); + + /**** Mutex handling ****/ + fn handleMutexLock( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + ) -> MutexLockResult; + fn handleMutexTryLock( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + ) -> MutexLockResult; + fn handleMutexUnlock( + self: Pin<&mut MiriGenMCShim>, + thread_id: i32, + address: u64, + size: u64, + ) -> StoreResult; + + /**** Scheduling ****/ + fn scheduleNext( + self: Pin<&mut MiriGenMCShim>, + curr_thread_id: i32, + curr_thread_next_instr_kind: ActionKind, + ) -> i64; + + // TODO GENMC: Replace once VerificationResult is accessible (or at least rename the function). + fn getStuckExecutionCount(self: &MiriGenMCShim) -> u64; + fn isExplorationDone(self: Pin<&mut MiriGenMCShim>) -> bool; + + fn printGraph(self: Pin<&mut MiriGenMCShim>); + fn printEstimationResults(self: &MiriGenMCShim, elapsed_time_sec: f64); + } +} diff --git a/genmc-sys/src_cpp/MiriInterface.cpp b/genmc-sys/src_cpp/MiriInterface.cpp new file mode 100644 index 0000000000..c014def853 --- /dev/null +++ b/genmc-sys/src_cpp/MiriInterface.cpp @@ -0,0 +1,524 @@ +#include "MiriInterface.hpp" + +#include "genmc-sys/src/lib.rs.h" + +#include "ExecutionGraph/EventLabel.hpp" +#include "Support/ASize.hpp" +#include "Support/Error.hpp" +#include "Support/Logger.hpp" +#include "Support/MemAccess.hpp" +#include "Support/MemOrdering.hpp" +#include "Support/MemoryModel.hpp" +#include "Support/RMWOps.hpp" +#include "Support/SAddr.hpp" +#include "Support/SVal.hpp" +#include "Support/ThreadInfo.hpp" +#include "Support/Verbosity.hpp" +#include "Verification/DriverEnumAPI.hpp" +#include "Verification/GenMCDriver.hpp" + +#include +#include +#include +#include + +using AnnotID = ModuleID_ID; +using AnnotT = SExpr; + +// Return -1 when no thread can/should be scheduled, or the thread id of the next thread +// NOTE: this is safe because ThreadId is 32 bit, and we return a 64 bit integer +// TODO GENMC: could directly return std::optional if CXX ever supports this +auto MiriGenMCShim::scheduleNext(const int curr_thread_id, + const ActionKind curr_thread_next_instr_kind) -> int64_t +{ + // The current thread is the only one where the `kind` could have changed since we last made + // a scheduling decision. + globalInstructions[curr_thread_id].kind = curr_thread_next_instr_kind; + + auto result = GenMCDriver::scheduleNext(globalInstructions); + if (result.has_value()) { + return static_cast(result.value()); + } + return -1; +} + +/**** Functions available to Miri ****/ + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +auto MiriGenMCShim::createHandle(const GenmcParams &config, bool estimation_mode) + -> std::unique_ptr +{ + auto vConf = std::make_shared(); + // TODO GENMC: Can we get some default values somehow? + // Config::saveConfigOptions(*vConf); + + // NOTE: Miri already initialization checks, so we can disable them in GenMC + vConf->skipNonAtomicInitializedCheck = true; + + // Miri needs all threads to be replayed, even fully completed ones. + vConf->replayCompletedThreads = true; + + // TODO GENMC: make sure this doesn't affect any tests, and maybe make it changeable from + // Miri: + constexpr unsigned int DEFAULT_WARN_ON_GRAPH_SIZE = 16 * 1024; + vConf->warnOnGraphSize = DEFAULT_WARN_ON_GRAPH_SIZE; + vConf->model = ModelType::RC11; + vConf->randomScheduleSeed = + "42"; // TODO GENMC: only for random exploration/scheduling mode in GenMC + vConf->printRandomScheduleSeed = config.print_random_schedule_seed; + if (config.quiet) { + // logLevel = VerbosityLevel::Quiet; + // TODO GENMC: error might be better (or new level for `BUG`) + // logLevel = VerbosityLevel::Quiet; + logLevel = VerbosityLevel::Error; + } else if (config.log_level_trace) { + logLevel = VerbosityLevel::Trace; + } else { + logLevel = VerbosityLevel::Tip; + } + + // TODO GENMC (EXTRA): check if we can enable IPR: + vConf->ipr = false; + // TODO GENMC (EXTRA): check if we can enable BAM: + vConf->disableBAM = true; + // TODO GENMC (EXTRA): check if we can enable Symmetry Reduction: + vConf->symmetryReduction = config.do_symmetry_reduction; + + // TODO GENMC (EXTRA): check if we can do instruction caching (probably not) + vConf->instructionCaching = false; + + // TODO GENMC: Should there be a way to change this option from Miri? + vConf->schedulePolicy = SchedulePolicy::WF; + + vConf->estimate = estimation_mode; + vConf->estimationMax = config.estimation_max; + const auto mode = vConf->estimate ? GenMCDriver::Mode(GenMCDriver::EstimationMode{}) + : GenMCDriver::Mode(GenMCDriver::VerificationMode{}); + + // With `disableRaceDetection = true`, the scheduler would be incorrectly replaying + // executions with Miri, since we can only schedule at Mir terminators, and each Mir + // terminator can generate multiple events in the ExecutionGraph. + // Users running Miri-GenMC most likely want to always have race detection enabled anyway. + vConf->disableRaceDetection = false; + + // Miri can already check for unfreed memory. Also, GenMC cannot distinguish between memory + // that is allowed to leak and memory that is not. + vConf->warnUnfreedMemory = false; + + checkVerificationConfigOptions(*vConf); + + auto driver = std::make_unique(std::move(vConf), mode); + + auto *driverPtr = driver.get(); + auto initValGetter = [driverPtr](const AAccess &access) { + const auto addr = access.getAddr(); + if (!driverPtr->initVals_.contains(addr)) { + MIRI_LOG() << "WARNING: TODO GENMC: requested initial value for address " + << addr << ", but there is none.\n"; + return SVal(0xCC00CC00); + // BUG_ON(!driverPtr->initVals_.contains(addr)); + } + auto result = driverPtr->initVals_[addr]; + if (!result.is_init) { + MIRI_LOG() << "WARNING: TODO GENMC: requested initial value for address " + << addr << ", but the memory is uninitialized.\n"; + return SVal(0xFF00FF00); + } + MIRI_LOG() << "MiriGenMCShim: requested initial value for address " << addr + << " == " << addr.get() << ", returning: " << result << "\n"; + return result.toSVal(); + }; + driver->getExec().getGraph().setInitValGetter(initValGetter); + + return driver; +} + +// This needs to be available to Miri, but clang-tidy wants it static +// NOLINTNEXTLINE(misc-use-internal-linkage) +auto createGenmcHandle(const GenmcParams &config, bool estimation_mode) + -> std::unique_ptr +{ + return MiriGenMCShim::createHandle(config, estimation_mode); +} + +/**** Execution start/end handling ****/ + +void MiriGenMCShim::handleExecutionStart() +{ + // TODO GENMC: reset completely or just set to init event for each thread? + globalInstructions.clear(); + globalInstructions.push_back(Action(ActionKind::Load, Event::getInit())); + // for (auto &action : globalInstructions) { + // action.event.index = 0; + // action.kind = ActionKind::Load; + // } + GenMCDriver::handleExecutionStart(); +} + +auto MiriGenMCShim::handleExecutionEnd() -> std::unique_ptr +{ + return GenMCDriver::handleExecutionEnd(globalInstructions); +} + +/**** Thread management ****/ + +void MiriGenMCShim::handleThreadCreate(ThreadId thread_id, ThreadId parent_id) +{ + // NOTE: The threadCreate event happens in the parent: + auto pos = incPos(parent_id); + + const unsigned funId = 0; // TODO GENMC + const SVal arg = SVal(0); // TODO GENMC + const ThreadInfo childInfo = ThreadInfo{thread_id, parent_id, funId, arg}; + + // NOTE: Default GenMC ordering used here + auto tcLab = std::make_unique(pos, childInfo); + auto createLab = GenMCDriver::handleThreadCreate(std::move(tcLab)); + auto genmcTid = createLab->getChildId(); + + BUG_ON(genmcTid != thread_id); + BUG_ON(genmcTid == -1); // TODO GENMC (ERROR HANDLING): proper error handling + BUG_ON(genmcTid > globalInstructions.size()); + + // TODO GENMC: should both these be possible? + if (genmcTid >= globalInstructions.size()) + globalInstructions.push_back(Action(ActionKind::Load, Event(genmcTid, 0))); + else + globalInstructions[genmcTid] = Action(ActionKind::Load, Event(genmcTid, 0)); +} + +void MiriGenMCShim::handleThreadJoin(ThreadId thread_id, ThreadId child_id) +{ + auto parentTid = thread_id; + auto childTid = child_id; + + // NOTE: The thread join event happens in the parent: + auto pos = incPos(parentTid); + + // NOTE: Default GenMC ordering used here + auto lab = std::make_unique(pos, childTid); + auto res = GenMCDriver::handleThreadJoin(std::move(lab)); + // TODO GENMC: use return value if needed + if (res.has_value()) { + MIRI_LOG() << "TODO GENMC: GenMC::handleThreadJoin: returned value: " + << res.getValue() << "\n"; + } else { + MIRI_LOG() << "MiriGenMCShim::handleThreadJoin got no value."; + decPos(parentTid); + } +} + +void MiriGenMCShim::handleThreadFinish(ThreadId thread_id, uint64_t ret_val) +{ + MIRI_LOG() << "GenMC: handleThreadFinish: thread id: " << thread_id << "\n"; + + auto pos = incPos(thread_id); + auto retVal = SVal(ret_val); + + // NOTE: Default GenMC ordering used here + auto eLab = std::make_unique(pos, retVal); + + GenMCDriver::handleThreadFinish(std::move(eLab)); +} + +/**** Blocking instructions ****/ + +void MiriGenMCShim::handleUserBlock(ThreadId thread_id) +{ + + auto pos = incPos(thread_id); + auto bLab = UserBlockLabel::create(/* EventLabelKind::UserBlock, */ pos); + GenMCDriver::handleBlock(std::move(bLab)); + // TODO GENMC: could this ever fail? +} + +/**** Memory access handling ****/ + +[[nodiscard]] auto MiriGenMCShim::handleLoad(ThreadId thread_id, uint64_t address, uint64_t size, + MemOrdering ord, GenmcScalar old_val) -> LoadResult +{ + MIRI_LOG() << "Received Load from Miri at address: " << address << ", size " << size + << " with ordering " << ord << "\n"; + + auto pos = incPos(thread_id); + + auto loc = SAddr(address); + auto aSize = ASize(size); + auto type = AType::Unsigned; // TODO GENMC: get correct type from Miri + + auto newLab = std::make_unique(pos, ord, loc, aSize, type); + + auto oldValSetter = [this, old_val](SAddr loc) { this->handleOldVal(loc, old_val); }; + auto result = GenMCDriver::handleLoad(std::move(newLab), oldValSetter); + return result; +} + +[[nodiscard]] auto MiriGenMCShim::handleReadModifyWrite(ThreadId thread_id, uint64_t address, + uint64_t size, MemOrdering loadOrd, + MemOrdering store_ordering, RMWBinOp rmw_op, + GenmcScalar rhs_value, GenmcScalar old_val) + -> ReadModifyWriteResult +{ + MIRI_LOG() << "Received Read-Modify-Write from Miri at address: " << address << ", size " + << size << " with orderings (" << loadOrd << ", " << store_ordering + << "), rmw op: " << static_cast(rmw_op) << "\n"; + + auto pos = incPos(thread_id); + + auto loc = SAddr(address); + auto aSize = ASize(size); + auto type = AType::Unsigned; + + auto rhsVal = rhs_value.toSVal(); + auto newLab = + std::make_unique(pos, loadOrd, loc, aSize, type, rmw_op, rhsVal); + + auto oldValSetter = [this, old_val](SAddr loc) { this->handleOldVal(loc, old_val); }; + auto result = GenMCDriver::handleLoad(std::move(newLab), oldValSetter); + if (const auto *error = result.error.get()) { + return ReadModifyWriteResult::fromError(*error); + } + + auto oldVal = result.scalar.toSVal(); // TODO GENMC: u128 handling + auto newVal = executeRMWBinOp(oldVal, rhsVal, size, rmw_op); + + auto store_result = handleStore(thread_id, address, size, GenmcScalar(newVal), old_val, + store_ordering, StoreEventType::ReadModifyWrite); + + if (store_result.is_error()) + return ReadModifyWriteResult::fromError(*store_result.error.get()); + return ReadModifyWriteResult(oldVal, newVal, store_result.isCoMaxWrite); +} + +[[nodiscard]] auto MiriGenMCShim::handleCompareExchange( + ThreadId thread_id, uint64_t address, uint64_t size, GenmcScalar expected_value, + GenmcScalar new_value, GenmcScalar old_val, MemOrdering success_load_ordering, + MemOrdering success_store_ordering, MemOrdering fail_load_ordering, + bool can_fail_spuriously) -> CompareExchangeResult +{ + + MIRI_LOG() << "Received Compare-Exchange from Miri (value: " << expected_value << " --> " + << new_value << ", old value: " << old_val << ") at address: " << address + << ", size " << size << " with success orderings (" << success_load_ordering + << ", " << success_store_ordering + << "), fail load ordering: " << fail_load_ordering + << ", is weak (can fail spuriously): " << can_fail_spuriously << "\n"; + + auto pos = incPos(thread_id); + + auto loc = SAddr(address); + auto aSize = ASize(size); + auto type = AType::Unsigned; + + auto expectedVal = expected_value.toSVal(); + auto newVal = new_value.toSVal(); + + // FIXME(GenMC): properly handle failure memory ordering. + + auto newLab = std::make_unique(pos, success_load_ordering, loc, aSize, type, + expectedVal, newVal); + + auto oldValSetter = [this, old_val](SAddr loc) { this->handleOldVal(loc, old_val); }; + auto result = GenMCDriver::handleLoad(std::move(newLab), oldValSetter); + if (const auto *error = result.error.get()) { + return CompareExchangeResult::fromError(*error); + } + + auto oldVal = result.scalar.toSVal(); + if (oldVal != expectedVal) + return CompareExchangeResult::failure(oldVal); + + auto store_result = handleStore(thread_id, address, size, GenmcScalar(newVal), old_val, + success_store_ordering, StoreEventType::CompareExchange); + + if (store_result.is_error()) + return CompareExchangeResult::fromError(*store_result.error); + return CompareExchangeResult::success(oldVal, store_result.isCoMaxWrite); +} + +[[nodiscard]] auto MiriGenMCShim::handleStore(ThreadId thread_id, uint64_t address, uint64_t size, + GenmcScalar value, GenmcScalar old_val, + MemOrdering ord, StoreEventType store_event_type) + -> StoreResult +{ + MIRI_LOG() << "Received Store from Miri at address " << address << ", size " << size + << " with ordering " << ord << ", is part of rmw: (" + << static_cast(store_event_type) << ")\n"; + + auto pos = incPos(thread_id); + + auto loc = SAddr(address); // TODO GENMC: called addr for write, loc for read? + auto aSize = ASize(size); + auto type = AType::Unsigned; // TODO GENMC: get from Miri + + // TODO GENMC: u128 support + auto val = value.toSVal(); + + std::unique_ptr wLab; + switch (store_event_type) { + case StoreEventType::Normal: + wLab = std::make_unique(pos, ord, loc, aSize, type, val); + break; + case StoreEventType::ReadModifyWrite: + wLab = std::make_unique(pos, ord, loc, aSize, type, val); + break; + case StoreEventType::CompareExchange: + wLab = std::make_unique(pos, ord, loc, aSize, type, val); + break; + case StoreEventType::MutexUnlockWrite: + wLab = UnlockWriteLabel::create(pos, ord, loc, aSize, AType::Signed, val); + break; + default: + ERROR("Unsupported Store Event Type"); + } + + auto oldValSetter = [this, old_val](SAddr loc) { + this->handleOldVal(loc, + old_val); // TODO GENMC(HACK): is this the correct way to do it? + }; + + return GenMCDriver::handleStore(std::move(wLab), oldValSetter); +} + +void MiriGenMCShim::handleFence(ThreadId thread_id, MemOrdering ord) +{ + MIRI_LOG() << "Received fence operation from Miri with ordering " << ord << "\n"; + + auto pos = incPos(thread_id); + + auto fLab = std::make_unique(pos, ord); + GenMCDriver::handleFence(std::move(fLab)); +} + +/**** Memory (de)allocation ****/ + +auto MiriGenMCShim::handleMalloc(ThreadId thread_id, uint64_t size, uint64_t alignment) -> uintptr_t +{ + BUG_ON(size == 0); + auto pos = incPos(thread_id); + + MIRI_LOG() << "handleMalloc: thread " << thread_id << ", new MallocLabel at position {" + << pos.thread << ", " << pos.index << "}\n"; + + auto sd = StorageDuration::SD_Heap; // TODO GENMC: get from Miri + auto stype = StorageType::ST_Durable; // TODO GENMC + auto spc = AddressSpace::AS_User; // TODO GENMC + + auto deps = EventDeps(); // TODO GENMC: without this, constructor is ambiguous + + // TODO GENMC (types): size_t vs unsigned int + auto aLab = std::make_unique(pos, size, alignment, sd, stype, spc, deps); + + SAddr retVal = GenMCDriver::handleMalloc(std::move(aLab)); + + BUG_ON(retVal.get() == 0); + + auto address = retVal.get(); + return address; +} + +void MiriGenMCShim::handleFree(ThreadId thread_id, uint64_t address, uint64_t size) +{ + MIRI_LOG() << "GENMC: handleFree called (address: " << address << ", size: " << size + << ")\n"; + BUG_ON(size == 0); + + auto addr = SAddr(address); + auto alloc_size = SAddr(size); + BUG_ON(addr.get() == 0); + + auto pos = incPos(thread_id); + + auto dLab = std::make_unique(pos, addr, size); + GenMCDriver::handleFree(std::move(dLab)); +} + +/**** Mutex handling ****/ + +auto MiriGenMCShim::handleMutexLock(ThreadId thread_id, uint64_t address, uint64_t size) + -> MutexLockResult +{ + // TODO GENMC: this needs to be identical even in multithreading + unsigned int annot_id; + if (annotation_id.contains(address)) { + annot_id = annotation_id.at(address); + } else { + annot_id = annotation_id_counter++; + annotation_id.insert(std::make_pair(address, annot_id)); + } + auto annot = std::move(Annotation( + AssumeType::Spinloop, + Annotation::ExprVP(NeExpr::create( + RegisterExpr::create(size * CHAR_BIT, annot_id), + ConcreteExpr::create(size * CHAR_BIT, SVal(1))) + .release()))); + + auto &currPos = globalInstructions[thread_id].event; + // auto rLab = LockCasReadLabel::create(++currPos, address, size); + auto rLab = LockCasReadLabel::create(++currPos, address, size, annot); + + // Mutex starts out unlocked, so we always say the previous value is "unlocked". + auto oldValSetter = [this](SAddr loc) { this->handleOldVal(loc, SVal(0)); }; + LoadResult loadResult = GenMCDriver::handleLoad(std::move(rLab), oldValSetter); + if (loadResult.is_error()) { + --currPos; + return MutexLockResult::fromError(*loadResult.error); + } else if (loadResult.is_read_opt) { + --currPos; + // TODO GENMC: is_read_opt == Mutex is acquired + // None --> Someone else has lock, this thread will be rescheduled later (currently + // block) 0 --> Got the lock 1 --> Someone else has lock, this thread will + // not be rescheduled later (block on Miri side) + return MutexLockResult(false); + } + // TODO GENMC(QUESTION): is the `isBlocked` even needed? + // if (!loadResult.has_value() || getCurThr().isBlocked()) + // return; + + const bool is_lock_acquired = loadResult.getValue() == SVal(0); + if (is_lock_acquired) { + auto wLab = LockCasWriteLabel::create(++currPos, address, size); + StoreResult storeResult = GenMCDriver::handleStore(std::move(wLab), oldValSetter); + if (storeResult.is_error()) + return MutexLockResult::fromError(*storeResult.error); + + } else { + auto bLab = LockNotAcqBlockLabel::create(++currPos); + GenMCDriver::handleBlock(std::move(bLab)); + } + + return MutexLockResult(is_lock_acquired); +} + +auto MiriGenMCShim::handleMutexTryLock(ThreadId thread_id, uint64_t address, uint64_t size) + -> MutexLockResult +{ + auto &currPos = globalInstructions[thread_id].event; + auto rLab = TrylockCasReadLabel::create(++currPos, address, size); + // Mutex starts out unlocked, so we always say the previous value is "unlocked". + auto oldValSetter = [this](SAddr loc) { this->handleOldVal(loc, SVal(0)); }; + LoadResult loadResult = GenMCDriver::handleLoad(std::move(rLab), oldValSetter); + if (!loadResult.has_value()) { + --currPos; + // TODO GENMC: maybe use std move and make it take a unique_ptr ? + return MutexLockResult::fromError(*loadResult.error); + } + + const bool is_lock_acquired = loadResult.getValue() == SVal(0); + if (!is_lock_acquired) + return MutexLockResult(false); /* Lock already held. */ + + auto wLab = TrylockCasWriteLabel::create(++currPos, address, size); + StoreResult storeResult = GenMCDriver::handleStore(std::move(wLab), oldValSetter); + if (storeResult.is_error()) + return MutexLockResult::fromError(*storeResult.error); + + return MutexLockResult(true); +} + +auto MiriGenMCShim::handleMutexUnlock(ThreadId thread_id, uint64_t address, uint64_t size) + -> StoreResult +{ + return handleStore(thread_id, address, size, SVal(0), SVal(0xDEADBEEF), + MemOrdering::Release, StoreEventType::MutexUnlockWrite); +} diff --git a/genmc-sys/src_cpp/MiriInterface.hpp b/genmc-sys/src_cpp/MiriInterface.hpp new file mode 100644 index 0000000000..8c29fc1477 --- /dev/null +++ b/genmc-sys/src_cpp/MiriInterface.hpp @@ -0,0 +1,232 @@ +#ifndef GENMC_GENMC_MIRI_INTERFACE_HPP +#define GENMC_GENMC_MIRI_INTERFACE_HPP + +#include "rust/cxx.h" + +#include "ExecutionGraph/EventLabel.hpp" +#include "Support/MemOrdering.hpp" +#include "Support/RMWOps.hpp" +#include "Verification/GenMCDriver.hpp" +#include "Verification/VerificationConfig.hpp" + +#include +#include +#include + +/**** Types available to Miri ****/ + +struct GenmcParams; + +using ThreadId = int; + +enum class StoreEventType : uint8_t { + Normal, + ReadModifyWrite, + CompareExchange, + MutexUnlockWrite, +}; + +struct MutexLockResult { + bool is_lock_acquired; + std::unique_ptr error; // TODO GENMC: pass more error info here + + MutexLockResult(bool is_lock_acquired) : is_lock_acquired(is_lock_acquired), error(nullptr) + {} + + static auto fromError(std::string msg) -> MutexLockResult + { + auto res = MutexLockResult(false); + res.error = std::make_unique(msg); + return res; + } +}; + +// TODO GENMC: fix naming conventions + +struct MiriGenMCShim : private GenMCDriver { + +public: + MiriGenMCShim(std::shared_ptr vConf, Mode mode /* = VerificationMode{} */) + : GenMCDriver(std::move(vConf), nullptr, mode) + { + globalInstructions.reserve(8); + globalInstructions.push_back(Action(ActionKind::Load, Event::getInit())); + } + + virtual ~MiriGenMCShim() {} + + /**** Execution start/end handling ****/ + + void handleExecutionStart(); + std::unique_ptr handleExecutionEnd(); + + /**** Memory access handling ****/ + + /////////////////// + [[nodiscard]] LoadResult handleLoad(ThreadId thread_id, uint64_t address, uint64_t size, + MemOrdering ord, GenmcScalar old_val); + [[nodiscard]] ReadModifyWriteResult + handleReadModifyWrite(ThreadId thread_id, uint64_t address, uint64_t size, + MemOrdering loadOrd, MemOrdering store_ordering, RMWBinOp rmw_op, + GenmcScalar rhs_value, GenmcScalar old_val); + [[nodiscard]] CompareExchangeResult + handleCompareExchange(ThreadId thread_id, uint64_t address, uint64_t size, + GenmcScalar expected_value, GenmcScalar new_value, + GenmcScalar old_val, MemOrdering success_load_ordering, + MemOrdering success_store_ordering, MemOrdering fail_load_ordering, + bool can_fail_spuriously); + [[nodiscard]] StoreResult handleStore(ThreadId thread_id, uint64_t address, uint64_t size, + GenmcScalar value, GenmcScalar old_val, + MemOrdering ord, StoreEventType store_event_type); + + void handleFence(ThreadId thread_id, MemOrdering ord); + + /**** Memory (de)allocation ****/ + + uintptr_t handleMalloc(ThreadId thread_id, uint64_t size, uint64_t alignment); + void handleFree(ThreadId thread_id, uint64_t address, uint64_t size); + + /**** Thread management ****/ + + void handleThreadCreate(ThreadId thread_id, ThreadId parent_id); + void handleThreadJoin(ThreadId thread_id, ThreadId child_id); + void handleThreadFinish(ThreadId thread_id, uint64_t ret_val); + + /**** Blocking instructions ****/ + + void handleUserBlock(ThreadId thread_id); + + /**** Mutex handling ****/ + auto handleMutexLock(ThreadId thread_id, uint64_t address, uint64_t size) + -> MutexLockResult; + auto handleMutexTryLock(ThreadId thread_id, uint64_t address, uint64_t size) + -> MutexLockResult; + auto handleMutexUnlock(ThreadId thread_id, uint64_t address, uint64_t size) -> StoreResult; + + /**** Scheduling queries ****/ + + // TODO GENMC: implement + + auto scheduleNext(const int curr_thread_id, const ActionKind curr_thread_next_instr_kind) + -> int64_t; + + /**** TODO GENMC: Other stuff: ****/ + + auto getStuckExecutionCount() const -> uint64_t + { + return static_cast(getResult().exploredBlocked); + } + + bool isExplorationDone() { return GenMCDriver::done(); } + + /**** OTHER ****/ + + auto incPos(ThreadId tid) -> Event + { + ERROR_ON(tid >= globalInstructions.size(), "ThreadId out of bounds"); + return ++globalInstructions[tid].event; + } + auto decPos(ThreadId tid) -> Event + { + ERROR_ON(tid >= globalInstructions.size(), "ThreadId out of bounds"); + return --globalInstructions[tid].event; + } + + void printGraph() { GenMCDriver::debugPrintGraph(); } + + void printEstimationResults(const double elapsed_time_sec) const + { + // TODO GENMC(CLEANUP): should this happen on the Rust side? + const auto &res = getResult(); + const auto *vConf = getConf(); + + auto mean = std::llround(res.estimationMean); + auto sd = std::llround(std::sqrt(res.estimationVariance)); + auto meanTimeSecs = (long double)elapsed_time_sec / (res.explored + res.exploredBlocked); + // FIXME(io): restore the old precision after the print? + PRINT(VerbosityLevel::Error) + << "Finished estimation in " << std::setprecision(2) << elapsed_time_sec << " seconds.\n\n" + << "Total executions estimate: " << mean << " (+- " << sd << ")\n" + << "Time to completion estimate: " + << std::setprecision(2) << (meanTimeSecs * mean) << "s\n"; + GENMC_DEBUG(if (vConf->printEstimationStats) PRINT(VerbosityLevel::Error) + << "Estimation moot: " << res.exploredMoot << "\n" + << "Estimation blocked: " << res.exploredBlocked << "\n" + << "Estimation complete: " << res.explored << "\n";); + } + + static std::unique_ptr createHandle(const GenmcParams &config, + bool estimation_mode); + +private: + /** + * @brief Try to insert the initial value of a memory location. + * @param addr + * @param value + * */ + void handleOldVal(const SAddr addr, GenmcScalar value) + { + MIRI_LOG() << "handleOldVal: " << addr << ", " << value.value << ", " << value.extra + << ", " << value.is_init << "\n"; + // if (!value.is_init) { + // // // TODO GENMC(uninit value handling) + // // MIRI_LOG() << "WARNING: got uninitialized old value, ignoring ...\n"; + // // return; + // MIRI_LOG() << "WARNING: got uninitialized old value, converting to dummy " + // "value ...\n"; + // value.is_init = true; + // value.value = 0xAAFFAAFF; + // } + + // TODO GENMC(CLEANUP): Pass this as a parameter: + auto &g = getExec().getGraph(); + auto *coLab = g.co_max(addr); + MIRI_LOG() << "handleOldVal: coLab: " << *coLab << "\n"; + if (auto *wLab = llvm::dyn_cast(coLab)) { + MIRI_LOG() << "handleOldVal: got WriteLabel, atomic: " << wLab->isAtomic() + << "\n"; + if (!value.is_init) + MIRI_LOG() << "WARNING: TODO GENMC: handleOldVal tried to " + "overwrite value of NA " + "reads-from label, but old value is `uninit`\n"; + else if (wLab->isNotAtomic()) + wLab->setVal(value.toSVal()); + } else if (const auto *wLab = llvm::dyn_cast(coLab)) { + if (value.is_init) { + auto result = initVals_.insert(std::make_pair(addr, value)); + MIRI_LOG() << "handleOldVal: got InitLabel, insertion result: " + << result.first->second << ", " << result.second << "\n"; + BUG_ON(result.second && + (*result.first).second != + value); /* Attempt to replace initial value */ + } else { + // LOG(VerbosityLevel::Error) << + MIRI_LOG() << "WARNING: TODO GENMC: handleOldVal tried set initial " + "value, but old " + "value is `uninit`\n"; + } + } else { + BUG(); /* Invalid label */ + } + // either initLabel ==> update initValGetter + // or WriteLabel ==> Update its value in place (only if non-atomic) + } + + // TODO GENMC(mixed-size accesses): + std::unordered_map initVals_{}; + + std::vector globalInstructions; + + std::unordered_map annotation_id{}; + unsigned int annotation_id_counter = 0; +}; + +/**** Functions available to Miri ****/ + +// NOTE: CXX doesn't seem to support exposing static methods to Rust, so we expose this +// function instead +std::unique_ptr createGenmcHandle(const GenmcParams &config, bool estimation_mode); + +constexpr auto getGlobalAllocStaticMask() -> uint64_t { return SAddr::staticMask; } + +#endif /* GENMC_GENMC_MIRI_INTERFACE_HPP */ diff --git a/src/alloc_addresses/mod.rs b/src/alloc_addresses/mod.rs index 3cc38fa087..2beb309078 100644 --- a/src/alloc_addresses/mod.rs +++ b/src/alloc_addresses/mod.rs @@ -33,6 +33,7 @@ pub struct GlobalStateInner { /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset /// from the base address, and we need to find the `AllocId` it belongs to. This is not the /// *full* inverse of `base_addr`; dead allocations have been removed. + /// TODO GENMC: keep dead allocations in GenMC mode? int_to_ptr_map: Vec<(u64, AllocId)>, /// The base address for each allocation. We cannot put that into /// `AllocExtra` because function pointers also have a base address, and @@ -98,7 +99,8 @@ impl GlobalStateInner { /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple /// of `align` that is larger or equal to `addr` -fn align_addr(addr: u64, align: u64) -> u64 { +/// FIXME(GenMC): is it ok to make this public? +pub(crate) fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, rem => addr.strict_add(align) - rem, @@ -119,8 +121,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miri's address assignment leaks state across thread boundaries, which is incompatible // with GenMC execution. So we instead let GenMC assign addresses to allocations. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?; - return interp_ok(addr); + return genmc_ctx.handle_alloc(this, alloc_id, info.size, info.align, memory_kind); } let mut rng = this.machine.rng.borrow_mut(); @@ -262,7 +263,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only use this provenance if it has been exposed, or if the caller requested also non-exposed allocations if !only_exposed_allocations || global_state.exposed.contains(&alloc_id) { // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - debug_assert!(this.is_alloc_live(alloc_id)); + // In GenMC mode, we keep all allocations, so this check doesn't apply there. + debug_assert!( + this.machine.data_race.as_genmc_ref().is_some() || this.is_alloc_live(alloc_id) + ); Some(alloc_id) } else { None @@ -493,11 +497,15 @@ impl<'tcx> MiriMachine<'tcx> { let addr = *global_state.base_addr.get(&dead_id).unwrap(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr).unwrap(); - let removed = global_state.int_to_ptr_map.remove(pos); - assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing - // We can also remove it from `exposed`, since this allocation can anyway not be returned by - // `alloc_id_from_addr` any more. - global_state.exposed.remove(&dead_id); + + // TODO GENMC(DOCUMENTATION): + if self.data_race.as_genmc_ref().is_none() { + let removed = global_state.int_to_ptr_map.remove(pos); + assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing + // We can also remove it from `exposed`, since this allocation can anyway not be returned by + // `alloc_id_from_addr` any more. + global_state.exposed.remove(&dead_id); + } // Also remember this address for future reuse. let thread = self.threads.active_thread(); global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 89fa980ff6..ccdd4eb2ab 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -39,7 +39,7 @@ use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use miri::{ BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType, - ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, + ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, miri_genmc, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -193,9 +193,34 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } if let Some(genmc_config) = &self.genmc_config { - let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config)); + let eval_entry_once = |genmc_ctx: Rc| { + miri::eval_entry(tcx, entry_def_id, entry_type, &config, Some(genmc_ctx)) + }; + + if genmc_config.do_estimation() + && miri_genmc::run_genmc_mode( + &config, + genmc_config, + eval_entry_once, + miri_genmc::Mode::Estimation, + ) + .is_some() + { + tcx.dcx().abort_if_errors(); + } - todo!("GenMC mode not yet implemented"); + let return_code = miri_genmc::run_genmc_mode( + &config, + genmc_config, + eval_entry_once, + miri_genmc::Mode::Verification, + ) + .unwrap_or_else(|| { + tcx.dcx().abort_if_errors(); + rustc_driver::EXIT_FAILURE + }); + + exit(return_code); }; if let Some(many_seeds) = self.many_seeds.take() { @@ -603,8 +628,11 @@ fn main() { } else if arg == "-Zmiri-many-seeds-keep-going" { many_seeds_keep_going = true; } else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") { - // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. - miri_config.borrow_tracker = None; + if !miri_config.genmc_mode { + miri_config.genmc_mode = true; + // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. + miri_config.borrow_tracker = None; + } GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); @@ -741,9 +769,9 @@ fn main() { // Validate settings for data race detection and GenMC mode. assert_eq!(genmc_config.is_some(), miri_config.genmc_mode); - if genmc_config.is_some() { + if miri_config.genmc_mode { if !miri_config.data_race_detector { - fatal_error!("Cannot disable data race detection in GenMC mode (currently)"); + fatal_error!("Cannot disable data race detection in GenMC mode"); } else if !miri_config.weak_memory_emulation { fatal_error!("Cannot disable weak memory emulation in GenMC mode"); } diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 38d76f5cf7..c9112cda08 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -71,7 +71,7 @@ pub enum AtomicRwOrd { } /// Valid atomic read orderings, subset of atomic::Ordering. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum AtomicReadOrd { Relaxed, Acquire, @@ -719,8 +719,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Only metadata on the location itself is used. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics - let old_val = None; + let old_val = this.run_for_validation_ref(|this| this.read_scalar(place)).discard_err(); return genmc_ctx.atomic_load( this, place.ptr().addr(), @@ -752,10 +751,21 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err(); + // Inform GenMC about the atomic store. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics - genmc_ctx.atomic_store(this, dest.ptr().addr(), dest.layout.size, val, atomic)?; + if genmc_ctx.atomic_store( + this, + dest.ptr().addr(), + dest.layout.size, + val, + old_val, + atomic, + )? { + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + this.allow_data_races_mut(|this| this.write_scalar(val, dest))?; + } return interp_ok(()); } this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; @@ -779,7 +789,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic rmw operation. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics let (old_val, new_val) = genmc_ctx.atomic_rmw_op( this, place.ptr().addr(), @@ -787,8 +796,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { atomic, (op, not), rhs.to_scalar(), + old.to_scalar(), )?; - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + if let Some(new_val) = new_val { + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + } return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } @@ -818,14 +830,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic atomic exchange. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics - let (old_val, _is_success) = genmc_ctx.atomic_exchange( + let (old_val, new_val) = genmc_ctx.atomic_exchange( this, place.ptr().addr(), place.layout.size, new, atomic, + old, )?; + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + if let Some(new_val) = new_val { + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + } return interp_ok(old_val); } @@ -851,7 +868,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic min/max operation. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics let (old_val, new_val) = genmc_ctx.atomic_min_max_op( this, place.ptr().addr(), @@ -860,8 +876,13 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { min, old.layout.backend_repr.is_signed(), rhs.to_scalar(), + old.to_scalar(), )?; - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + if let Some(new_val) = new_val { + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + } return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } @@ -903,6 +924,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; + // // FIXME(GenMC): this comment is wrong: // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -911,20 +933,24 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic atomic compare exchange. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let (old, cmpxchg_success) = genmc_ctx.atomic_compare_exchange( - this, - place.ptr().addr(), - place.layout.size, - this.read_scalar(expect_old)?, - new, - success, - fail, - can_fail_spuriously, - )?; - if cmpxchg_success { + let (old_value, is_co_maximal_write, cmpxchg_success) = genmc_ctx + .atomic_compare_exchange( + this, + place.ptr().addr(), + place.layout.size, + this.read_scalar(expect_old)?, + new, + success, + fail, + can_fail_spuriously, + old.to_scalar(), + )?; + // The store might be the latest store in coherence order (determined by GenMC). + // If it is, we need to update the value in Miri's memory: + if is_co_maximal_write { this.allow_data_races_mut(|this| this.write_scalar(new, place))?; } - return interp_ok(Immediate::ScalarPair(old, Scalar::from_bool(cmpxchg_success))); + return interp_ok(Immediate::ScalarPair(old_value, Scalar::from_bool(cmpxchg_success))); } // `binary_op` will bail if either of them is not a scalar. @@ -990,6 +1016,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(clock, &this.machine.threads); } + // TODO GENMC: does GenMC need to be informed about this? } } diff --git a/src/concurrency/genmc/config.rs b/src/concurrency/genmc/config.rs index f91211a670..aef41a0aa9 100644 --- a/src/concurrency/genmc/config.rs +++ b/src/concurrency/genmc/config.rs @@ -1,11 +1,27 @@ -use crate::MiriConfig; +use super::GenmcParams; +// TODO GENMC: document this: #[derive(Debug, Default, Clone)] pub struct GenmcConfig { - // TODO: add fields + pub(super) params: GenmcParams, + print_exec_graphs: bool, + do_estimation: bool, } impl GenmcConfig { + fn set_log_level_trace(&mut self) { + self.params.quiet = false; + self.params.log_level_trace = true; + } + + pub fn print_exec_graphs(&self) -> bool { + self.print_exec_graphs + } + + pub fn do_estimation(&self) -> bool { + self.do_estimation + } + /// Function for parsing command line options for GenMC mode. /// All GenMC arguments start with the string "-Zmiri-genmc". /// @@ -14,6 +30,35 @@ impl GenmcConfig { if genmc_config.is_none() { *genmc_config = Some(Default::default()); } - todo!("implement parsing of GenMC options") + if trimmed_arg.is_empty() { + return; // this corresponds to "-Zmiri-genmc" + } + let genmc_config = genmc_config.as_mut().unwrap(); + let trimmed_arg = trimmed_arg + .strip_prefix("-") + .unwrap_or_else(|| panic!("Invalid GenMC argument \"-Zmiri-genmc{trimmed_arg}\"")); + if trimmed_arg == "log-trace" { + // TODO GENMC: maybe expand to allow more control over log level? + genmc_config.set_log_level_trace(); + } else if trimmed_arg == "print-graphs" { + // TODO GENMC (DOCUMENTATION) + genmc_config.print_exec_graphs = true; + } else if trimmed_arg == "estimate" { + // TODO GENMC (DOCUMENTATION): naming, off/on by default? + genmc_config.do_estimation = true; + } else if let Some(estimation_max_str) = trimmed_arg.strip_prefix("estimation-max=") { + // TODO GENMC (DOCUMENTATION) + let estimation_max = estimation_max_str + .parse() + .expect("Zmiri-genmc-estimation-max expects a positive integer argument"); + assert!(estimation_max > 0); + genmc_config.params.estimation_max = estimation_max; + } else if trimmed_arg == "symmetry-reduction" { + // TODO GENMC (PERFORMANCE): maybe make this the default, have an option to turn it off instead + genmc_config.params.do_symmetry_reduction = true; + } else { + // TODO GENMC: how to properly handle this? + panic!("Invalid GenMC argument: \"-Zmiri-genmc-{trimmed_arg}\""); + } } } diff --git a/src/concurrency/genmc/cxx_extra.rs b/src/concurrency/genmc/cxx_extra.rs new file mode 100644 index 0000000000..55cfee57ea --- /dev/null +++ b/src/concurrency/genmc/cxx_extra.rs @@ -0,0 +1,48 @@ +#![allow(unused)] // TODO GENMC + +use std::pin::Pin; + +use cxx::UniquePtr; +use cxx::memory::UniquePtrTarget; + +#[repr(transparent)] +pub struct NonNullUniquePtr { + /// SAFETY: `inner` is never `null` + inner: UniquePtr, +} + +impl NonNullUniquePtr { + pub fn new(input: UniquePtr) -> Option { + if input.is_null() { + None + } else { + // SAFETY: `input` is not `null` + Some(unsafe { Self::new_unchecked(input) }) + } + } + + /// SAFETY: caller must ensure that `input` is not `null` + pub unsafe fn new_unchecked(input: UniquePtr) -> Self { + Self { inner: input } + } + + pub fn into_inner(self) -> UniquePtr { + self.inner + } + + pub fn as_mut(&mut self) -> Pin<&mut T> { + let ptr = self.inner.as_mut_ptr(); + + // SAFETY: `inner` is not `null` (type invariant) + let mut_reference = unsafe { ptr.as_mut().unwrap_unchecked() }; + // SAFETY: TODO GENMC (should be the same reason as in CXX crate, but there is no safety comment there) + unsafe { Pin::new_unchecked(mut_reference) } + } +} + +impl AsRef for NonNullUniquePtr { + fn as_ref(&self) -> &T { + // SAFETY: `inner` is not `null` (type invariant) + unsafe { self.inner.as_ref().unwrap_unchecked() } + } +} diff --git a/src/concurrency/genmc/dummy.rs b/src/concurrency/genmc/dummy.rs index 3d0558fb68..4a09a278d7 100644 --- a/src/concurrency/genmc/dummy.rs +++ b/src/concurrency/genmc/dummy.rs @@ -1,12 +1,10 @@ -#![allow(unused)] - use rustc_abi::{Align, Size}; -use rustc_const_eval::interpret::{InterpCx, InterpResult}; +use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult}; use rustc_middle::mir; use crate::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, - MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, + MiriMachine, OpTy, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, }; #[derive(Debug)] @@ -15,12 +13,18 @@ pub struct GenmcCtx {} #[derive(Debug, Default, Clone)] pub struct GenmcConfig {} +// TODO GENMC: add all exposed methods here too + impl GenmcCtx { pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self { unreachable!() } + + pub fn print_estimation_result(&self) { + unreachable!() + } - pub fn get_stuck_execution_count(&self) -> usize { + pub fn get_blocked_execution_count(&self) -> usize { unreachable!() } @@ -67,8 +71,9 @@ impl GenmcCtx { _address: Size, _size: Size, _value: Scalar, + _old_value: Option, _ordering: AtomicWriteOrd, - ) -> InterpResult<'tcx, ()> { + ) -> InterpResult<'tcx, bool> { unreachable!() } @@ -86,21 +91,23 @@ impl GenmcCtx { _address: Size, _size: Size, _ordering: AtomicRwOrd, - (rmw_op, not): (mir::BinOp, bool), + (_rmw_op, _not): (mir::BinOp, bool), _rhs_scalar: Scalar, + _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Scalar)> { unreachable!() } pub(crate) fn atomic_min_max_op<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - ordering: AtomicRwOrd, - min: bool, - is_signed: bool, - rhs_scalar: Scalar, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicRwOrd, + _min: bool, + _is_signed: bool, + _rhs_scalar: Scalar, + _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Scalar)> { unreachable!() } @@ -112,6 +119,7 @@ impl GenmcCtx { _size: Size, _rhs_scalar: Scalar, _ordering: AtomicRwOrd, + _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, bool)> { unreachable!() } @@ -126,6 +134,7 @@ impl GenmcCtx { _success: AtomicRwOrd, _fail: AtomicReadOrd, _can_fail_spuriously: bool, + _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, bool)> { unreachable!() } @@ -152,7 +161,8 @@ impl GenmcCtx { pub(crate) fn handle_alloc<'tcx>( &self, - _machine: &MiriMachine<'tcx>, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _alloc_id: AllocId, _size: Size, _alignment: Align, _memory_kind: MemoryKind, @@ -163,6 +173,7 @@ impl GenmcCtx { pub(crate) fn handle_dealloc<'tcx>( &self, _machine: &MiriMachine<'tcx>, + _alloc_id: AllocId, _address: Size, _size: Size, _align: Align, @@ -176,6 +187,8 @@ impl GenmcCtx { pub(crate) fn handle_thread_create<'tcx>( &self, _threads: &ThreadManager<'tcx>, + _start_routine: crate::Pointer, + _func_arg: &crate::ImmTy<'tcx>, _new_thread_id: ThreadId, ) -> InterpResult<'tcx, ()> { unreachable!() @@ -189,14 +202,19 @@ impl GenmcCtx { unreachable!() } - pub(crate) fn handle_thread_stack_empty(&self, _thread_id: ThreadId) { + pub(crate) fn handle_thread_stack_empty<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + _thread_id: ThreadId, + ) { unreachable!() } - pub(crate) fn handle_thread_finish<'tcx>( - &self, - _threads: &ThreadManager<'tcx>, - ) -> InterpResult<'tcx, ()> { + pub(crate) fn handle_main_thread_stack_empty<'tcx>(&self, _threads: &ThreadManager<'tcx>) { + unreachable!() + } + + pub(crate) fn handle_thread_finish<'tcx>(&self, _threads: &ThreadManager<'tcx>) { unreachable!() } @@ -208,14 +226,24 @@ impl GenmcCtx { ) -> InterpResult<'tcx, ThreadId> { unreachable!() } +} + +/// Other functionality not directly related to event handling +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn check_genmc_intercept_function( + &mut self, + _instance: rustc_middle::ty::Instance<'tcx>, + _args: &[rustc_const_eval::interpret::FnArg<'tcx, crate::Provenance>], + _dest: &crate::PlaceTy<'tcx>, + _ret: Option, + ) -> InterpResult<'tcx, bool> { + unreachable!() + } /**** Blocking instructions ****/ - pub(crate) fn handle_verifier_assume<'tcx>( - &self, - _machine: &MiriMachine<'tcx>, - _condition: bool, - ) -> InterpResult<'tcx, ()> { + fn handle_genmc_verifier_assume(&mut self, _condition: &OpTy<'tcx>) -> InterpResult<'tcx> { unreachable!() } } @@ -233,7 +261,11 @@ impl GenmcConfig { ); } - pub fn should_print_graph(&self, _rep: usize) -> bool { + pub fn print_exec_graphs(&self) -> bool { + unreachable!() + } + + pub fn do_estimation(&self) -> bool { unreachable!() } } diff --git a/src/concurrency/genmc/global_allocations.rs b/src/concurrency/genmc/global_allocations.rs new file mode 100644 index 0000000000..e2fafba9cc --- /dev/null +++ b/src/concurrency/genmc/global_allocations.rs @@ -0,0 +1,145 @@ +use std::cmp::max; +use std::collections::hash_map::Entry; +use std::sync::RwLock; + +use genmc_sys::{GENMC_GLOBAL_ADDRESSES_MASK, getGlobalAllocStaticMask}; +use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; +use rustc_const_eval::interpret::{ + AllocId, AllocInfo, AllocKind, InterpResult, PointerArithmetic, interp_ok, +}; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::{err_exhaust, throw_exhaust}; +use tracing::info; + +use crate::alloc_addresses::align_addr; + +#[derive(Debug, Default)] +pub struct GlobalAllocationHandler { + inner: RwLock, +} + +/// This contains more or less a subset of the functionality of `struct GlobalStateInner` in `alloc_addresses`. +#[derive(Clone, Debug)] +struct GlobalStateInner { + /// This is used as a map between the address of each allocation and its `AllocId`. It is always + /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset + /// from the base address, and we need to find the `AllocId` it belongs to. This is not the + /// *full* inverse of `base_addr`; dead allocations have been removed. + #[allow(unused)] // FIXME(GenMC): do we need this? + int_to_ptr_map: Vec<(u64, AllocId)>, + /// The base address for each allocation. + /// This is the inverse of `int_to_ptr_map`. + base_addr: FxHashMap, + /// This is used as a memory address when a new pointer is casted to an integer. It + /// is always larger than any address that was previously made part of a block. + next_base_addr: u64, + /// To add some randomness to the allocations + /// FIXME(GenMC): maybe seed this from the rng in MiriMachine? + rng: StdRng, +} + +impl Default for GlobalStateInner { + fn default() -> Self { + Self::new() + } +} + +impl GlobalStateInner { + pub fn new() -> Self { + assert_eq!(GENMC_GLOBAL_ADDRESSES_MASK, getGlobalAllocStaticMask()); + assert_ne!(GENMC_GLOBAL_ADDRESSES_MASK, 0); + Self { + int_to_ptr_map: Vec::default(), + base_addr: FxHashMap::default(), + next_base_addr: GENMC_GLOBAL_ADDRESSES_MASK, + rng: StdRng::seed_from_u64(0), + } + } + + fn global_allocate_addr<'tcx>( + &mut self, + alloc_id: AllocId, + info: AllocInfo, + ) -> InterpResult<'tcx, u64> { + let entry = match self.base_addr.entry(alloc_id) { + Entry::Occupied(occupied_entry) => { + // Looks like some other thread allocated this for us + // between when we released the read lock and aquired the write lock, + // so we just return that value. + return interp_ok(*occupied_entry.get()); + } + Entry::Vacant(vacant_entry) => vacant_entry, + }; + + // This is either called immediately after allocation (and then cached), or when + // adjusting `tcx` pointers (which never get freed). So assert that we are looking + // at a live allocation. This also ensures that we never re-assign an address to an + // allocation that previously had an address, but then was freed and the address + // information was removed. + assert!(!matches!(info.kind, AllocKind::Dead)); + + // This allocation does not have a base address yet, pick or reuse one. + + // We are not in native lib mode, so we control the addresses ourselves. + + // We have to pick a fresh address. + // Leave some space to the previous allocation, to give it some chance to be less aligned. + // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. + let slack = self.rng.random_range(0..16); + // From next_base_addr + slack, round up to adjust for alignment. + let base_addr = + self.next_base_addr.checked_add(slack).ok_or_else(|| err_exhaust!(AddressSpaceFull))?; + let base_addr = align_addr(base_addr, info.align.bytes()); + + // Remember next base address. If this allocation is zero-sized, leave a gap of at + // least 1 to avoid two allocations having the same base address. (The logic in + // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers + // need to be distinguishable!) + self.next_base_addr = base_addr + .checked_add(max(info.size.bytes(), 1)) + .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; + + assert_ne!(0, base_addr & GENMC_GLOBAL_ADDRESSES_MASK); + assert_ne!(0, self.next_base_addr & GENMC_GLOBAL_ADDRESSES_MASK); + // Cache the address for future use. + entry.insert(base_addr); + + interp_ok(base_addr) + } +} + +// FIXME(GenMC): "ExtPriv" or "PrivExt"? +impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} +pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn get_global_allocation_address( + &self, + global_allocation_handler: &GlobalAllocationHandler, + alloc_id: AllocId, + ) -> InterpResult<'tcx, u64> { + let this = self.eval_context_ref(); + let info = this.get_alloc_info(alloc_id); + + let global_state = global_allocation_handler.inner.read().unwrap(); + if let Some(base_addr) = global_state.base_addr.get(&alloc_id) { + info!( + "GenMC: address for global with alloc id {alloc_id:?} was cached: {base_addr} == {base_addr:#x}" + ); + return interp_ok(*base_addr); + } + + drop(global_state); + // We need to upgrade to a write lock. std::sync::RwLock doesn't support this, so we drop the guard and lock again + // Note that another thread might run in between and allocate the address, but we handle this case in the allocation function. + let mut global_state = global_allocation_handler.inner.write().unwrap(); + let base_addr = global_state.global_allocate_addr(alloc_id, info)?; + // Even if `Size` didn't overflow, we might still have filled up the address space. + if global_state.next_base_addr > this.target_usize_max() { + throw_exhaust!(AddressSpaceFull); + } + info!( + "GenMC: global with alloc id {alloc_id:?} got address: {base_addr} == {base_addr:#x}" + ); + interp_ok(base_addr) + } +} diff --git a/src/concurrency/genmc/helper.rs b/src/concurrency/genmc/helper.rs new file mode 100644 index 0000000000..e9d94be6cb --- /dev/null +++ b/src/concurrency/genmc/helper.rs @@ -0,0 +1,230 @@ +use rustc_abi::Size; +use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; +use rustc_middle::mir::{Terminator, TerminatorKind}; +use rustc_middle::ty::{self, ScalarInt, Ty}; +use tracing::info; + +use super::GenmcScalar; +use crate::alloc_addresses::EvalContextExt as _; +use crate::{ + BorTag, MiriInterpCx, MiriMachine, Pointer, Provenance, Scalar, ThreadId, throw_unsup_format, +}; + +const MEM_ACCESS_MAX_SIZE_BYTES: u64 = 8; + +pub fn split_access(address: Size, size: Size) -> impl Iterator { + // Handle possible misalignment: TODO GENMC: could always do largest power-of-two here + let size_bytes = size.bytes(); + + let start_address = address.bytes(); + let end_address = start_address + size_bytes; + // TODO GENMC: optimize this: + let start_missing = (MEM_ACCESS_MAX_SIZE_BYTES - (start_address % MEM_ACCESS_MAX_SIZE_BYTES)) + % MEM_ACCESS_MAX_SIZE_BYTES; + let end_missing = end_address % MEM_ACCESS_MAX_SIZE_BYTES; + + let start_address_aligned = start_address + start_missing; + let end_address_aligned = end_address - end_missing; + + info!( + "GenMC: splitting NA memory access into {MEM_ACCESS_MAX_SIZE_BYTES} byte chunks: {start_missing}B + {} * {MEM_ACCESS_MAX_SIZE_BYTES}B + {end_missing}B = {size:?}", + (end_address_aligned - start_address_aligned) / MEM_ACCESS_MAX_SIZE_BYTES + ); + debug_assert_eq!( + 0, + start_address_aligned % MEM_ACCESS_MAX_SIZE_BYTES, + "Incorrectly aligned start address: {start_address_aligned} % {MEM_ACCESS_MAX_SIZE_BYTES} != 0, {start_address} + {start_missing}" + ); + debug_assert_eq!( + 0, + end_address_aligned % MEM_ACCESS_MAX_SIZE_BYTES, + "Incorrectly aligned end address: {end_address_aligned} % {MEM_ACCESS_MAX_SIZE_BYTES} != 0, {end_address} - {end_missing}" + ); + debug_assert!( + start_missing < MEM_ACCESS_MAX_SIZE_BYTES && end_missing < MEM_ACCESS_MAX_SIZE_BYTES + ); + + let start_chunks = (start_address..start_address_aligned).map(|address| (address, 1)); + let aligned_chunks = (start_address_aligned..end_address_aligned) + .step_by(MEM_ACCESS_MAX_SIZE_BYTES.try_into().unwrap()) + .map(|address| (address, MEM_ACCESS_MAX_SIZE_BYTES)); + let end_chunks = (end_address_aligned..end_address).map(|address| (address, 1)); + + start_chunks.chain(aligned_chunks).chain(end_chunks) +} + +/// Convert an address (originally selected by GenMC) back into form that GenMC expects. +pub fn size_to_genmc(miri_address: Size) -> u64 { + miri_address.bytes() +} + +/// Like `scalar_to_genmc_scalar`, but returns an error if the scalar is not an integer +pub fn rhs_scalar_to_genmc_scalar<'tcx>( + ecx: &MiriInterpCx<'tcx>, + scalar: Scalar, +) -> InterpResult<'tcx, GenmcScalar> { + if matches!(scalar, Scalar::Ptr(..)) { + throw_unsup_format!("Right hand side of atomic operation cannot be a pointer"); + } + scalar_to_genmc_scalar(ecx, scalar) +} + +pub fn option_scalar_to_genmc_scalar<'tcx>( + ecx: &MiriInterpCx<'tcx>, + maybe_scalar: Option, +) -> InterpResult<'tcx, GenmcScalar> { + if let Some(scalar) = maybe_scalar { + scalar_to_genmc_scalar(ecx, scalar) + } else { + interp_ok(GenmcScalar::UNINIT) + } +} + +pub fn scalar_to_genmc_scalar<'tcx>( + ecx: &MiriInterpCx<'tcx>, + scalar: Scalar, +) -> InterpResult<'tcx, GenmcScalar> { + interp_ok(match scalar { + rustc_const_eval::interpret::Scalar::Int(scalar_int) => { + // TODO GENMC: u128 support + let value: u64 = scalar_int.to_uint(scalar_int.size()).try_into().unwrap(); // TODO GENMC: doesn't work for size != 8 + GenmcScalar { value, extra: 0, is_init: true } + } + rustc_const_eval::interpret::Scalar::Ptr(pointer, size) => { + let addr = Pointer::from(pointer).addr(); + if let Provenance::Wildcard = pointer.provenance { + throw_unsup_format!("Pointers with wildcard provenance not allowed in GenMC mode"); + } + let (alloc_id, _size, _prov_extra) = + rustc_const_eval::interpret::Machine::ptr_get_alloc(ecx, pointer, size.into()) + .unwrap(); + let base_addr = ecx.addr_from_alloc_id(alloc_id, None)?; + GenmcScalar { value: addr.bytes(), extra: base_addr, is_init: true } + } + }) +} + +pub fn genmc_scalar_to_scalar<'tcx>( + ecx: &MiriInterpCx<'tcx>, + scalar: GenmcScalar, + size: Size, +) -> InterpResult<'tcx, Scalar> { + // TODO GENMC: proper handling of large integers + // TODO GENMC: proper handling of pointers (currently assumes all integers) + + if scalar.extra != 0 { + // We have a pointer! + + let addr = Size::from_bytes(scalar.value); + let base_addr = scalar.extra; + + let alloc_size = 0; // TODO GENMC: what is the correct size here? Is 0 ok? + let only_exposed_allocations = false; + let Some(alloc_id) = + ecx.alloc_id_from_addr(base_addr, alloc_size, only_exposed_allocations) + else { + // TODO GENMC: what is the correct error in this case? + throw_unsup_format!( + "Cannot get allocation id of pointer received from GenMC (base address: 0x{base_addr:x}, pointer address: 0x{:x})", + addr.bytes() + ); + }; + + // TODO GENMC: is using `size: Size` ok here? Can we ever have `size != sizeof pointer`? + + // FIXME: Currently GenMC mode incompatible with aliasing model checking + let tag = BorTag::default(); + let provenance = crate::machine::Provenance::Concrete { alloc_id, tag }; + let offset = addr; + let ptr = rustc_middle::mir::interpret::Pointer::new(provenance, offset); + + let size = size.bytes().try_into().unwrap(); + return interp_ok(Scalar::Ptr(ptr, size)); + } + + // TODO GENMC (HACK): since we give dummy values to GenMC for NA accesses, we need to be able to convert it back: + let trunc_value = if size.bits() >= 64 { + scalar.value + } else { + let mask = (1u64 << size.bits()) - 1; + // let trunc_value = value & mask; + // eprintln!( + // "Masking {value} = 0x{value:x} to size {size:?}, with mask 0x{mask:x}, result: {trunc_value} = 0x{trunc_value:x}" + // ); + // trunc_value + scalar.value & mask + }; + + let Some(value_scalar_int) = ScalarInt::try_from_uint(trunc_value, size) else { + todo!( + "GenMC: cannot currently convert GenMC value {} (0x{:x}) (truncated {trunc_value} = 0x{trunc_value:x}), with size {size:?} into a Miri Scalar", + scalar.value, + scalar.value, + ); + }; + interp_ok(Scalar::Int(value_scalar_int)) +} + +pub fn is_terminator_atomic<'tcx>( + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + terminator: &Terminator<'tcx>, + thread_id: ThreadId, + // _cache: &mut FxHashMap, bool>, +) -> InterpResult<'tcx, bool> { + match &terminator.kind { + // All atomics are modeled as function calls to intrinsic functions. + // The one exception is thread joining, but those are also calls. + TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => { + let frame = ecx.machine.threads.get_thread_stack(thread_id).last().unwrap(); + let func_ty = func.ty(&frame.body().local_decls, *ecx.tcx); + info!("GenMC: terminator is a call with operand: {func:?}, ty of operand: {func_ty:?}"); + + is_function_atomic(ecx, func_ty) + + // match cache.entry(func_ty) { + // std::collections::hash_map::Entry::Occupied(occupied_entry) => { + // assert_eq!(is_function_atomic(ecx, func_ty)?, *occupied_entry.get()); + // interp_ok(*occupied_entry.get()) + // } + // std::collections::hash_map::Entry::Vacant(vacant_entry) => { + // let is_atomic = is_function_atomic(ecx, func_ty)?; + // vacant_entry.insert(is_atomic); + // interp_ok(is_atomic) + // } + // } + // } + } + _ => interp_ok(false), + } +} + +fn is_function_atomic<'tcx>( + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + func_ty: Ty<'tcx>, + // func: &Operand<'tcx>, +) -> InterpResult<'tcx, bool> { + let callee_def_id = match func_ty.kind() { + ty::FnDef(def_id, _args) => def_id, + _ => return interp_ok(true), // we don't know the callee, might be an intrinsic or pthread_join + }; + if ecx.tcx.is_foreign_item(*callee_def_id) { + // Some shims, like pthread_join, must be considered loads. So just consider them all loads, + // these calls are not *that* common. + return interp_ok(true); + } + + let Some(intrinsic_def) = ecx.tcx.intrinsic(callee_def_id) else { + // TODO GENMC: Make this work for other platforms? + let item_name = ecx.tcx.item_name(*callee_def_id); + info!("GenMC: function DefId: {callee_def_id:?}, item name: {item_name:?}"); + if matches!(item_name.as_str(), "pthread_join" | "WaitForSingleObject") { + info!("GenMC: found a 'join' terminator: '{}'", item_name.as_str(),); + return interp_ok(true); + } + return interp_ok(false); + }; + let intrinsice_name = intrinsic_def.name.as_str(); + info!("GenMC: intrinsic name: '{intrinsice_name}'"); + // TODO GENMC(ENHANCEMENT): make this more precise (only loads). How can we make this maintainable? + interp_ok(intrinsice_name.starts_with("atomic_")) +} diff --git a/src/concurrency/genmc/mapping.rs b/src/concurrency/genmc/mapping.rs new file mode 100644 index 0000000000..5a64eebef9 --- /dev/null +++ b/src/concurrency/genmc/mapping.rs @@ -0,0 +1,83 @@ +use genmc_sys::{MemOrdering, RMWBinOp}; + +use crate::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd}; + +impl AtomicReadOrd { + pub(super) fn convert(self) -> MemOrdering { + match self { + AtomicReadOrd::Relaxed => MemOrdering::Relaxed, + AtomicReadOrd::Acquire => MemOrdering::Acquire, + AtomicReadOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} + +impl AtomicWriteOrd { + pub(super) fn convert(self) -> MemOrdering { + match self { + AtomicWriteOrd::Relaxed => MemOrdering::Relaxed, + AtomicWriteOrd::Release => MemOrdering::Release, + AtomicWriteOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} + +impl AtomicFenceOrd { + pub(super) fn convert(self) -> MemOrdering { + match self { + AtomicFenceOrd::Acquire => MemOrdering::Acquire, + AtomicFenceOrd::Release => MemOrdering::Release, + AtomicFenceOrd::AcqRel => MemOrdering::AcquireRelease, + AtomicFenceOrd::SeqCst => MemOrdering::SequentiallyConsistent, + } + } +} + +impl AtomicRwOrd { + /// Split up an atomic read-write memory ordering into a separate read and write ordering. + pub(super) fn split_memory_orderings(self) -> (AtomicReadOrd, AtomicWriteOrd) { + match self { + AtomicRwOrd::Relaxed => (AtomicReadOrd::Relaxed, AtomicWriteOrd::Relaxed), + AtomicRwOrd::Acquire => (AtomicReadOrd::Acquire, AtomicWriteOrd::Relaxed), + AtomicRwOrd::Release => (AtomicReadOrd::Relaxed, AtomicWriteOrd::Release), + AtomicRwOrd::AcqRel => (AtomicReadOrd::Acquire, AtomicWriteOrd::Release), + AtomicRwOrd::SeqCst => (AtomicReadOrd::SeqCst, AtomicWriteOrd::SeqCst), + } + } + + /// Split up the atomic success ordering of a read-modify-write operation into GenMC's representation. + /// Note that both returned orderings are currently identical, because this is what GenMC expects. + pub(super) fn to_genmc_memory_orderings(self) -> (MemOrdering, MemOrdering) { + match self { + AtomicRwOrd::Relaxed => (MemOrdering::Relaxed, MemOrdering::Relaxed), + AtomicRwOrd::Acquire => (MemOrdering::Acquire, MemOrdering::Acquire), + AtomicRwOrd::Release => (MemOrdering::Release, MemOrdering::Release), + AtomicRwOrd::AcqRel => (MemOrdering::AcquireRelease, MemOrdering::AcquireRelease), + AtomicRwOrd::SeqCst => + (MemOrdering::SequentiallyConsistent, MemOrdering::SequentiallyConsistent), + } + } +} + +pub(super) fn min_max_to_genmc_rmw_op(min: bool, is_signed: bool) -> RMWBinOp { + match (min, is_signed) { + (true, true) => RMWBinOp::Min, // TODO GENMC: is there a use for FMin? (Min, UMin, FMin) + (false, true) => RMWBinOp::Max, + (true, false) => RMWBinOp::UMin, + (false, false) => RMWBinOp::UMax, + } +} + +pub(super) fn to_genmc_rmw_op(bin_op: rustc_middle::mir::BinOp, negate: bool) -> RMWBinOp { + match bin_op { + rustc_middle::mir::BinOp::Add => RMWBinOp::Add, + rustc_middle::mir::BinOp::Sub => RMWBinOp::Sub, + rustc_middle::mir::BinOp::BitOr if !negate => RMWBinOp::Or, + rustc_middle::mir::BinOp::BitXor if !negate => RMWBinOp::Xor, + rustc_middle::mir::BinOp::BitAnd if negate => RMWBinOp::Nand, + rustc_middle::mir::BinOp::BitAnd => RMWBinOp::And, + _ => { + panic!("unsupported atomic operation: bin_op: {bin_op:?}, negate: {negate}"); + } + } +} diff --git a/src/concurrency/genmc/miri_genmc.rs b/src/concurrency/genmc/miri_genmc.rs new file mode 100644 index 0000000000..950b270c0b --- /dev/null +++ b/src/concurrency/genmc/miri_genmc.rs @@ -0,0 +1,73 @@ +use std::fmt::Display; +use std::rc::Rc; +use std::time::Instant; + +use crate::{GenmcConfig, GenmcCtx, MiriConfig}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Mode { + Estimation, + Verification, +} + +impl Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Mode::Estimation => "Estimation", + Mode::Verification => "Verification", + }) + } +} + +pub fn run_genmc_mode( + config: &MiriConfig, + genmc_config: &GenmcConfig, + eval_entry: impl Fn(Rc) -> Option, + mode: Mode, +) -> Option { + let time_start = Instant::now(); + let genmc_ctx = Rc::new(GenmcCtx::new(config, genmc_config, mode)); + + for rep in 0u64.. { + tracing::info!("Miri-GenMC loop {}", rep + 1); + let result = eval_entry(genmc_ctx.clone()); + + if genmc_config.print_exec_graphs() { + genmc_ctx.print_genmc_graph(); + } + + // TODO GENMC (ERROR REPORTING): we currently do this here, so we can still print the GenMC graph above + let return_code = result?; + + let is_exploration_done = genmc_ctx.is_exploration_done(); + + tracing::info!( + "(GenMC Mode) Execution done (return code: {return_code}), is_exploration_done: {is_exploration_done}", + ); + + if is_exploration_done { + eprintln!(); + eprintln!("(GenMC) {mode} complete. No errors were detected.",); + + if mode == Mode::Estimation && return_code == 0 { + let elapsed_time = Instant::now().duration_since(time_start); + genmc_ctx.print_estimation_result(elapsed_time); + return Some(0); + } + + // TODO GENMC: proper message here, which info should be printed? + let blocked_execution_count = genmc_ctx.get_blocked_execution_count(); + // TODO GENMC: use VerificationResult instead: + let explored_execution_count = rep + 1 - blocked_execution_count; + eprintln!("Number of complete executions explored: {explored_execution_count}"); + if blocked_execution_count > 0 { + eprintln!("Number of blocked executions seen: {blocked_execution_count}"); + } + + // TODO GENMC: what is an appropriate return code? (since there are possibly many) + return Some(return_code); + } + } + tracing::error!("GenMC mode did not finish in 2^64 iterations!"); + None +} diff --git a/src/concurrency/genmc/mod.rs b/src/concurrency/genmc/mod.rs index 0dfd4b9b80..ab727ec0ce 100644 --- a/src/concurrency/genmc/mod.rs +++ b/src/concurrency/genmc/mod.rs @@ -1,63 +1,158 @@ -#![allow(unused)] // FIXME(GenMC): remove this - -use std::cell::Cell; +use std::cell::{Cell, RefCell}; +use std::sync::Arc; +use std::time::Duration; +use genmc_sys::{ + ActionKind, GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, GenmcThreadId, MemOrdering, + MiriGenMCShim, RMWBinOp, StoreEventType, createGenmcHandle, +}; use rustc_abi::{Align, Size}; -use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; -use rustc_middle::mir; +use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult, interp_ok}; +use rustc_middle::{mir, throw_machine_stop, throw_ub_format, throw_unsup_format}; +use tracing::info; +use self::cxx_extra::NonNullUniquePtr; +use self::global_allocations::{EvalContextExtPriv as _, GlobalAllocationHandler}; +use self::helper::{ + genmc_scalar_to_scalar, option_scalar_to_genmc_scalar, rhs_scalar_to_genmc_scalar, + scalar_to_genmc_scalar, size_to_genmc, +}; +use self::mapping::{min_max_to_genmc_rmw_op, to_genmc_rmw_op}; +use self::thread_info_manager::ThreadInfoManager; +use crate::concurrency::genmc::helper::{is_terminator_atomic, split_access}; +use crate::concurrency::genmc::warnings::WarningsCache; +use crate::concurrency::thread::{EvalContextExt as _, ThreadState}; use crate::{ - AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, - MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, + callback, AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, BlockReason, MachineCallback, MemoryKind, MiriConfig, MiriInterpCx, MiriMachine, MiriMemoryKind, OpTy, Scalar, TerminationInfo, ThreadId, ThreadManager, UnblockKind, VisitProvenance, VisitWith }; +pub mod miri_genmc; mod config; +mod cxx_extra; +mod global_allocations; +mod helper; +mod mapping; +mod thread_info_manager; +mod warnings; + +pub use genmc_sys::GenmcParams; pub use self::config::GenmcConfig; -// FIXME(GenMC): add fields +const UNSUPPORTED_ATOMICS_SIZE_MSG: &str = + "GenMC mode currently does not support atomics larger than 8 bytes."; + pub struct GenmcCtx { + handle: RefCell>, + + // TODO GENMC (PERFORMANCE): could use one RefCell for all internals instead of multiple + thread_infos: RefCell, + /// Some actions Miri does are allowed to cause data races. /// GenMC will not be informed about certain actions (e.g. non-atomic loads) when this flag is set. allow_data_races: Cell, + + main_thread_user_code_finished: Cell, + + /// Keep track of global allocations, to ensure they keep the same address across different executions, even if the order of allocations changes. + /// The `AllocId` for globals is stable across executions, so we can use it as an identifier. + global_allocations: Arc, + // TODO GENMC: maybe make this a (base, size), maybe BTreeMap/sorted vector for reverse lookups + // GenMC needs to have access to that + // TODO: look at code of "pub struct GlobalStateInner" + warnings_cache: RefCell, + + // terminator_cache: RefCell, bool>>, } +/// GenMC Context creation and administrative / query actions impl GenmcCtx { /// Create a new `GenmcCtx` from a given config. - pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self { + pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig, mode: miri_genmc::Mode) -> Self { assert!(miri_config.genmc_mode); - todo!() + info!("GenMC: Creating new GenMC Context"); + + let handle = createGenmcHandle(&genmc_config.params, mode == miri_genmc::Mode::Estimation); + let non_null_handle = NonNullUniquePtr::new(handle).expect("GenMC should not return null"); + let non_null_handle = RefCell::new(non_null_handle); + + Self { + handle: non_null_handle, + thread_infos: Default::default(), + allow_data_races: Cell::new(false), + main_thread_user_code_finished: Cell::new(false), + global_allocations: Default::default(), + warnings_cache: Default::default(), + // terminator_cache: Default::default(), + } } - pub fn get_stuck_execution_count(&self) -> usize { - todo!() + pub fn print_estimation_result(&self, elapsed_time: Duration) { + let elapsed_time_sec = elapsed_time.as_secs_f64(); + let mc = self.handle.borrow(); + mc.as_ref().printEstimationResults(elapsed_time_sec); + } + + pub fn get_blocked_execution_count(&self) -> u64 { + let mc = self.handle.borrow(); + mc.as_ref().getStuckExecutionCount() } pub fn print_genmc_graph(&self) { - todo!() + info!("GenMC: print the Execution graph"); + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.printGraph(); } /// This function determines if we should continue exploring executions or if we are done. /// /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. pub fn is_exploration_done(&self) -> bool { - todo!() + info!("GenMC: ask if execution exploration is done"); + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.isExplorationDone() } +} + +/// GenMC event handling. These methods are used to inform GenMC about events happening in the program, and to handle scheduling decisions. +impl GenmcCtx { + /**** Memory access handling ****/ /// Inform GenMC that a new program execution has started. /// This function should be called at the start of every execution. pub(crate) fn handle_execution_start(&self) { - todo!() + info!("GenMC: inform GenMC that new execution started"); + self.allow_data_races.replace(false); + self.main_thread_user_code_finished.set(false); + self.thread_infos.borrow_mut().reset(); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleExecutionStart(); } /// Inform GenMC that the program's execution has ended. /// - /// This function must be called even when the execution got stuck (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). + /// This function must be called even when the execution is blocked + /// (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcBlockedExecution`). pub(crate) fn handle_execution_end<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, ) -> Result<(), String> { - todo!() + info!("GenMC: inform GenMC that execution ended!"); + let mut mc = self.handle.borrow_mut(); + + let pinned_mc = mc.as_mut(); + let result = pinned_mc.handleExecutionEnd(); + if let Some(msg) = result.as_ref() { + let msg = msg.to_string_lossy().to_string(); + info!("GenMC: execution ended with error \"{msg}\""); + Err(msg) // TODO GENMC: add more error info here, and possibly handle this without requiring to clone the CxxString + } else { + Ok(()) + } } /**** Memory access handling ****/ @@ -72,20 +167,29 @@ impl GenmcCtx { /// # Panics /// If data race free is attempted to be set more than once (i.e., no nesting allowed). pub(super) fn set_ongoing_action_data_race_free(&self, enable: bool) { + info!("GenMC: set_ongoing_action_data_race_free ({enable})"); let old = self.allow_data_races.replace(enable); assert_ne!(old, enable, "cannot nest allow_data_races"); } + //* might fails if there's a race, load might also not read anything (returns None) */ pub(crate) fn atomic_load<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, address: Size, size: Size, ordering: AtomicReadOrd, + // The value that we would get, if we were to do a non-atomic load here. old_val: Option, ) -> InterpResult<'tcx, Scalar> { - assert!(!self.allow_data_races.get()); - todo!() + info!("GenMC: atomic_load: old_val: {old_val:?}"); + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let ordering = ordering.convert(); + let genmc_old_value = option_scalar_to_genmc_scalar(ecx, old_val)?; + let read_value = + self.atomic_load_impl(&ecx.machine, address, size, ordering, genmc_old_value)?; + info!("GenMC: atomic_load: received value from GenMC: {read_value:?}"); + genmc_scalar_to_scalar(ecx, read_value, size) } pub(crate) fn atomic_store<'tcx>( @@ -94,10 +198,15 @@ impl GenmcCtx { address: Size, size: Size, value: Scalar, + // The value that we would get, if we were to do a non-atomic load here. + old_value: Option, ordering: AtomicWriteOrd, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + ) -> InterpResult<'tcx, bool> { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let ordering = ordering.convert(); + let genmc_value = scalar_to_genmc_scalar(ecx, value)?; + let genmc_old_value = option_scalar_to_genmc_scalar(ecx, old_value)?; + self.atomic_store_impl(&ecx.machine, address, size, genmc_value, genmc_old_value, ordering) } pub(crate) fn atomic_fence<'tcx>( @@ -105,13 +214,26 @@ impl GenmcCtx { machine: &MiriMachine<'tcx>, ordering: AtomicFenceOrd, ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + info!("GenMC: atomic_fence with ordering: {ordering:?}"); + + let ordering = ordering.convert(); + + let thread_infos = self.thread_infos.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleFence(genmc_tid.0, ordering); + + // TODO GENMC: can this operation ever fail? + interp_ok(()) } /// Inform GenMC about an atomic read-modify-write operation. /// - /// Returns `(old_val, new_val)`. + /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. pub(crate) fn atomic_rmw_op<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -120,14 +242,32 @@ impl GenmcCtx { ordering: AtomicRwOrd, (rmw_op, not): (mir::BinOp, bool), rhs_scalar: Scalar, - ) -> InterpResult<'tcx, (Scalar, Scalar)> { - assert!(!self.allow_data_races.get()); - todo!() + // The value that we would get, if we were to do a non-atomic load here. + old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let (load_ordering, store_ordering) = ordering.to_genmc_memory_orderings(); + let genmc_rmw_op = to_genmc_rmw_op(rmw_op, not); + tracing::info!( + "GenMC: atomic_rmw_op (op: {rmw_op:?}, not: {not}, genmc_rmw_op: {genmc_rmw_op:?}): rhs value: {rhs_scalar:?}, orderings ({load_ordering:?}, {store_ordering:?})" + ); + let genmc_rhs_scalar = rhs_scalar_to_genmc_scalar(ecx, rhs_scalar)?; + let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; + self.atomic_rmw_op_impl( + ecx, + address, + size, + load_ordering, + store_ordering, + genmc_rmw_op, + genmc_rhs_scalar, + genmc_old_value, + ) } /// Inform GenMC about an atomic `min` or `max` operation. /// - /// Returns `(old_val, new_val)`. + /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. pub(crate) fn atomic_min_max_op<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -137,11 +277,30 @@ impl GenmcCtx { min: bool, is_signed: bool, rhs_scalar: Scalar, - ) -> InterpResult<'tcx, (Scalar, Scalar)> { - assert!(!self.allow_data_races.get()); - todo!() + // The value that we would get, if we were to do a non-atomic load here. + old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let (load_ordering, store_ordering) = ordering.to_genmc_memory_orderings(); + let genmc_rmw_op = min_max_to_genmc_rmw_op(min, is_signed); + tracing::info!( + "GenMC: atomic_min_max_op (min: {min}, signed: {is_signed}, genmc_rmw_op: {genmc_rmw_op:?}): rhs value: {rhs_scalar:?}, orderings ({load_ordering:?}, {store_ordering:?})" + ); + let genmc_rhs_scalar = rhs_scalar_to_genmc_scalar(ecx, rhs_scalar)?; + let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; + self.atomic_rmw_op_impl( + ecx, + address, + size, + load_ordering, + store_ordering, + genmc_rmw_op, + genmc_rhs_scalar, + genmc_old_value, + ) } + /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. pub(crate) fn atomic_exchange<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -149,9 +308,29 @@ impl GenmcCtx { size: Size, rhs_scalar: Scalar, ordering: AtomicRwOrd, - ) -> InterpResult<'tcx, (Scalar, bool)> { - assert!(!self.allow_data_races.get()); - todo!() + // The value that we would get, if we were to do a non-atomic load here. + old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + // TODO GENMC: could maybe merge this with atomic_rmw? + + let (load_ordering, store_ordering) = ordering.to_genmc_memory_orderings(); + let genmc_rmw_op = RMWBinOp::Xchg; + tracing::info!( + "GenMC: atomic_exchange (op: {genmc_rmw_op:?}): new value: {rhs_scalar:?}, orderings ({load_ordering:?}, {store_ordering:?})" + ); + let genmc_rhs_scalar = scalar_to_genmc_scalar(ecx, rhs_scalar)?; + let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; + self.atomic_rmw_op_impl( + ecx, + address, + size, + load_ordering, + store_ordering, + genmc_rmw_op, + genmc_rhs_scalar, + genmc_old_value, + ) } pub(crate) fn atomic_compare_exchange<'tcx>( @@ -164,9 +343,68 @@ impl GenmcCtx { success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, - ) -> InterpResult<'tcx, (Scalar, bool)> { - assert!(!self.allow_data_races.get()); - todo!() + // The value that we would get, if we were to do a non-atomic load here. + old_value: Scalar, + ) -> InterpResult<'tcx, (Scalar, bool, bool)> { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + + // FIXME(genmc): remove once GenMC supports failure memory ordering in `compare_exchange`. + self.warnings_cache.borrow_mut().warn_once_rmw_failure_ordering(&ecx.tcx, success, fail); + // FIXME(genmc): remove once GenMC implements spurious failures for `compare_exchange_weak`. + if can_fail_spuriously { + self.warnings_cache.borrow_mut().warn_once_compare_exchange_weak(&ecx.tcx); + } + + let machine = &ecx.machine; + let (success_load_ordering, success_store_ordering) = success.to_genmc_memory_orderings(); + let fail_load_ordering = fail.convert(); + + info!( + "GenMC: atomic_compare_exchange, address: {address:?}, size: {size:?} (expect: {expected_old_value:?}, new: {new_value:?}, old_value: {old_value:?}, {success:?}, {fail:?}), can fail spuriously: {can_fail_spuriously}" + ); + info!( + "GenMC: atomic_compare_exchange orderings: success: ({success_load_ordering:?}, {success_store_ordering:?}), failure load ordering: {fail_load_ordering:?}" + ); + + let thread_infos = self.thread_infos.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; + + let genmc_address = size_to_genmc(address); + let genmc_size = size_to_genmc(size); + + let genmc_expected_value = scalar_to_genmc_scalar(ecx, expected_old_value)?; + let genmc_new_value = scalar_to_genmc_scalar(ecx, new_value)?; + let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let cas_result = pinned_mc.handleCompareExchange( + genmc_tid.0, + genmc_address, + genmc_size, + genmc_expected_value, + genmc_new_value, + genmc_old_value, + success_load_ordering, + success_store_ordering, + fail_load_ordering, + can_fail_spuriously, + ); + + if let Some(error) = cas_result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: RMW operation returned an error: \"{msg}\""); + throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here + } + + let return_scalar = genmc_scalar_to_scalar(ecx, cas_result.old_value, size)?; + info!( + "GenMC: atomic_compare_exchange: result: {cas_result:?}, returning scalar: {return_scalar:?}" + ); + // The write can only be a co-maximal write if the CAS succeeded. + assert!(cas_result.is_success || !cas_result.isCoMaxWrite); + interp_ok((return_scalar, cas_result.isCoMaxWrite, cas_result.is_success)) } /// Inform GenMC about a non-atomic memory load @@ -178,7 +416,59 @@ impl GenmcCtx { address: Size, size: Size, ) -> InterpResult<'tcx, ()> { - todo!() + if self.allow_data_races.get() { + // TODO GENMC: handle this properly + info!("GenMC: skipping `handle_load`"); + return interp_ok(()); + } + info!( + "GenMC: received memory_load (non-atomic): address: {:#x}, size: {}", + address.bytes(), + size.bytes() + ); + // GenMC doesn't like ZSTs, and they can't have any data races, so we skip them + if size.bytes() == 0 { + return interp_ok(()); + } + + // TODO GENMC: can this be improved? + if machine.threads.active_thread() == ThreadId::MAIN_THREAD + && self.main_thread_user_code_finished.get() + { + info!("GenMC: skipping `memory_load` for finished main thread"); + return interp_ok(()); + } + + // let _read_value = + // self.atomic_load_impl(machine, address, size, MemOrdering::NotAtomic)?; + + // // TODO GENMC (HACK): to handle large non-atomics, we ignore the value by GenMC for now + // interp_ok(Scalar::from_u64(0xDEADBEEF)) + + if size.bytes() <= 8 { + // NOTE: Values loaded non-atomically are still handled by Miri, so we discard whatever we get from GenMC + let _read_value = self.atomic_load_impl( + machine, + address, + size, + MemOrdering::NotAtomic, + GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value + )?; + return interp_ok(()); + } + + for (address, size) in split_access(address, size) { + let chunk_addr = Size::from_bytes(address); + let chunk_size = Size::from_bytes(size); + let _read_value = self.atomic_load_impl( + machine, + chunk_addr, + chunk_size, + MemOrdering::NotAtomic, + GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value + )?; + } + interp_ok(()) } pub(crate) fn memory_store<'tcx>( @@ -186,31 +476,168 @@ impl GenmcCtx { machine: &MiriMachine<'tcx>, address: Size, size: Size, + // old_value: Option, // TODO GENMC(mixed atomic-non-atomic): is this needed? ) -> InterpResult<'tcx, ()> { - todo!() + if self.allow_data_races.get() { + // TODO GENMC: handle this properly + info!( + "GenMC: skipping `handle_store` for address {addr} == {addr:#x}, size: {}", + size.bytes(), + addr = address.bytes() + ); + return interp_ok(()); + } + // GenMC doesn't like ZSTs, and they can't have any data races, so we skip them + if size.bytes() == 0 { + return interp_ok(()); + } + + // TODO GENMC: can this be improved? + if machine.threads.active_thread() == ThreadId::MAIN_THREAD + && self.main_thread_user_code_finished.get() + { + info!("GenMC: skipping `memory_store` for finished main thread"); + return interp_ok(()); + } + + if size.bytes() <= 8 { + // TODO GENMC(mixed atomic-non-atomics): anything to do here? + let _is_co_max_write = self.atomic_store_impl( + machine, + address, + size, + GenmcScalar::DUMMY, + GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value + MemOrdering::NotAtomic, + )?; + return interp_ok(()); + } + + for (address, size) in split_access(address, size) { + let chunk_addr = Size::from_bytes(address); + let chunk_size = Size::from_bytes(size); + // TODO GENMC(mixed atomic-non-atomics): anything to do here? + let _is_co_max_write = self.atomic_store_impl( + machine, + chunk_addr, + chunk_size, + GenmcScalar::DUMMY, + GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value + MemOrdering::NotAtomic, + )?; + } + interp_ok(()) } /**** Memory (de)allocation ****/ pub(crate) fn handle_alloc<'tcx>( &self, - machine: &MiriMachine<'tcx>, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + alloc_id: AllocId, size: Size, alignment: Align, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - todo!() + let machine = &ecx.machine; + let chosen_address = if memory_kind == MiriMemoryKind::Global.into() { + info!("GenMC: global memory allocation: {alloc_id:?}"); + ecx.get_global_allocation_address(&self.global_allocations, alloc_id)? + } else { + // TODO GENMC: Does GenMC need to know about the kind of Memory? + + // eprintln!( + // "handle_alloc ({memory_kind:?}): Custom backtrace: {}", + // std::backtrace::Backtrace::force_capture() + // ); + // TODO GENMC: should we put this before the special handling for globals? + if self.allow_data_races.get() { + // TODO GENMC: handle this properly + info!("GenMC: skipping `handle_alloc`"); + return interp_ok(0); + } + let thread_infos = self.thread_infos.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; + // GenMC doesn't support ZSTs, so we set the minimum size to 1 byte + let genmc_size = size_to_genmc(size).max(1); + info!( + "GenMC: handle_alloc (thread: {curr_thread:?} ({genmc_tid:?}), size: {}, alignment: {alignment:?}, memory_kind: {memory_kind:?})", + size.bytes() + ); + // TODO GENMC: can this be improved? + if curr_thread == ThreadId::MAIN_THREAD && self.main_thread_user_code_finished.get() { + panic!("GenMC: `handle_alloc` on finished main thread"); + } + + let alignment = alignment.bytes(); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let chosen_address = pinned_mc.handleMalloc(genmc_tid.0, genmc_size, alignment); + info!("GenMC: handle_alloc: got address '{chosen_address}' ({chosen_address:#x})"); + + // TODO GENMC: + if chosen_address == 0 { + throw_unsup_format!("TODO GENMC: we got address '0' from malloc"); + } + assert_eq!(0, chosen_address & GENMC_GLOBAL_ADDRESSES_MASK); + chosen_address + }; + // Sanity check the address alignment: + assert_eq!( + 0, + chosen_address % alignment.bytes(), + "GenMC returned address {chosen_address} == {chosen_address:#x} with lower alignment than requested ({:})!", + alignment.bytes() + ); + + interp_ok(chosen_address) } pub(crate) fn handle_dealloc<'tcx>( &self, machine: &MiriMachine<'tcx>, + alloc_id: AllocId, address: Size, size: Size, align: Align, kind: MemoryKind, ) -> InterpResult<'tcx, ()> { - todo!() + assert_ne!( + kind, + MiriMemoryKind::Global.into(), + "we probably shouldn't try to deallocate global allocations (alloc_id: {alloc_id:?})" + ); + if self.allow_data_races.get() { + // TODO GENMC: handle this properly, should this be skipped in this mode? + info!("GenMC: skipping `handle_dealloc`"); + return interp_ok(()); + } + // eprintln!("handle_dealloc: Custom backtrace: {}", std::backtrace::Backtrace::force_capture()); + let thread_infos = self.thread_infos.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; + info!( + "GenMC: memory deallocation, thread: {curr_thread:?} ({genmc_tid:?}), address: {addr} == {addr:#x}, size: {size:?}, align: {align:?}, memory_kind: {kind:?}", + addr = address.bytes() + ); + // TODO GENMC: can this be improved? + if curr_thread == ThreadId::MAIN_THREAD && self.main_thread_user_code_finished.get() { + info!("GenMC: skipping `handle_dealloc` for finished main thread"); + return interp_ok(()); + } + + let genmc_address = size_to_genmc(address); + // GenMC doesn't support ZSTs, so we set the minimum size to 1 byte + let genmc_size = size_to_genmc(size).max(1); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleFree(genmc_tid.0, genmc_address, genmc_size); + + // TODO GENMC (ERROR HANDLING): can this ever fail? + interp_ok(()) } /**** Thread management ****/ @@ -218,10 +645,27 @@ impl GenmcCtx { pub(crate) fn handle_thread_create<'tcx>( &self, threads: &ThreadManager<'tcx>, + _start_routine: crate::Pointer, // TODO GENMC: pass info to GenMC + _func_arg: &crate::ImmTy<'tcx>, new_thread_id: ThreadId, ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let mut thread_infos = self.thread_infos.borrow_mut(); + + let curr_thread_id = threads.active_thread(); + let genmc_parent_tid = thread_infos.get_info(curr_thread_id).genmc_tid; + let genmc_new_tid = thread_infos.add_thread(new_thread_id); + + info!( + "GenMC: handling thread creation (thread {curr_thread_id:?} ({genmc_parent_tid:?}) spawned thread {new_thread_id:?} ({genmc_new_tid:?}))" + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleThreadCreate(genmc_new_tid.0, genmc_parent_tid.0); + + // TODO GENMC (ERROR HANDLING): can this ever fail? + interp_ok(()) } pub(crate) fn handle_thread_join<'tcx>( @@ -229,46 +673,589 @@ impl GenmcCtx { active_thread_id: ThreadId, child_thread_id: ThreadId, ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let thread_infos = self.thread_infos.borrow(); + + let genmc_curr_tid = thread_infos.get_info(active_thread_id).genmc_tid; + let genmc_child_tid = thread_infos.get_info(child_thread_id).genmc_tid; + + info!( + "GenMC: handling thread joining (thread {active_thread_id:?} ({genmc_curr_tid:?}) joining thread {child_thread_id:?} ({genmc_child_tid:?}))" + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + + // TODO GENMC: error handling: + pinned_mc.handleThreadJoin(genmc_curr_tid.0, genmc_child_tid.0); + + interp_ok(()) + } + + pub(crate) fn handle_thread_stack_empty<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + thread_id: ThreadId, + ) { + // TODO GENMC(CLEANUP): do we need this for all threads? + info!("GenMC: thread stack empty: {thread_id:?}"); + // warn!("GenMC: thread stack empty: {thread_id:?}"); + { + let mut thread_infos = self.thread_infos.borrow_mut(); + let info = thread_infos.get_info_mut(thread_id); + info.user_code_finished = true; + } + + // if thread_id == ThreadId::MAIN_THREAD { + // // Miri stops once the main thread is finished, but GenMC doesn't know that. + // // We tell GenMC that the main thread is already finished now, so it won't be scheduled by GenMC again. + // self.handle_thread_finish(threads); + // } } - pub(crate) fn handle_thread_stack_empty(&self, thread_id: ThreadId) { - todo!() + pub(crate) fn handle_main_thread_stack_empty<'tcx>(&self, threads: &ThreadManager<'tcx>) { + // TODO GENMC(CLEANUP): do we need this for all threads? + info!("GenMC: main thread stack empty"); + // warn!("GenMC: main thread stack empty: {thread_id:?}"); + // { + // let mut thread_infos = self.thread_infos.borrow_mut(); + // let info = thread_infos.get_info_mut(thread_id); + // info.user_code_finished = true; + // } + + // if thread_id == ThreadId::MAIN_THREAD { + // Miri stops once the main thread is finished, but GenMC doesn't know that. + // We tell GenMC that the main thread is already finished now, so it won't be scheduled by GenMC again. + self.handle_thread_finish(threads); + // } } - pub(crate) fn handle_thread_finish<'tcx>( + pub(crate) fn handle_thread_finish<'tcx>(&self, threads: &ThreadManager<'tcx>) { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let curr_thread_id = threads.active_thread(); + if curr_thread_id == ThreadId::MAIN_THREAD { + if self.main_thread_user_code_finished.replace(true) { + info!("GenMC: Skip repeated thread finish for main thread."); + // warn!("GenMC: Skip repeated thread finish for main thread."); + return; + } + // self.main_thread_user_code_finished.set(true); + } + + let thread_infos = self.thread_infos.borrow(); + let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; + + // NOTE: Miri doesn't support return values for threads, but GenMC expects one, so we return 0 + let ret_val = 0; + + info!( + "GenMC: handling thread finish (thread {curr_thread_id:?} ({genmc_tid:?}) returns with dummy value 0)" + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleThreadFinish(genmc_tid.0, ret_val); + } + + /**** Scheduling functionality ****/ + + pub(crate) fn schedule_thread<'tcx>( &self, - threads: &ThreadManager<'tcx>, - ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); - todo!() + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> InterpResult<'tcx, ThreadId> { + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let thread_manager = &ecx.machine.threads; + let active_thread_id = thread_manager.active_thread(); + + let curr_thread_next_instr_kind = + if !thread_manager.active_thread_ref().get_state().is_enabled() + || (active_thread_id == ThreadId::MAIN_THREAD + && self.main_thread_user_code_finished.get()) + { + // There are 2 cases where we need to schedule always: + // - The current thread is blocked (e.g., due to a thread join, assume statement, ...), we need to ask for another thread to schedule. + // - The current thread is the main thread, and it has completed all user code. + info!("GenMC: schedule_thread: overriding check for terminator."); + ActionKind::NonLoad + } else { + let Some(frame) = thread_manager.get_thread_stack(active_thread_id).last() else { + info!("GenMC: Skipping scheduling (0)"); + return interp_ok(active_thread_id); + }; + let either::Either::Left(loc) = frame.current_loc() else { + // We are unwinding. + info!("GenMC: Skipping scheduling (1): unwinding"); + return interp_ok(active_thread_id); + }; + let basic_block = &frame.body().basic_blocks[loc.block]; + if let Some(_statement) = basic_block.statements.get(loc.statement_index) { + info!("GenMC: Skipping scheduling (2): Statement: {_statement:?}"); + return interp_ok(active_thread_id); + } + + // let mut terminator_cache = self.terminator_cache.borrow_mut(); + // let curr_thread_next_instr_kind = + // get_next_instr_kind(ecx, thread_manager, active_thread_id, &mut terminator_cache)?; + // let is_terminator_atomic = + if is_terminator_atomic( + ecx, + basic_block.terminator(), + active_thread_id, + // &mut terminator_cache, + )? { + ActionKind::Load + } else { + ActionKind::NonLoad + } + }; + + info!( + "GenMC: schedule_thread, active thread: {active_thread_id:?}, next instr.: '{curr_thread_next_instr_kind:?}'" + ); + + // let curr_thread_user_block = self.curr_thread_user_block.replace(false); + let thread_infos = self.thread_infos.borrow(); + let curr_thread_info = thread_infos.get_info(active_thread_id); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let result = + pinned_mc.scheduleNext(curr_thread_info.genmc_tid.0, curr_thread_next_instr_kind); + if result >= 0 { + // TODO GENMC: can we ensure this thread_id is valid? + let genmc_next_thread_id = result.try_into().unwrap(); + let genmc_next_thread_id = GenmcThreadId(genmc_next_thread_id); + let thread_infos = self.thread_infos.borrow(); + let next_thread_id = thread_infos.get_info_genmc(genmc_next_thread_id).miri_tid; + + return interp_ok(next_thread_id); + } + + // Negative result means that GenMC has no next thread to schedule. + // We could either be encountering a blocked execution, + // or we are in the special case of the main thread having all user code finished. + // If the latter is true, we schedule the main thread. + info!( + "GenMC: scheduleNext returned no thread to schedule. Is main thread user code finished: {}", + self.main_thread_user_code_finished.get() + ); + if self.main_thread_user_code_finished.get() + && thread_manager.threads_ref().iter_enumerated().all(|(thread_id, thread)| { + thread_id == ThreadId::MAIN_THREAD || thread.get_state().is_terminated() + }) + { + let state = thread_manager.threads_ref()[ThreadId::MAIN_THREAD].get_state(); + if !state.is_terminated() { + info!( + "GenMC: main thread user code finished, but not yet terminated (state: {state:?})" + ); + return interp_ok(ThreadId::MAIN_THREAD); + } + info!( + "GenMC: main thread user code finished and also terminated (state: {state:?})" + ); + } + throw_machine_stop!(TerminationInfo::GenmcBlockedExecution); + } +} + +impl GenmcCtx { + //* might fails if there's a race, load might also not read anything (returns None) */ + fn atomic_load_impl<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + memory_ordering: MemOrdering, + genmc_old_value: GenmcScalar, + ) -> InterpResult<'tcx, GenmcScalar> { + assert!( + size.bytes() != 0 + && (memory_ordering == MemOrdering::NotAtomic || size.bytes().is_power_of_two()) + ); + if size.bytes() > 8 { + throw_unsup_format!("{UNSUPPORTED_ATOMICS_SIZE_MSG}"); + } + assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly + let thread_infos = self.thread_infos.borrow(); + let curr_thread_id = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; + + info!( + "GenMC: load, thread: {curr_thread_id:?} ({genmc_tid:?}), address: {addr} == {addr:#x}, size: {size:?}, ordering: {memory_ordering:?}, old_value: {genmc_old_value:x?}", + addr = address.bytes() + ); + let genmc_address = size_to_genmc(address); + let genmc_size = size_to_genmc(size); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let load_result = pinned_mc.handleLoad( + genmc_tid.0, + genmc_address, + genmc_size, + memory_ordering, + genmc_old_value, + ); + + if load_result.is_read_opt { + todo!(); + } + + if let Some(error) = load_result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: load operation returned an error: \"{msg}\""); + throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here + } + + info!("GenMC: load returned value: {:?}", load_result.read_value); + + interp_ok(load_result.read_value) + } + + fn atomic_store_impl<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + genmc_value: GenmcScalar, + genmc_old_value: GenmcScalar, + memory_ordering: MemOrdering, + ) -> InterpResult<'tcx, bool> { + assert!( + size.bytes() != 0 + && (memory_ordering == MemOrdering::NotAtomic || size.bytes().is_power_of_two()) + ); + if size.bytes() > 8 { + throw_unsup_format!("{UNSUPPORTED_ATOMICS_SIZE_MSG}"); + } + let thread_infos = self.thread_infos.borrow(); + let curr_thread_id = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; + + let genmc_address = size_to_genmc(address); + let genmc_size = size_to_genmc(size); + + info!( + "GenMC: store, thread: {curr_thread_id:?} ({genmc_tid:?}), address: {addr} = {addr:#x}, size: {size:?}, ordering {memory_ordering:?}, value: {genmc_value:?}", + addr = address.bytes() + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let store_result = pinned_mc.handleStore( + genmc_tid.0, + genmc_address, + genmc_size, + genmc_value, + genmc_old_value, + memory_ordering, + StoreEventType::Normal, + ); + + if let Some(error) = store_result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: store operation returned an error: \"{msg}\""); + throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here + } + + interp_ok(store_result.isCoMaxWrite) + } + + pub(crate) fn atomic_rmw_op_impl<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + load_ordering: MemOrdering, + store_ordering: MemOrdering, + genmc_rmw_op: RMWBinOp, + genmc_rhs_scalar: GenmcScalar, + genmc_old_value: GenmcScalar, + ) -> InterpResult<'tcx, (Scalar, Option)> { + assert!( + size.bytes() <= 8, + "TODO GENMC: no support for accesses larger than 8 bytes (got {} bytes)", + size.bytes() + ); + let machine = &ecx.machine; + assert_ne!(0, size.bytes()); + let thread_infos = self.thread_infos.borrow(); + let curr_thread_id = machine.threads.active_thread(); + let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; + + let genmc_address = size_to_genmc(address); + let genmc_size = size_to_genmc(size); + + info!( + "GenMC: atomic_rmw_op, thread: {curr_thread_id:?} ({genmc_tid:?}) (op: {genmc_rmw_op:?}, rhs value: {genmc_rhs_scalar:?}), address: {address:?}, size: {size:?}, orderings: ({load_ordering:?}, {store_ordering:?})", + ); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let rmw_result = pinned_mc.handleReadModifyWrite( + genmc_tid.0, + genmc_address, + genmc_size, + load_ordering, + store_ordering, + genmc_rmw_op, + genmc_rhs_scalar, + genmc_old_value, + ); + + if let Some(error) = rmw_result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: RMW operation returned an error: \"{msg}\""); + throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here + } + + let old_value_scalar = genmc_scalar_to_scalar(ecx, rmw_result.old_value, size)?; + + let new_value_scalar = if rmw_result.isCoMaxWrite { + Some(genmc_scalar_to_scalar(ecx, rmw_result.new_value, size)?) + } else { + None + }; + interp_ok((old_value_scalar, new_value_scalar)) + } + + fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { + let thread_infos = self.thread_infos.borrow(); + let curr_thread = machine.threads.active_thread(); + let genmc_curr_thread = thread_infos.get_info(curr_thread).genmc_tid; + info!("GenMC: handle_user_block, blocking thread {curr_thread:?} ({genmc_curr_thread:?})"); + + let mut mc = self.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleUserBlock(genmc_curr_thread.0); + + interp_ok(()) + } +} + +/// Other functionality not directly related to event handling +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Given a `ty::Instance<'tcx>`, do any required special handling. Returns true if this `instance` should be skipped (i.e., no Mir should be executed for it). + fn check_genmc_intercept_function( + &mut self, + instance: rustc_middle::ty::Instance<'tcx>, + args: &[rustc_const_eval::interpret::FnArg<'tcx, crate::Provenance>], + dest: &crate::PlaceTy<'tcx>, + ret: Option, + ) -> InterpResult<'tcx, bool> { + let this = self.eval_context_mut(); + let genmc_ctx = this + .machine + .data_race + .as_genmc_ref() + .expect("This function should only be called in GenMC mode."); + + let get_mutex_call_infos = || { + // assert!(!args.is_empty()); + assert_eq!(args.len(), 1); + let arg = this.copy_fn_arg(&args[0]); + let addr = this.read_target_usize(&arg)?; + // FIXME(genmc): assert that we have at least 1 byte. + // FIXME(genmc): maybe use actual size of mutex here?. + + let thread_infos = genmc_ctx.thread_infos.borrow(); + let curr_thread = this.machine.threads.active_thread(); + let genmc_curr_thread = thread_infos.get_info(curr_thread).genmc_tid; + interp_ok((genmc_curr_thread, addr, 1)) + }; + + use rustc_span::sym; + if this.tcx.is_diagnostic_item(sym::sys_mutex_lock, instance.def_id()) { + info!("GenMC: handling Mutex::lock()"); + let (genmc_curr_thread, addr, size) = get_mutex_call_infos()?; + + let result = { + let mut mc = genmc_ctx.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleMutexLock(genmc_curr_thread.0, addr, size) + }; + if let Some(error) = result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: handling Mutex::lock: error: {msg:?}"); + throw_ub_format!("{msg}"); + } + // TODO GENMC(HACK): for determining if the Mutex lock blocks this thread. + if !result.is_lock_acquired { + fn create_callback<'tcx>( + genmc_curr_thread: i32, + addr: u64, + size: u64, + ) -> crate::DynUnblockCallback<'tcx> { + crate::callback!( + @capture<'tcx> { + // mutex_ref: MutexRef, + // retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, + genmc_curr_thread: i32, + addr: u64, + size: u64, + } + |this, unblock: crate::UnblockKind| { + assert_eq!(unblock, crate::UnblockKind::Ready); + let genmc_ctx = this.machine.data_race.as_genmc_ref().unwrap(); + + info!("GenMC: handling Mutex::lock: unblocking callback called!"); + let result = { + let mut mc = genmc_ctx.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleMutexLock(genmc_curr_thread, addr, size) + }; + if let Some(error) = result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: handling Mutex::lock: error: {msg:?}"); + throw_ub_format!("{msg}"); + } + // TODO GENMC(HACK): for determining if the Mutex lock blocks this thread. + if !result.is_lock_acquired { + // If this thread gets woken up without the mutex being made available, block the thread again. + this.block_thread( crate::BlockReason::Mutex, None, create_callback(genmc_curr_thread, addr, size)); + // panic!( + // "Somehow, Mutex is still locked after waiting thread was unblocked?!" + // ); + } + interp_ok(()) + } + ) + } + + info!("GenMC: handling Mutex::lock failed, blocking thread"); + // NOTE: We don't write anything back to Miri's memory, the Mutex state is handled only by GenMC. + + info!("GenMC: blocking thread due to intercepted call."); + let genmc_curr_thread = genmc_curr_thread.0; + this.block_thread( + crate::BlockReason::Mutex, + None, + create_callback(genmc_curr_thread, addr, size), + ); + } else { + info!("GenMC: handling Mutex::lock: success: lock acquired."); + } + } else if this.tcx.is_diagnostic_item(sym::sys_mutex_try_lock, instance.def_id()) { + info!("GenMC: handling Mutex::try_lock()"); + let (genmc_curr_thread, addr, size) = get_mutex_call_infos()?; + + let result = { + let mut mc = genmc_ctx.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + pinned_mc.handleMutexTryLock(genmc_curr_thread.0, addr, size) + }; + if let Some(error) = result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + info!("GenMC: handling Mutex::try_lock: error: {msg:?}"); + throw_ub_format!("{msg}"); + } + info!("GenMC: Mutex::try_lock(): writing resulting bool is_lock_acquired ({}) to place: {dest:?}", result.is_lock_acquired); + + this.write_scalar(Scalar::from_bool(result.is_lock_acquired), dest)?; + // todo!("return whether lock was successful or not"); + } else if this.tcx.is_diagnostic_item(sym::sys_mutex_unlock, instance.def_id()) { + info!("GenMC: handling Mutex::unlock()"); + let (genmc_curr_thread, addr, size) = get_mutex_call_infos()?; + + let mut mc = genmc_ctx.handle.borrow_mut(); + let pinned_mc = mc.as_mut(); + let result = pinned_mc.handleMutexUnlock(genmc_curr_thread.0, addr, size); + if let Some(error) = result.error.as_ref() { + let msg = error.to_string_lossy().to_string(); + throw_ub_format!("{msg}"); + } + // NOTE: We don't write anything back to Miri's memory, the Mutex state is handled only by GenMC. + + // this.unblock_thread(, crate::BlockReason::Mutex)?; + } else { + return interp_ok(false); + }; + + this.return_to_block(ret)?; + + interp_ok(true) } /**** Scheduling functionality ****/ /// Ask for a scheduling decision. This should be called before every MIR instruction. /// - /// GenMC may realize that the execution got stuck, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). + /// GenMC may realize that the execution is blocked, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcBlockedExecution`). /// /// This is **not** an error by iself! Treat this as if the program ended normally: `handle_execution_end` should be called next, which will determine if were are any actual errors. - pub(crate) fn schedule_thread<'tcx>( - &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + fn genmc_schedule_thread( + &mut self, ) -> InterpResult<'tcx, ThreadId> { - assert!(!self.allow_data_races.get()); - todo!() + let this = self.eval_context_mut(); + loop { + let genmc_ctx = this.machine.data_race.as_genmc_ref().unwrap(); + let next_thread_id = genmc_ctx.schedule_thread(this)?; + + match this.machine.threads.threads_ref()[next_thread_id].get_state() { + ThreadState::Blocked { + reason: block_reason @ (BlockReason::Mutex | BlockReason::GenmcAssume), + .. + } => { + info!( + "GenMC: schedule returned thread {next_thread_id:?}, which is blocked, so we unblock it now." + ); + this.unblock_thread(next_thread_id, *block_reason)?; + + // In some cases, like waiting on a Mutex::lock, the thread might still be blocked here: + if this.machine.threads.threads_ref()[next_thread_id] + .get_state() + .is_blocked_on(crate::BlockReason::Mutex) + { + info!("GenMC: Unblocked thread is blocked on a Mutex again!"); + continue; + } + } + _ => {} + } + + return interp_ok(next_thread_id); + } } /**** Blocking instructions ****/ - pub(crate) fn handle_verifier_assume<'tcx>( - &self, - machine: &MiriMachine<'tcx>, - condition: bool, - ) -> InterpResult<'tcx, ()> { - if condition { interp_ok(()) } else { self.handle_user_block(machine) } + /// Handle an `assume` statement. This will tell GenMC to block the current thread if the `condition` is false. + /// Returns `true` if the current thread should be blocked in Miri too. + fn handle_genmc_verifier_assume( + &mut self, + condition: &OpTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let condition_bool = this.read_scalar(condition)?.to_bool()?; + info!("GenMC: handle_verifier_assume, condition: {condition:?} = {condition_bool}"); + if condition_bool { + return interp_ok(()); + } + let genmc_ctx = this.machine.data_race.as_genmc_ref().unwrap(); + genmc_ctx.handle_user_block(&this.machine)?; + let condition = condition.clone(); + this.block_thread( + BlockReason::GenmcAssume, + None, + callback!( + @capture<'tcx> { + condition: OpTy<'tcx>, + } + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); + + let condition = this.run_for_validation_ref(|this| this.read_scalar(&condition))?.to_bool()?; + assert!(condition); + + interp_ok(()) + } + ), + ); + interp_ok(()) } + } impl VisitProvenance for GenmcCtx { @@ -277,8 +1264,11 @@ impl VisitProvenance for GenmcCtx { } } -impl GenmcCtx { - fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { - todo!() +impl std::fmt::Debug for GenmcCtx { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GenmcCtx") + // .field("mc", &self.mc) + .field("thread_infos", &self.thread_infos) + .finish_non_exhaustive() } } diff --git a/src/concurrency/genmc/thread_info_manager.rs b/src/concurrency/genmc/thread_info_manager.rs new file mode 100644 index 0000000000..7f4ee682d6 --- /dev/null +++ b/src/concurrency/genmc/thread_info_manager.rs @@ -0,0 +1,95 @@ +use genmc_sys::{GENMC_MAIN_THREAD_ID, GenmcThreadId}; +use rustc_data_structures::fx::FxHashMap; + +use crate::ThreadId; + +#[derive(Debug)] +pub struct ThreadInfo { + pub miri_tid: ThreadId, + pub genmc_tid: GenmcThreadId, + // TODO GENMC: Do we need this? Only for the main thread? + pub user_code_finished: bool, +} + +impl ThreadInfo { + const MAIN_THREAD_INFO: Self = Self::new(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); + + #[must_use] + pub const fn new(miri_tid: ThreadId, genmc_tid: GenmcThreadId) -> Self { + Self { miri_tid, genmc_tid, user_code_finished: false } + } +} + +#[derive(Debug)] +pub struct ThreadInfoManager { + tid_map: FxHashMap, + thread_infos: Vec, +} + +impl Default for ThreadInfoManager { + fn default() -> Self { + Self::new() + } +} + +impl ThreadInfoManager { + #[must_use] + pub fn new() -> Self { + let mut tid_map = FxHashMap::default(); + tid_map.insert(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); + let thread_infos = vec![ThreadInfo::MAIN_THREAD_INFO]; + Self { tid_map, thread_infos } + } + + pub fn reset(&mut self) { + self.tid_map.clear(); + self.tid_map.insert(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); + self.thread_infos.clear(); + self.thread_infos.push(ThreadInfo::MAIN_THREAD_INFO); + } + + #[must_use] + #[allow(unused)] + pub fn thread_count(&self) -> usize { + self.thread_infos.len() + } + + pub fn add_thread(&mut self, thread_id: ThreadId) -> GenmcThreadId { + // NOTE: GenMC thread ids are integers incremented by one every time + let index = self.thread_infos.len(); + let genmc_tid = GenmcThreadId(index.try_into().unwrap()); + let thread_info = ThreadInfo::new(thread_id, genmc_tid); + // TODO GENMC: Document this in place where ThreadIds are created + assert!( + self.tid_map.insert(thread_id, genmc_tid).is_none(), + "Cannot reuse thread ids: thread id {thread_id:?} already inserted" + ); + self.thread_infos.push(thread_info); + + genmc_tid + } + + #[must_use] + pub fn get_info(&self, thread_id: ThreadId) -> &ThreadInfo { + let genmc_tid = *self.tid_map.get(&thread_id).unwrap(); + self.get_info_genmc(genmc_tid) + } + + #[must_use] + pub fn get_info_genmc(&self, genmc_tid: GenmcThreadId) -> &ThreadInfo { + let index: usize = genmc_tid.0.try_into().unwrap(); + &self.thread_infos[index] + } + + #[must_use] + pub fn get_info_mut(&mut self, thread_id: ThreadId) -> &mut ThreadInfo { + let genmc_tid = *self.tid_map.get(&thread_id).unwrap(); + self.get_info_mut_genmc(genmc_tid) + } + + #[must_use] + pub fn get_info_mut_genmc(&mut self, genmc_tid: GenmcThreadId) -> &mut ThreadInfo { + let index: usize = genmc_tid.0.try_into().unwrap(); + &mut self.thread_infos[index] + } +} diff --git a/src/concurrency/genmc/warnings.rs b/src/concurrency/genmc/warnings.rs new file mode 100644 index 0000000000..e8d3b2a922 --- /dev/null +++ b/src/concurrency/genmc/warnings.rs @@ -0,0 +1,66 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_middle::query::TyCtxtAt; +use rustc_span::Span; + +use crate::{AtomicReadOrd, AtomicRwOrd}; + +#[derive(Default)] +pub struct WarningsCache { + emitted_compare_exchange_weak: FxHashSet, + emitted_compare_exchange_failure_ordering: FxHashSet<(Span, AtomicReadOrd, AtomicReadOrd)>, +} + +impl WarningsCache { + /// Warn about unsupported spurious failures of `compare_exchange_weak`, once per span, returning `true` if the warning was printed. + pub fn warn_once_compare_exchange_weak<'tcx>(&mut self, tcx: &TyCtxtAt<'tcx>) -> bool { + if self.emitted_compare_exchange_weak.insert(tcx.span) { + tcx.dcx().span_warn(tcx.span, "GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)!"); + return true; + } + false + } + + /// Check if the given failure ordering is unsupported by GenMC. + /// Warning is printed only once per span and ordering combination. + /// Returns `true` if the warning was printed. + pub fn warn_once_rmw_failure_ordering<'tcx>( + &mut self, + tcx: &TyCtxtAt<'tcx>, + success_ordering: AtomicRwOrd, + failure_load_ordering: AtomicReadOrd, + ) -> bool { + let (success_load_ordering, _success_store_ordering) = + success_ordering.split_memory_orderings(); + let is_failure_ordering_weaker = match (success_load_ordering, failure_load_ordering) { + // Unsound: failure ordering is weaker than success ordering, but GenMC treats them as equally strong. + // Actual program execution might have behavior not modelled by GenMC: + (AtomicReadOrd::Acquire, AtomicReadOrd::Relaxed) + | (AtomicReadOrd::SeqCst, AtomicReadOrd::Relaxed) + | (AtomicReadOrd::SeqCst, AtomicReadOrd::Acquire) => true, + // Possible false positives: failure ordering is stronger than success ordering, but GenMC treats them as equally strong. + // We might explore executions that are not allowed by the program. + (AtomicReadOrd::Relaxed, AtomicReadOrd::Acquire) + | (AtomicReadOrd::Relaxed, AtomicReadOrd::SeqCst) + | (AtomicReadOrd::Acquire, AtomicReadOrd::SeqCst) => false, + // Correct: failure ordering is equally strong as success ordering: + (AtomicReadOrd::Relaxed, AtomicReadOrd::Relaxed) + | (AtomicReadOrd::Acquire, AtomicReadOrd::Acquire) + | (AtomicReadOrd::SeqCst, AtomicReadOrd::SeqCst) => return false, + }; + let key = (tcx.span, success_load_ordering, failure_load_ordering); + if self.emitted_compare_exchange_failure_ordering.insert(key) { + let error = if is_failure_ordering_weaker { + "miss bugs related to this memory access (possible unsoundness)!" + } else { + "incorrectly detect errors related to this memory access (possible false positives)." + }; + let msg = format!( + "GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering '{failure_load_ordering:?}' is treated like '{success_load_ordering:?}', which means that Miri might {error}", + ); + // FIXME(genmc): this doesn't print a span: + tcx.dcx().span_warn(tcx.span, msg); + return true; + } + false + } +} diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index c2ea8a00de..dee270abe0 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -12,5 +12,7 @@ pub mod weak_memory; mod genmc; pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler}; -pub use self::genmc::{GenmcConfig, GenmcCtx}; +pub use self::genmc::{ + EvalContextExt as GenmcEvalContextExt, GenmcConfig, GenmcCtx, miri_genmc, +}; pub use self::vector_clock::VClock; diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index 878afdf251..444ef143c0 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::Span; -use crate::concurrency::GlobalDataRaceHandler; +use crate::concurrency::{GenmcEvalContextExt as _, GlobalDataRaceHandler}; use crate::shims::tls; use crate::*; @@ -110,10 +110,13 @@ pub enum BlockReason { Eventfd, /// Blocked on unnamed_socket. UnnamedSocket, + /// Blocked on a GenMC `assume` statement (GenMC mode only). + GenmcAssume, } /// The state of a thread. -enum ThreadState<'tcx> { +// TODO GENMC: is this ok to be pub? +pub enum ThreadState<'tcx> { /// The thread is enabled and can be executed. Enabled, /// The thread is blocked on something. @@ -135,15 +138,16 @@ impl<'tcx> std::fmt::Debug for ThreadState<'tcx> { } impl<'tcx> ThreadState<'tcx> { - fn is_enabled(&self) -> bool { + // TODO GENMC: is it ok if these are pub? + pub fn is_enabled(&self) -> bool { matches!(self, ThreadState::Enabled) } - fn is_terminated(&self) -> bool { + pub fn is_terminated(&self) -> bool { matches!(self, ThreadState::Terminated) } - fn is_blocked_on(&self, reason: BlockReason) -> bool { + pub fn is_blocked_on(&self, reason: BlockReason) -> bool { matches!(*self, ThreadState::Blocked { reason: actual_reason, .. } if actual_reason == reason) } } @@ -209,6 +213,11 @@ impl<'tcx> Thread<'tcx> { self.thread_name.as_deref() } + pub fn get_state(&self) -> &ThreadState<'tcx> { + // TODO GENMC: should this implementation detail be exposed? + &self.state + } + /// Get the name of the current thread for display purposes; will include thread ID if not set. fn thread_display_name(&self, id: ThreadId) -> String { if let Some(ref thread_name) = self.thread_name { @@ -343,8 +352,9 @@ impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> { } /// The moment in time when a blocked thread should be woken up. +// TODO GENMC: is this ok to be pub? #[derive(Debug)] -enum Timeout { +pub enum Timeout { Monotonic(Instant), RealTime(SystemTime), } @@ -491,6 +501,11 @@ impl<'tcx> ThreadManager<'tcx> { &mut self.threads[self.active_thread].stack } + /// TODO GENMC: this function can probably be removed once the GenmcCtx code is finished: + pub fn get_thread_stack(&self, id: ThreadId) -> &[Frame<'tcx, Provenance, FrameExtra<'tcx>>] { + &self.threads[id].stack + } + pub fn all_stacks( &self, ) -> impl Iterator>])> { @@ -520,11 +535,21 @@ impl<'tcx> ThreadManager<'tcx> { self.active_thread } + pub fn threads_ref(&self) -> &IndexVec> { + // TODO GENMC: should this implementation detail be exposed? + &self.threads + } + /// Get the total number of threads that were ever spawn by this program. pub fn get_total_thread_count(&self) -> usize { self.threads.len() } + /// Get the total of threads that are currently enabled, i.e., could continue executing. + pub fn get_enabled_thread_count(&self) -> usize { + self.threads.iter().filter(|t| t.state.is_enabled()).count() + } + /// Get the total of threads that are currently live, i.e., not yet terminated. /// (They might be blocked.) pub fn get_live_thread_count(&self) -> usize { @@ -568,6 +593,8 @@ impl<'tcx> ThreadManager<'tcx> { fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> InterpResult<'tcx> { trace!("detaching {:?}", id); + tracing::info!("GenMC: TODO GENMC: does GenMC need special handling for detached threads?"); + let is_ub = if allow_terminated_joined && self.threads[id].state.is_terminated() { // "Detached" in particular means "not yet joined". Redundant detaching is still UB. self.threads[id].join_status == ThreadJoinStatus::Detached @@ -676,13 +703,6 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); - // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. - // FIXME(GenMC): Thread-local destructors *are* user code, so this is odd. Also now that we - // support pre-main constructors, it can get called there as well. - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let thread_id = this.active_thread(); - genmc_ctx.handle_thread_stack_empty(thread_id); - } let mut callback = this .active_thread_mut() .on_stack_empty @@ -690,6 +710,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { .expect("`on_stack_empty` not set up, or already running"); let res = callback(this)?; this.active_thread_mut().on_stack_empty = Some(callback); + // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let thread_id = this.active_thread(); + genmc_ctx.handle_thread_stack_empty(&this.machine.threads, thread_id); + } interp_ok(res) } @@ -703,9 +728,10 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// If GenMC mode is active, the scheduling is instead handled by GenMC. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - // In GenMC mode, we let GenMC do the scheduling - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let next_thread_id = genmc_ctx.schedule_thread(this)?; + + // In GenMC mode, we let GenMC do the scheduling. + if this.machine.data_race.as_genmc_ref().is_some() { + let next_thread_id = this.genmc_schedule_thread()?; let thread_manager = &mut this.machine.threads; thread_manager.active_thread = next_thread_id; @@ -715,7 +741,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { return interp_ok(SchedulingAction::ExecuteStep); } - // We are not in GenMC mode, so we control the schedule + // We are not in GenMC mode, so we control the scheduling. let thread_manager = &mut this.machine.threads; let clock = &this.machine.monotonic_clock; let rng = this.machine.rng.get_mut(); @@ -863,7 +889,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { GlobalDataRaceHandler::Vclocks(data_race) => data_race.thread_created(&this.machine.threads, new_thread_id, current_span), GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_thread_create(&this.machine.threads, new_thread_id)?, + genmc_ctx.handle_thread_create( + &this.machine.threads, + start_routine, + &func_arg, + new_thread_id, + )?, } // Write the current thread-id, switch to the next thread later // to treat this write operation as occurring on the current thread. @@ -916,12 +947,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread = this.active_thread_mut(); assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated"); thread.state = ThreadState::Terminated; - match &mut this.machine.data_race { - GlobalDataRaceHandler::None => {} - GlobalDataRaceHandler::Vclocks(data_race) => - data_race.thread_terminated(&this.machine.threads), - GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_thread_finish(&this.machine.threads)?, + + // TODO GENMC (QUESTION): Can we move this down to where the GenmcCtx is? + if let Some(data_race) = this.machine.data_race.as_vclocks_mut() { + data_race.thread_terminated(&this.machine.threads); } // Deallocate TLS. let gone_thread = this.active_thread(); @@ -953,6 +982,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } + + // Inform GenMC that the thread finished. + // This needs to happen once all accesses to the thread are done, including freeing any TLS statics. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + genmc_ctx.handle_thread_finish(&this.machine.threads); + } + // Unblock joining threads. let unblock_reason = BlockReason::Join(gone_thread); let threads = &this.machine.threads.threads; @@ -1076,6 +1112,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "{:?} blocked on {:?} when trying to join", thread_mgr.active_thread, joined_thread_id ); + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + info!("GenMC: informing GenMC about blocked thread join."); + genmc_ctx.handle_thread_join(thread_mgr.active_thread, joined_thread_id)?; + } + // The joined thread is still running, we need to wait for it. // Once we get unblocked, perform the appropriate synchronization and write the return value. let dest = return_dest.clone(); @@ -1206,6 +1247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); + if !this.machine.threads.fixed_scheduling && this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) { @@ -1236,6 +1278,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { SchedulingAction::ExecuteTimeoutCallback => { this.run_timeout_callback()?; } + // TODO GENMC: do we need to sleep in GenMC Mode? SchedulingAction::Sleep(duration) => { this.machine.monotonic_clock.sleep(duration); } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a752ef7e45..ef0332d312 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -175,6 +175,7 @@ impl StoreBufferAlloc { /// after all the prior atomic writes so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. pub fn memory_accessed(&self, range: AllocRange, global: &DataRaceState) { + // TODO GENMC: what needs to be done here for GenMC (if anything at all)? if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); @@ -460,6 +461,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; + // TODO GENMC: what needs to be done here for GenMC (if anything at all)? if let ( crate::AllocExtra { data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), @@ -542,6 +544,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?; + // TODO GENMC: what needs to be done here for GenMC (if anything at all)? if let ( crate::AllocExtra { data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 9ecbd31c5b..8a36fd4356 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -31,8 +31,8 @@ pub enum TerminationInfo { }, Int2PtrWithStrictProvenance, Deadlock, - /// In GenMC mode, an execution can get stuck in certain cases. This is not an error. - GenmcStuckExecution, + /// In GenMC mode, an execution can get blocked in certain cases. This is not an error. + GenmcBlockedExecution, MultipleSymbolDefinitions { link_name: Symbol, first: SpanData, @@ -77,7 +77,7 @@ impl fmt::Display for TerminationInfo { StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), TreeBorrowsUb { title, .. } => write!(f, "{title}"), Deadlock => write!(f, "the evaluated program deadlocked"), - GenmcStuckExecution => write!(f, "GenMC determined that the execution got stuck"), + GenmcBlockedExecution => write!(f, "GenMC determined that the execution is blocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => @@ -243,11 +243,12 @@ pub fn report_error<'tcx>( labels.push(format!("this thread got stuck here")); None } - GenmcStuckExecution => { + GenmcBlockedExecution => { // This case should only happen in GenMC mode. We treat it like a normal program exit. + // Leak checks should not be performed, since some threads might not have run to completion. assert!(ecx.machine.data_race.as_genmc_ref().is_some()); - tracing::info!("GenMC: found stuck execution"); - return Some((0, true)); + tracing::info!("GenMC: found blocked execution"); + return Some((0, false)); } MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; diff --git a/src/eval.rs b/src/eval.rs index 3c80e60b77..1c64e541f0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -261,9 +261,10 @@ impl<'tcx> MainThreadState<'tcx> { match state.on_stack_empty(this)? { Poll::Pending => {} // just keep going Poll::Ready(()) => { - if this.machine.data_race.as_genmc_ref().is_some() { + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { // In GenMC mode, we don't yield at the end of the main thread. // Instead, the `GenmcCtx` will ensure that unfinished threads get a chance to run at this point. + genmc_ctx.handle_main_thread_stack_empty(&this.machine.threads); *self = Done; } else { // Give background threads a chance to finish by yielding the main thread a diff --git a/src/lib.rs b/src/lib.rs index ae70257653..fe5fa6eb19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ pub use crate::concurrency::thread::{ BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; -pub use crate::concurrency::{GenmcConfig, GenmcCtx}; +pub use crate::concurrency::{GenmcConfig, GenmcCtx, miri_genmc}; pub use crate::data_structures::dedup_range_map::DedupRangeMap; pub use crate::data_structures::mono_hash_map::MonoHashMap; pub use crate::diagnostics::{ diff --git a/src/machine.rs b/src/machine.rs index ce33c870b4..3ba7028970 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -31,7 +31,9 @@ use rustc_target::callconv::FnAbi; use crate::alloc_addresses::EvalContextExt; use crate::concurrency::cpu_affinity::{self, CpuAffinityMask}; use crate::concurrency::data_race::{self, NaReadType, NaWriteType}; -use crate::concurrency::{AllocDataRaceHandler, GenmcCtx, GlobalDataRaceHandler, weak_memory}; +use crate::concurrency::{ + AllocDataRaceHandler, GenmcCtx, GenmcEvalContextExt as _, GlobalDataRaceHandler, weak_memory, +}; use crate::*; /// First real-time signal. @@ -1141,6 +1143,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); } + if ecx.machine.data_race.as_genmc_ref().is_some() + && ecx.check_genmc_intercept_function(instance, args, dest, ret)? + { + return interp_ok(None); + } + // Otherwise, load the MIR. interp_ok(Some((ecx.load_mir(instance.def, None)?, instance))) } @@ -1293,6 +1301,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { size: Size, align: Align, ) -> InterpResult<'tcx, Self::AllocExtra> { + info!( + "GenMC: TODO GENMC: init_local_allocation: id: {id:?}, kind: {kind:?}, size: {size:?}, align: {align:?}" + ); + assert!(kind != MiriMemoryKind::Global.into()); MiriMachine::init_allocation(ecx, id, kind, size, align) } @@ -1384,6 +1396,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { alloc: &'b Allocation, ) -> InterpResult<'tcx, Cow<'b, Allocation>> { + info!( + "GenMC: adjust_global_allocation (TODO GENMC): id: {id:?} ==> Maybe tell GenMC about initial value here?" + ); + let alloc = alloc.adjust_from_tcx( &ecx.tcx, |bytes, align| ecx.get_global_alloc_bytes(id, bytes, align), @@ -1445,7 +1461,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { match &machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Genmc(genmc_ctx) => { - genmc_ctx.memory_store(machine, ptr.addr(), range.size)?; + // TODO GENMC(mixed atomic-non-atomic): is this needed? + // let old_val = this.run_for_validation_ref(|this| this.read_scalar(dest)).discard_err(); + genmc_ctx.memory_store(machine, ptr.addr(), range.size /* , old_val */)?; } GlobalDataRaceHandler::Vclocks(_global_state) => { let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = @@ -1482,7 +1500,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { match &machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?, + genmc_ctx.handle_dealloc(machine, alloc_id, ptr.addr(), size, align, kind)?, GlobalDataRaceHandler::Vclocks(_global_state) => { let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap(); data_race.write( @@ -1573,6 +1591,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let borrow_tracker = ecx.machine.borrow_tracker.as_ref(); + // TODO GENMC: what needs to be done here for GenMC (if anything at all)? let extra = FrameExtra { borrow_tracker: borrow_tracker.map(|bt| bt.borrow_mut().new_frame()), catch_unwind: None, @@ -1694,6 +1713,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>, local: mir::Local, ) -> InterpResult<'tcx> { + // TODO GENMC: does GenMC care about local reads/writes? if let Some(data_race) = &frame.extra.data_race { data_race.local_read(local, &ecx.machine); } @@ -1705,6 +1725,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { local: mir::Local, storage_live: bool, ) -> InterpResult<'tcx> { + // TODO GENMC: does GenMC care about local reads/writes? if let Some(data_race) = &ecx.frame().extra.data_race { data_race.local_write(local, storage_live, &ecx.machine); } @@ -1734,6 +1755,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine, ); } + // TODO GENMC: how to handle this (if at all)? interp_ok(()) } @@ -1752,6 +1774,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { Option>, ) -> InterpResult<'tcx, OpTy<'tcx>>, { + info!("GenMC: TODO GENMC: evaluating MIR constant: {val:?}"); let frame = ecx.active_thread_stack().last().unwrap(); let mut cache = ecx.machine.const_cache.borrow_mut(); match cache.entry((val, frame.extra.salt)) { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 94cda57658..2452bdfa81 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -17,6 +17,7 @@ use rustc_target::callconv::FnAbi; use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; +use crate::concurrency::GenmcEvalContextExt as _; use crate::*; /// Type of dynamic symbols (for `dlsym` et al) @@ -435,6 +436,21 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } + /*** \/ GENMC VERIFIER CALLS \/ ****/ + "miri_genmc_verifier_assume" => { + let [condition] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; + if this.machine.data_race.as_genmc_ref().is_some() { + this.handle_genmc_verifier_assume(condition)?; + } else { + tracing::warn!( + "GenMC: function `miri_genmc_verifier_assume` used, but GenMC mode is not active, skip ..." + ); + } + } + + // TODO GENMC: add other genmc functions + + /*** /\ GENMC VERIFIER CALLS /\ ****/ // Aborting the process. "exit" => { let [code] = this.check_shim(abi, CanonAbi::C, link_name, args)?; diff --git a/tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs b/tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs new file mode 100644 index 0000000000..ef06bbfd0c --- /dev/null +++ b/tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs @@ -0,0 +1,57 @@ +//@compile-flags: -Zmiri-genmc + +// NOTE: Disabled due to incomplete uninitialized memory support in Miri-GenMC mode. + +// Tests showing weak memory behaviours are exhibited. All tests +// return true when the desired behaviour is seen. +// This is scheduler and pseudo-RNG dependent, so each test is +// run multiple times until one try returns true. +// Spurious failure is possible, if you are really unlucky with +// the RNG and always read the latest value from the store buffer. + +#![no_main] + +#[path = "../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::mem::MaybeUninit; +use std::sync::atomic::*; + +use crate::utils_dep::*; + +#[allow(dead_code)] +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static mut F: MaybeUninit = MaybeUninit::uninit(); + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + unsafe { + let x = AtomicUsize::from_ptr(&raw mut F as *mut usize); + x.store(1, Ordering::Relaxed); + std::ptr::null_mut() + } +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + unsafe { + let x = AtomicUsize::from_ptr(&raw mut F as *mut usize); + x.load(Ordering::Relaxed); //~ERROR: using uninitialized data + std::ptr::null_mut() + } +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // Unlike with the non-GenMC version of this test, we should only need 1 iteration to detect the bug: + unsafe { + let ids = create_pthreads_no_params([thread_1, thread_2]); + join_pthreads(ids); + } + + 0 +} diff --git a/tests/genmc/fail/simple/2w2w_acq_rel.rs b/tests/genmc/fail/simple/2w2w_acq_rel.rs new file mode 100644 index 0000000000..586bdd0428 --- /dev/null +++ b/tests/genmc/fail/simple/2w2w_acq_rel.rs @@ -0,0 +1,44 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use libc::{self, pthread_attr_t, pthread_t}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +const LOAD_ORD: Ordering = Ordering::Acquire; +const STORE_ORD: Ordering = Ordering::Release; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + let ret_create = unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }; + assert!(ret_create == 0); + + X.store(1, STORE_ORD); + Y.store(2, STORE_ORD); + + let ret_join = unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }; + assert!(ret_join == 0); + + let x = X.load(LOAD_ORD); + let y = Y.load(LOAD_ORD); + if x == 1 && y == 1 { + unsafe { std::hint::unreachable_unchecked() }; //~ ERROR: entering unreachable code + } + 0 +} + +extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { + Y.store(1, STORE_ORD); + X.store(2, STORE_ORD); + std::ptr::null_mut() +} diff --git a/tests/genmc/fail/simple/2w2w_acq_rel.stderr b/tests/genmc/fail/simple/2w2w_acq_rel.stderr new file mode 100644 index 0000000000..c05a405cfe --- /dev/null +++ b/tests/genmc/fail/simple/2w2w_acq_rel.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/2w2w_acq_rel.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_acq_rel.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/genmc/fail/simple/2w2w_relaxed.rs b/tests/genmc/fail/simple/2w2w_relaxed.rs new file mode 100644 index 0000000000..d01780e375 --- /dev/null +++ b/tests/genmc/fail/simple/2w2w_relaxed.rs @@ -0,0 +1,44 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use libc::{self, pthread_attr_t, pthread_t}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +const LOAD_ORD: Ordering = Ordering::Relaxed; +const STORE_ORD: Ordering = Ordering::Relaxed; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + let ret_create = unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }; + assert!(ret_create == 0); + + X.store(1, STORE_ORD); + Y.store(2, STORE_ORD); + + let ret_join = unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }; + assert!(ret_join == 0); + + let x = X.load(LOAD_ORD); + let y = Y.load(LOAD_ORD); + if x == 1 && y == 1 { + unsafe { std::hint::unreachable_unchecked() }; //~ ERROR: entering unreachable code + } + 0 +} + +extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { + Y.store(1, STORE_ORD); + X.store(2, STORE_ORD); + std::ptr::null_mut() +} diff --git a/tests/genmc/fail/simple/2w2w_relaxed.stderr b/tests/genmc/fail/simple/2w2w_relaxed.stderr new file mode 100644 index 0000000000..93ddf7de53 --- /dev/null +++ b/tests/genmc/fail/simple/2w2w_relaxed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/2w2w_relaxed.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_relaxed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs b/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs new file mode 100644 index 0000000000..c244f5bf81 --- /dev/null +++ b/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs @@ -0,0 +1,20 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(1234); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // TODO GENMC: make this a "pass" test + if 1234 != unsafe { *X.as_ptr() } { + unsafe { std::hint::unreachable_unchecked() }; + } + if 1234 == X.load(Ordering::SeqCst) { + unsafe { std::hint::unreachable_unchecked() }; //~ ERROR: entering unreachable code + } + + 0 +} diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr b/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr new file mode 100644 index 0000000000..ec779aa7c4 --- /dev/null +++ b/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `miri_start` at tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr new file mode 100644 index 0000000000..28a8b74c86 --- /dev/null +++ b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC + | +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside `read_relaxed` at tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr new file mode 100644 index 0000000000..28a8b74c86 --- /dev/null +++ b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC + | +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside `read_relaxed` at tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs new file mode 100644 index 0000000000..0ebac090ad --- /dev/null +++ b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs @@ -0,0 +1,58 @@ +//@compile-flags: -Zmiri-genmc +//@revisions: return1234 return42 + +#![no_main] + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use libc::{self, pthread_attr_t, pthread_t}; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let mut t0: pthread_t = 0; + let mut t1: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + + let mut x: AtomicU64 = AtomicU64::new(1); + *x.get_mut() = 42; + // x.store(42, STORE_ORD); + + let value: *mut c_void = x.as_ptr() as *mut c_void; + + assert!(0 == unsafe { libc::pthread_create(&raw mut t0, attr, read_relaxed, value) }); + assert!(0 == unsafe { libc::pthread_create(&raw mut t1, attr, write_relaxed, value) }); + + assert!(0 == unsafe { libc::pthread_join(t0, std::ptr::null_mut()) }); + assert!(0 == unsafe { libc::pthread_join(t1, std::ptr::null_mut()) }); + + 0 +} + +extern "C" fn read_relaxed(value: *mut c_void) -> *mut c_void { + unsafe { + let x = (value as *const AtomicU64).as_ref().unwrap(); + let val = x.load(Ordering::Relaxed); + + let mut flag = false; + if cfg!(return1234) && 1234 == val { + flag = true; + } + if cfg!(return42) && 42 == val { + flag = true; + } + if flag { + std::hint::unreachable_unchecked(); //~ ERROR: entering unreachable code + } + std::ptr::null_mut() + } +} + +extern "C" fn write_relaxed(value: *mut c_void) -> *mut c_void { + unsafe { + let x = (value as *const AtomicU64).as_ref().unwrap(); + x.store(1234, Ordering::Relaxed); + std::ptr::null_mut() + } +} diff --git a/tests/genmc/pass/basics/mutex/TODO_mutex_get_mut.rs.txt b/tests/genmc/pass/basics/mutex/TODO_mutex_get_mut.rs.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.c b/tests/genmc/pass/basics/mutex/mutex_simple.c new file mode 100644 index 0000000000..eb9c87aa82 --- /dev/null +++ b/tests/genmc/pass/basics/mutex/mutex_simple.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include + +#define REPS 1 + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static uint64_t data[32]; + +void* thread_1(void* arg) { + for (uint64_t i = 0; i < REPS; i++) { + pthread_mutex_lock(&lock); + data[0] += 2; + pthread_mutex_unlock(&lock); + } + return NULL; +} + +void* thread_2(void* arg) { + for (uint64_t i = 0; i < REPS; i++) { + pthread_mutex_lock(&lock); + data[0] += 4; + pthread_mutex_unlock(&lock); + } + return NULL; +} + +int main(int argc, char** argv) { + // Initialize data + for (int i = 0; i < 32; i++) { + data[i] = 1234; + } + + pthread_mutex_lock(&lock); + for (int i = 0; i < 32; i++) { + assert(data[i] == 1234); + } + data[0] = 0; + data[1] = 10; + assert(data[0] == 0 && data[1] == 10); + pthread_mutex_unlock(&lock); + + // Thread order: can be changed for different test orders +#ifdef ORDER21 + void* (*thread_order[2])(void*) = {thread_2, thread_1}; +#else + void* (*thread_order[2])(void*) = {thread_1, thread_2}; +#endif + + pthread_t ids[2]; + for (int i = 0; i < 2; i++) { + int ret = pthread_create(&ids[i], NULL, thread_order[i], NULL); + assert(ret == 0); + } + + for (int i = 0; i < 2; i++) { + int ret = pthread_join(ids[i], NULL); + assert(ret == 0); + } + + pthread_mutex_lock(&lock); + // assert(data[0] == REPS * 6); // Not checked, but can be enabled + assert(data[1] == 10); + for (int i = 2; i < 32; i++) { + assert(data[i] == 1234); + } + pthread_mutex_unlock(&lock); + + return 0; +} diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr new file mode 100644 index 0000000000..edecd38278 --- /dev/null +++ b/tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr new file mode 100644 index 0000000000..e4151d346e --- /dev/null +++ b/tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr new file mode 100644 index 0000000000..edecd38278 --- /dev/null +++ b/tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr new file mode 100644 index 0000000000..e4151d346e --- /dev/null +++ b/tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.rs b/tests/genmc/pass/basics/mutex/mutex_simple.rs new file mode 100644 index 0000000000..1c91126316 --- /dev/null +++ b/tests/genmc/pass/basics/mutex/mutex_simple.rs @@ -0,0 +1,73 @@ +//@compile-flags: -Zmiri-genmc +//@revisions: order12reps1 order21reps1 order12reps2 order21reps2 + +#![no_main] +#![feature(abort_unwind)] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::Mutex; + +use crate::utils_dep::*; + +#[cfg(not(any(order12reps2, order21reps2)))] +const REPS: u64 = 1; +#[cfg(any(order12reps2, order21reps2))] +const REPS: u64 = 2; + +static LOCK: Mutex<[u64; 32]> = Mutex::new([1234; 32]); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + std::panic::abort_unwind(main_); + 0 +} + +fn main_() { + let mut guard = LOCK.lock().unwrap(); + for &v in guard.iter() { + assert!(v == 1234); // Check that mutex values are initialized correctly + } + guard[0] = 0; + guard[1] = 10; + assert!(guard[0] == 0 && guard[1] == 10); // Check if changes are accepted + + assert!(LOCK.try_lock().is_err()); // Trying to lock should fail if the lock is already held + + drop(guard); // Dropping the guard should unlock the mutex correctly. + { + assert!(LOCK.try_lock().is_ok()); // Trying to lock now should *not* fail since the lock is not held. + } + + // Thread spawning order should not matter for the result + let thread_order = if cfg!(order21) { [thread_2, thread_1] } else { [thread_1, thread_2] }; + // let thread_order = [thread_1 as extern "C" fn(*mut libc::c_void) -> *mut libc::c_void]; + let ids = unsafe { create_pthreads_no_params(thread_order) }; + unsafe { join_pthreads(ids) }; + + let guard = LOCK.lock().unwrap(); + assert!(guard[0] == REPS * 6); // Due to locking, no weird values should be here + assert!(guard[1] == 10); // Rest should be unchanged + for &v in guard.iter().skip(2) { + assert!(v == 1234); + } + drop(guard); +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + for _ in 0..REPS { + let mut guard = LOCK.lock().unwrap(); + guard[0] += 2; + } + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + for _ in 0..REPS { + let mut guard = LOCK.lock().unwrap(); + guard[0] += 4; + } + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.rs b/tests/genmc/pass/basics/rmw/rmw_edge_cases.rs new file mode 100644 index 0000000000..4bb98caf03 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.rs @@ -0,0 +1,89 @@ +//@compile-flags: -Zmiri-genmc +//@revisions: u8_ u16_ u32_ u64_ usize_ i8_ i16_ i32_ i64_ isize_ + +// FIXME(genmc): ensure that 64 bit tests don't run on platforms without 64 bit atomics +// FIXME(genmc): add 128 bit tests for platforms that support it, once GenMC gets 128 bit atomic support + +// This test check for correct handling of some edge cases with atomic read-modify-write operations for all integer sizes. +// Atomic max and min should return the previous value, and store the result in the atomic. +// Atomic addition and subtraction should have wrapping semantics. + +#![no_main] + +#[cfg(u8_)] +type Int = u8; +#[cfg(u8_)] +type AtomicInt = AtomicU8; + +#[cfg(u16_)] +type Int = u16; +#[cfg(u16_)] +type AtomicInt = AtomicU16; + +#[cfg(u32_)] +type Int = u32; +#[cfg(u32_)] +type AtomicInt = AtomicU32; + +#[cfg(u64_)] +type Int = u64; +#[cfg(u64_)] +type AtomicInt = AtomicU64; + +#[cfg(usize_)] +type Int = usize; +#[cfg(usize_)] +type AtomicInt = AtomicUsize; + + +#[cfg(i8_)] +type Int = i8; +#[cfg(i8_)] +type AtomicInt = AtomicI8; + +#[cfg(i16_)] +type Int = i16; +#[cfg(i16_)] +type AtomicInt = AtomicI16; + +#[cfg(i32_)] +type Int = i32; +#[cfg(i32_)] +type AtomicInt = AtomicI32; + +#[cfg(i64_)] +type Int = i64; +#[cfg(i64_)] +type AtomicInt = AtomicI64; + +#[cfg(isize_)] +type Int = isize; +#[cfg(isize_)] +type AtomicInt = AtomicIsize; + +use std::sync::atomic::*; + +const ORD: Ordering = Ordering::SeqCst; + +fn assert_eq(x: T, y: T) { + if x != y { + std::process::abort(); + } +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let x = AtomicInt::new(123); + assert_eq(123, x.fetch_max(0, ORD)); // `max` keeps existing value + assert_eq(123, x.fetch_max(Int::MAX, ORD)); // `max` stores the new value + assert_eq(Int::MAX, x.fetch_add(10, ORD)); // `fetch_add` should be wrapping + assert_eq(Int::MAX.wrapping_add(10), x.load(ORD)); + + x.store(42, ORD); + assert_eq(42, x.fetch_min(Int::MAX, ORD)); // `max` keeps existing value + assert_eq(42, x.fetch_min(Int::MIN, ORD)); // `max` stores the new value + assert_eq(Int::MIN, x.fetch_sub(10, ORD)); // `fetch_sub` should be wrapping + assert_eq(Int::MIN.wrapping_sub(10), x.load(ORD)); + + 0 +} diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_simple.rs b/tests/genmc/pass/basics/rmw/rmw_simple.rs new file mode 100644 index 0000000000..2f72ea2c4d --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_simple.rs @@ -0,0 +1,29 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::sync::atomic::*; + +static VALUE: AtomicUsize = AtomicUsize::new(0); + +const ORD: Ordering = Ordering::SeqCst; + +fn assert_eq(x: usize, y: usize) { + if x != y { + std::process::abort(); + } +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + VALUE.store(1, ORD); + + assert_eq(1, VALUE.fetch_add(7, ORD)); + assert_eq(8, VALUE.fetch_sub(2, ORD)); + assert_eq(6, VALUE.fetch_max(16, ORD)); + assert_eq(16, VALUE.fetch_min(4, ORD)); + assert_eq(4, VALUE.swap(42, ORD)); + + assert_eq(42, VALUE.load(ORD)); + 0 +} diff --git a/tests/genmc/pass/basics/rmw/rmw_simple.stderr b/tests/genmc/pass/basics/rmw/rmw_simple.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/basics/rmw/rmw_simple.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/data-structures/ms_queue_dynamic.rs b/tests/genmc/pass/data-structures/ms_queue_dynamic.rs new file mode 100644 index 0000000000..a30c3957df --- /dev/null +++ b/tests/genmc/pass/data-structures/ms_queue_dynamic.rs @@ -0,0 +1,224 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +// TODO GENMC: maybe use `-Zmiri-genmc-symmetry-reduction`? +// TODO GENMC: investigate why `-Zmiri-ignore-leaks ` is required + +#![no_main] +#![allow(static_mut_refs)] +#![allow(unused)] + +use std::alloc::{Layout, alloc, dealloc}; +use std::ffi::c_void; +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicPtr, AtomicU64}; + +use libc::{self, pthread_attr_t, pthread_t}; + +const MAX_THREADS: usize = 32; + +const POISON_IDX: u64 = 0xAAAABBBBBBBBAAAA; + +static mut QUEUE: MyStack = MyStack::new(); +static mut PARAMS: [u64; MAX_THREADS] = [POISON_IDX; MAX_THREADS]; +static mut INPUT: [u64; MAX_THREADS] = [POISON_IDX; MAX_THREADS]; +static mut OUTPUT: [Option; MAX_THREADS] = [None; MAX_THREADS]; +static mut THREADS: [pthread_t; MAX_THREADS] = [0; MAX_THREADS]; + +#[repr(C)] +struct Node { + value: u64, + next: AtomicPtr, +} + +struct MyStack { + head: AtomicPtr, + tail: AtomicPtr, +} + +impl Node { + pub unsafe fn new_alloc() -> *mut Self { + alloc(Layout::new::()) as *mut Self + } + + pub unsafe fn free(node: *mut Self) { + dealloc(node as *mut u8, Layout::new::()) + } + + pub unsafe fn reclaim(_node: *mut Self) { + // __VERIFIER_hp_retire(node); + } +} + +impl MyStack { + pub const fn new() -> Self { + let head = AtomicPtr::new(std::ptr::null_mut()); + let tail = AtomicPtr::new(std::ptr::null_mut()); + Self { head, tail } + } + + pub unsafe fn init_queue(&mut self, _num_threads: usize) { + /* initialize queue */ + let mut dummy = Node::new_alloc(); + + (*dummy).next = AtomicPtr::new(std::ptr::null_mut()); + self.head = AtomicPtr::new(dummy); + self.tail = AtomicPtr::new(dummy); + } + + pub unsafe fn clear_queue(&mut self, _num_threads: usize) { + let mut next; + let mut head = *self.head.get_mut(); + while !head.is_null() { + next = *(*head).next.get_mut(); + Node::free(head); + head = next; + } + } + + pub unsafe fn enqueue(&self, value: u64) { + let mut tail; + let node = Node::new_alloc(); + (*node).value = value; + (*node).next = AtomicPtr::new(std::ptr::null_mut()); + + loop { + tail = self.tail.load(Acquire); + let next = (*tail).next.load(Acquire); + if tail != self.tail.load(Acquire) { + continue; + } + + if next.is_null() { + // TODO GENMC: what if anything has to be done for `__VERIFIER_final_CAS`? + if (*tail).next.compare_exchange(next, node, Release, Relaxed).is_ok() { + break; + } + } else { + // TODO GENMC: what if anything has to be done for `__VERIFIER_helping_CAS`? + let _ = self.tail.compare_exchange(tail, next, Release, Relaxed); + } + } + + // TODO GENMC: what if anything has to be done for `__VERIFIER_helped_CAS`? + let _ = self.tail.compare_exchange(tail, node, Release, Relaxed); + } + + pub unsafe fn dequeue(&self) -> Option { + loop { + let head = self.head.load(Acquire); + let tail = self.tail.load(Acquire); + + let next_ref = &(*head).next; + let next = next_ref.load(Acquire); + if self.head.load(Acquire) != head { + continue; + } + if head == tail { + if next.is_null() { + return None; + } + let _ = self.tail.compare_exchange(tail, next, Release, Relaxed); + } else { + let ret_val = (*next).value; + if self.head.compare_exchange(head, next, Release, Relaxed).is_ok() { + // reclaim(head); + // __VERIFIER_hp_free(hp_head); + // __VERIFIER_hp_free(hp_next); + return Some(ret_val); + } + } + } + } +} + +extern "C" fn thread_w(value: *mut c_void) -> *mut c_void { + unsafe { + let pid = *(value as *mut u64); + + INPUT[pid as usize] = pid * 10; + QUEUE.enqueue(INPUT[pid as usize]); + + std::ptr::null_mut() + } +} + +extern "C" fn thread_r(value: *mut c_void) -> *mut c_void { + unsafe { + let pid = *(value as *mut u64); + + OUTPUT[pid as usize] = QUEUE.dequeue(); + + std::ptr::null_mut() + } +} + +extern "C" fn thread_rw(value: *mut c_void) -> *mut c_void { + unsafe { + let pid = *(value as *mut u64); + + INPUT[pid as usize] = pid * 10; + QUEUE.enqueue(INPUT[pid as usize]); + + OUTPUT[pid as usize] = QUEUE.dequeue(); + + std::ptr::null_mut() + } +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let attr: *const pthread_attr_t = std::ptr::null(); + + // TODO GENMC (TESTS): make different tests: + let readers = 0; + let writers = 0; + let rdwr = 2; + + let num_threads = readers + writers + rdwr; + + if num_threads > MAX_THREADS { + std::process::abort(); + } + + let mut i = 0; + unsafe { + MyStack::init_queue(&mut QUEUE, num_threads); + + for j in 0..num_threads { + PARAMS[j] = j as u64; + } + + /* Spawn threads */ + for _ in 0..writers { + let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; + if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_w, value) { + std::process::abort(); + } + i += 1; + } + for _ in 0..readers { + let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; + if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_r, value) { + std::process::abort(); + } + i += 1; + } + for _ in 0..rdwr { + let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; + if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_rw, value) { + std::process::abort(); + } + i += 1; + } + + for i in 0..num_threads { + if 0 != libc::pthread_join(THREADS[i], std::ptr::null_mut()) { + std::process::abort(); + } + } + + MyStack::clear_queue(&mut QUEUE, num_threads); + } + + 0 +} diff --git a/tests/genmc/pass/data-structures/ms_queue_dynamic.stderr b/tests/genmc/pass/data-structures/ms_queue_dynamic.stderr new file mode 100644 index 0000000000..2ed05b58e8 --- /dev/null +++ b/tests/genmc/pass/data-structures/ms_queue_dynamic.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 222 diff --git a/tests/genmc/pass/data-structures/treiber_stack_dynamic.rs b/tests/genmc/pass/data-structures/treiber_stack_dynamic.rs new file mode 100644 index 0000000000..ba188aa270 --- /dev/null +++ b/tests/genmc/pass/data-structures/treiber_stack_dynamic.rs @@ -0,0 +1,211 @@ +//@compile-flags: -Zmiri-genmc -Zmiri-ignore-leaks + +// TODO GENMC: maybe use `-Zmiri-genmc-symmetry-reduction`? + +#![no_main] +#![allow(static_mut_refs)] +#![allow(unused)] + +use std::alloc::{Layout, alloc, dealloc}; +use std::ffi::c_void; +use std::sync::atomic::{AtomicPtr, AtomicU64, Ordering}; + +use libc::{self, pthread_attr_t, pthread_t}; + +const MAX_THREADS: usize = 32; + +const MAX_NODES: usize = 0xFF; + +const POISON_IDX: u64 = 0xDEADBEEF; + +// TODO GENMC: thread local (for GenMC hazard pointer API) +// static mut TID: u64 = POISON_IDX; + +static mut STACK: MyStack = MyStack::new(); +static mut THREADS: [pthread_t; MAX_THREADS] = [0; MAX_THREADS]; +static mut PARAMS: [u64; MAX_THREADS] = [POISON_IDX; MAX_THREADS]; + +unsafe fn set_thread_num(_i: u64) { + // TID = i; +} + +#[allow(unused)] // TODO GENMC: what is the purpose of this in the GenMC version? +unsafe fn get_thread_num() -> u64 { + // TID + todo!() +} + +#[repr(C)] +struct Node { + value: u64, + next: AtomicPtr, +} + +struct MyStack { + top: AtomicPtr, +} + +impl Node { + pub unsafe fn new_alloc() -> *mut Self { + alloc(Layout::new::()) as *mut Self + } + + pub unsafe fn free(node: *mut Self) { + dealloc(node as *mut u8, Layout::new::()) + } + + pub unsafe fn reclaim(_node: *mut Self) { + // __VERIFIER_hp_retire(node); + } +} + +impl MyStack { + pub const fn new() -> Self { + Self { top: AtomicPtr::new(std::ptr::null_mut()) } + } + + pub unsafe fn init_stack(&mut self, _num_threads: usize) { + self.top = AtomicPtr::new(std::ptr::null_mut()); + } + + pub unsafe fn clear_stack(&mut self, _num_threads: usize) { + let mut next; + let mut top = *self.top.get_mut(); + while !top.is_null() { + next = *(*top).next.get_mut(); + Node::free(top); + top = next; + } + } + + pub unsafe fn push(&self, value: u64) { + let node = Node::new_alloc(); + (*node).value = value; + + loop { + let top = self.top.load(Ordering::Acquire); + (*node).next.store(top, Ordering::Relaxed); + if self.top.compare_exchange(top, node, Ordering::Release, Ordering::Relaxed).is_ok() { + break; + } + } + } + + pub unsafe fn pop(&self) -> u64 { + let mut top; + + // TODO GENMC: enable if GenMC hazard pointer API is implemented in MIRI + // __VERIFIER_hp_t *hp = __VERIFIER_hp_alloc(); + loop { + top = STACK.top.load(Ordering::Acquire); + // top = __VERIFIER_hp_protect(hp, &s->top); + if top.is_null() { + // __VERIFIER_hp_free(hp); + return 0; + } + + let next = (*top).next.load(Ordering::Relaxed); + if self.top.compare_exchange(top, next, Ordering::Release, Ordering::Relaxed).is_ok() { + break; + } + } + + let value = (*top).value; + /* Reclaim the used slot */ + // Node::reclaim(top); + // Node::free(top); + // __VERIFIER_hp_free(hp); + return value; + } +} + +extern "C" fn thread_w(value: *mut c_void) -> *mut c_void { + unsafe { + let pid = *(value as *mut u64); + set_thread_num(pid); + + STACK.push(pid); + + std::ptr::null_mut() + } +} + +extern "C" fn thread_r(value: *mut c_void) -> *mut c_void { + unsafe { + let pid = *(value as *mut u64); + set_thread_num(pid); + + let _idx = STACK.pop(); + + std::ptr::null_mut() + } +} + +extern "C" fn thread_rw(value: *mut c_void) -> *mut c_void { + unsafe { + let pid = *(value as *mut u64); + set_thread_num(pid); + + STACK.push(pid); + + let _idx = STACK.pop(); + + std::ptr::null_mut() + } +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let attr: *const pthread_attr_t = std::ptr::null(); + + // TODO GENMC: make different tests: + let readers = 1; + let writers = 2; + let rdwr = 0; + + let num_threads = readers + writers + rdwr; + + if num_threads > MAX_THREADS { + std::process::abort(); + } + + let mut i = 0; + unsafe { + MyStack::init_stack(&mut STACK, num_threads); + + for j in 0..num_threads { + PARAMS[j] = j as u64; + } + for _ in 0..readers { + let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; + if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_r, value) { + std::process::abort(); + } + i += 1; + } + for _ in 0..writers { + let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; + if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_w, value) { + std::process::abort(); + } + i += 1; + } + for _ in 0..rdwr { + let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; + if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_rw, value) { + std::process::abort(); + } + i += 1; + } + + for i in 0..num_threads { + if 0 != libc::pthread_join(THREADS[i], std::ptr::null_mut()) { + std::process::abort(); + } + } + + MyStack::clear_stack(&mut STACK, num_threads); + } + + 0 +} diff --git a/tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr b/tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr new file mode 100644 index 0000000000..fbd9adb20b --- /dev/null +++ b/tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 22 diff --git a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs new file mode 100644 index 0000000000..be549401c7 --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs @@ -0,0 +1,43 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + Y.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + X.store(2, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs b/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs new file mode 100644 index 0000000000..4c2af1b5e9 --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs @@ -0,0 +1,33 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + Y.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Release); + X.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr b/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs b/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs new file mode 100644 index 0000000000..dc6616d37e --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs @@ -0,0 +1,33 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + Y.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::SeqCst); + X.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr b/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs b/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs new file mode 100644 index 0000000000..db29ab9f84 --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs @@ -0,0 +1,35 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + Y.store(2, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + X.store(2, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr b/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr b/tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr b/tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2+2w/2W2W.rs b/tests/genmc/pass/litmus/2+2w/2W2W.rs new file mode 100644 index 0000000000..712e55ed9b --- /dev/null +++ b/tests/genmc/pass/litmus/2+2w/2W2W.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Release); + X.store(2, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Release); + X.store(2, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.rs b/tests/genmc/pass/litmus/2CoWR/2cowr.rs new file mode 100644 index 0000000000..2fd4abc528 --- /dev/null +++ b/tests/genmc/pass/litmus/2CoWR/2cowr.rs @@ -0,0 +1,57 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order1234 order2341 order3412 order4123 order4321 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order1234) { + [thread_1, thread_2, thread_3, thread_4] + } else if cfg!(order2341) { + [thread_2, thread_3, thread_4, thread_1] + } else if cfg!(order3412) { + [thread_3, thread_4, thread_1, thread_2] + } else if cfg!(order4123) { + [thread_4, thread_1, thread_2, thread_3] + } else if cfg!(order4321) { + [thread_4, thread_3, thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + null_mut() +} + +pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Release); + null_mut() +} diff --git a/tests/genmc/pass/litmus/CoRR/corr.order12.stderr b/tests/genmc/pass/litmus/CoRR/corr.order12.stderr new file mode 100644 index 0000000000..e4151d346e --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR/corr.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/CoRR/corr.order21.stderr b/tests/genmc/pass/litmus/CoRR/corr.order21.stderr new file mode 100644 index 0000000000..e4151d346e --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR/corr.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/CoRR/corr.rs b/tests/genmc/pass/litmus/CoRR/corr.rs new file mode 100644 index 0000000000..3159d3e566 --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR/corr.rs @@ -0,0 +1,41 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + X.store(2, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.rs b/tests/genmc/pass/litmus/CoRR0/corr0.rs new file mode 100644 index 0000000000..edf949b5e6 --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR0/corr0.rs @@ -0,0 +1,48 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order123 order321 order312 order231 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order123) { + [thread_1, thread_2, thread_3] + } else if cfg!(order321) { + [thread_3, thread_2, thread_1] + } else if cfg!(order312) { + [thread_3, thread_1, thread_2] + } else if cfg!(order231) { + [thread_2, thread_3, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr new file mode 100644 index 0000000000..c2ffa8ec3c --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr new file mode 100644 index 0000000000..c2ffa8ec3c --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr new file mode 100644 index 0000000000..c2ffa8ec3c --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr new file mode 100644 index 0000000000..c2ffa8ec3c --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr new file mode 100644 index 0000000000..c2ffa8ec3c --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.rs b/tests/genmc/pass/litmus/CoRR1/corr1.rs new file mode 100644 index 0000000000..acc1a3d7ff --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR1/corr1.rs @@ -0,0 +1,57 @@ +//@compile-flags: -Zmiri-genmc +//@revisions: order1234 order4321 order4123 order3412 order2341 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order1234) { + [thread_1, thread_2, thread_3, thread_4] + } else if cfg!(order4321) { + [thread_4, thread_3, thread_2, thread_1] + } else if cfg!(order4123) { + [thread_4, thread_1, thread_2, thread_3] + } else if cfg!(order3412) { + [thread_3, thread_4, thread_1, thread_2] + } else if cfg!(order2341) { + [thread_2, thread_3, thread_4, thread_1] + } else { + unimplemented!(); + }; + + let ids = unsafe { create_pthreads_no_params(thread_order) }; + unsafe { join_pthreads(ids) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(2, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr new file mode 100644 index 0000000000..c8cd87ff6b --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr new file mode 100644 index 0000000000..c8cd87ff6b --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr new file mode 100644 index 0000000000..c8cd87ff6b --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr new file mode 100644 index 0000000000..c8cd87ff6b --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr new file mode 100644 index 0000000000..c8cd87ff6b --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.rs b/tests/genmc/pass/litmus/CoRR2/corr2.rs new file mode 100644 index 0000000000..1a3f2e10b7 --- /dev/null +++ b/tests/genmc/pass/litmus/CoRR2/corr2.rs @@ -0,0 +1,57 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order1234 order4321 order4123 order3412 order2341 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order1234) { + [thread_1, thread_2, thread_3, thread_4] + } else if cfg!(order4321) { + [thread_4, thread_3, thread_2, thread_1] + } else if cfg!(order4123) { + [thread_4, thread_1, thread_2, thread_3] + } else if cfg!(order3412) { + [thread_3, thread_4, thread_1, thread_2] + } else if cfg!(order2341) { + [thread_2, thread_3, thread_4, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(2, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/CoRW/corw.order12.stderr b/tests/genmc/pass/litmus/CoRW/corw.order12.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/CoRW/corw.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoRW/corw.order21.stderr b/tests/genmc/pass/litmus/CoRW/corw.order21.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/CoRW/corw.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoRW/corw.rs b/tests/genmc/pass/litmus/CoRW/corw.rs new file mode 100644 index 0000000000..4776ae61ed --- /dev/null +++ b/tests/genmc/pass/litmus/CoRW/corw.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + X.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(2, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/CoWR/cowr.order12.stderr b/tests/genmc/pass/litmus/CoWR/cowr.order12.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/CoWR/cowr.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoWR/cowr.order21.stderr b/tests/genmc/pass/litmus/CoWR/cowr.order21.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/CoWR/cowr.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoWR/cowr.rs b/tests/genmc/pass/litmus/CoWR/cowr.rs new file mode 100644 index 0000000000..8d3773bbfc --- /dev/null +++ b/tests/genmc/pass/litmus/CoWR/cowr.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(2, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs b/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs new file mode 100644 index 0000000000..d6dc8c755b --- /dev/null +++ b/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + Y.load(Ordering::SeqCst); + null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + X.load(Ordering::SeqCst); + null_mut() +} + +pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::SeqCst); + null_mut() +} diff --git a/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr b/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr new file mode 100644 index 0000000000..f5e120ea47 --- /dev/null +++ b/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 16 diff --git a/tests/genmc/pass/litmus/IRIWish/IRIWish.rs b/tests/genmc/pass/litmus/IRIWish/IRIWish.rs new file mode 100644 index 0000000000..b424c11208 --- /dev/null +++ b/tests/genmc/pass/litmus/IRIWish/IRIWish.rs @@ -0,0 +1,48 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + let r1 = X.load(Ordering::Relaxed); + Y.store(r1, Ordering::Release); + null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + let _r1 = X.load(Ordering::Relaxed); + std::sync::atomic::fence(Ordering::AcqRel); + let _r2 = Y.load(Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + let _r1 = Y.load(Ordering::Relaxed); + std::sync::atomic::fence(Ordering::AcqRel); + let _r2 = X.load(Ordering::Relaxed); + null_mut() +} diff --git a/tests/genmc/pass/litmus/IRIWish/IRIWish.stderr b/tests/genmc/pass/litmus/IRIWish/IRIWish.stderr new file mode 100644 index 0000000000..452fca4856 --- /dev/null +++ b/tests/genmc/pass/litmus/IRIWish/IRIWish.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 28 diff --git a/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs b/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs new file mode 100644 index 0000000000..beb8c47480 --- /dev/null +++ b/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs @@ -0,0 +1,48 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static W: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + Z.fetch_add(1, Ordering::AcqRel); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Z.fetch_add(1, Ordering::AcqRel); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + W.fetch_add(1, Ordering::AcqRel); + std::ptr::null_mut() +} + +extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + W.fetch_add(1, Ordering::AcqRel); + X.store(1, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr b/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr new file mode 100644 index 0000000000..978d7c1ff3 --- /dev/null +++ b/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 15 diff --git a/tests/genmc/pass/litmus/LB/LB.order12.stderr b/tests/genmc/pass/litmus/LB/LB.order12.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/LB/LB.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/LB/LB.order21.stderr b/tests/genmc/pass/litmus/LB/LB.order21.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/LB/LB.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/LB/LB.rs b/tests/genmc/pass/litmus/LB/LB.rs new file mode 100644 index 0000000000..0247ea9634 --- /dev/null +++ b/tests/genmc/pass/litmus/LB/LB.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + X.store(2, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs b/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs new file mode 100644 index 0000000000..aa089d3d39 --- /dev/null +++ b/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs @@ -0,0 +1,41 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + Z.fetch_add(1, Ordering::AcqRel); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Z.fetch_add(1, Ordering::AcqRel); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr b/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr new file mode 100644 index 0000000000..708f4aab1b --- /dev/null +++ b/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 7 diff --git a/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs b/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs new file mode 100644 index 0000000000..f11f6b9a0c --- /dev/null +++ b/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +// -Zmiri-disable-data-race-detector + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MP+rels+acqf/mp+rels+acqf.c) uses non-atomic accesses for `X` with disabled race detection. +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + + Y.store(0, Ordering::Release); + Y.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + if Y.load(Ordering::Relaxed) != 0 { + std::sync::atomic::fence(Ordering::Acquire); + let _x = X.load(Ordering::Relaxed); + } + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr b/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/MP/MP.order12.stderr b/tests/genmc/pass/litmus/MP/MP.order12.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/MP/MP.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/MP/MP.order21.stderr b/tests/genmc/pass/litmus/MP/MP.order21.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/MP/MP.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/MP/MP.rs b/tests/genmc/pass/litmus/MP/MP.rs new file mode 100644 index 0000000000..c298280f0f --- /dev/null +++ b/tests/genmc/pass/litmus/MP/MP.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs b/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs new file mode 100644 index 0000000000..3ff6c5f2fd --- /dev/null +++ b/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs @@ -0,0 +1,43 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MPU+rels+acq/mpu+rels+acq.c) uses non-atomic accesses for `X` with disabled race detection. +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + + Y.store(0, Ordering::Release); + Y.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + if Y.load(Ordering::Acquire) > 1 { + X.store(2, Ordering::Relaxed); + } + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr b/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr new file mode 100644 index 0000000000..89aa5eb69c --- /dev/null +++ b/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 13 diff --git a/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs b/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs new file mode 100644 index 0000000000..c98e9f23ba --- /dev/null +++ b/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs @@ -0,0 +1,51 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MPU2+rels+acqf/mpu2+rels+acqf.c) uses non-atomic accesses for `X` with disabled race detection. +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + + Y.store(0, Ordering::Release); + Y.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + let expected = 2; + let _ = Y.compare_exchange(expected, 3, Ordering::Relaxed, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + let expected = 1; + let _ = Y.compare_exchange(expected, 2, Ordering::Relaxed, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + if Y.load(Ordering::Acquire) > 2 { + std::sync::atomic::fence(Ordering::Acquire); + X.store(2, Ordering::Relaxed); + } + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr b/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr new file mode 100644 index 0000000000..c2ffa8ec3c --- /dev/null +++ b/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs b/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs new file mode 100644 index 0000000000..27d63b605e --- /dev/null +++ b/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs @@ -0,0 +1,35 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + Y.load(Ordering::SeqCst); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + X.load(Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr b/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/SB/SB.order12.stderr b/tests/genmc/pass/litmus/SB/SB.order12.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/SB/SB.order12.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/SB/SB.order21.stderr b/tests/genmc/pass/litmus/SB/SB.order21.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/SB/SB.order21.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/SB/SB.rs b/tests/genmc/pass/litmus/SB/SB.rs new file mode 100644 index 0000000000..645291d088 --- /dev/null +++ b/tests/genmc/pass/litmus/SB/SB.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order12 order21 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order12) { + [thread_1, thread_2] + } else if cfg!(order21) { + [thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + Y.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Release); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr new file mode 100644 index 0000000000..708f4aab1b --- /dev/null +++ b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 7 diff --git a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr new file mode 100644 index 0000000000..708f4aab1b --- /dev/null +++ b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 7 diff --git a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs new file mode 100644 index 0000000000..65f87925f2 --- /dev/null +++ b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs @@ -0,0 +1,51 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order123 order321 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order123) { + [thread_1, thread_2, thread_3] + } else if cfg!(order321) { + [thread_3, thread_2, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + Y.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Acquire); + Z.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + Z.store(2, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + X.load(Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs b/tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs new file mode 100644 index 0000000000..3459fbe6e5 --- /dev/null +++ b/tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs @@ -0,0 +1,40 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.fetch_add(1, Ordering::SeqCst); + Y.load(Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + Y.store(3, Ordering::SeqCst); + X.load(Ordering::SeqCst); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr b/tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr new file mode 100644 index 0000000000..fbd9adb20b --- /dev/null +++ b/tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 22 diff --git a/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs b/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs new file mode 100644 index 0000000000..351b65d0e6 --- /dev/null +++ b/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + // TODO GENMC: do these have to be unsafe? + unsafe { + miri_genmc_verifier_assume(2 > Y.load(Ordering::Relaxed) || Y.load(Ordering::Relaxed) > 3); + } + X.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + // TODO GENMC: do these have to be unsafe? + unsafe { + miri_genmc_verifier_assume(X.load(Ordering::Relaxed) < 3); + } + + Y.store(3, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::SeqCst); + Y.store(4, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr b/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr new file mode 100644 index 0000000000..bcd0ece9c7 --- /dev/null +++ b/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr @@ -0,0 +1,4 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 +Number of blocked executions seen: 1 diff --git a/tests/genmc/pass/litmus/atomicpo/atomicpo.rs b/tests/genmc/pass/litmus/atomicpo/atomicpo.rs new file mode 100644 index 0000000000..5c42605715 --- /dev/null +++ b/tests/genmc/pass/litmus/atomicpo/atomicpo.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + std::sync::atomic::fence(Ordering::AcqRel); + Y.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.swap(1, Ordering::Relaxed); + X.swap(1, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/atomicpo/atomicpo.stderr b/tests/genmc/pass/litmus/atomicpo/atomicpo.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/litmus/atomicpo/atomicpo.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/casdep/casdep.rs b/tests/genmc/pass/litmus/casdep/casdep.rs new file mode 100644 index 0000000000..ad70af27a9 --- /dev/null +++ b/tests/genmc/pass/litmus/casdep/casdep.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + let a = X.load(Ordering::Relaxed); + let _b = Y.compare_exchange(a, 1, Ordering::Relaxed, Ordering::Relaxed); + Z.store(a, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(2, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/casdep/casdep.stderr b/tests/genmc/pass/litmus/casdep/casdep.stderr new file mode 100644 index 0000000000..edecd38278 --- /dev/null +++ b/tests/genmc/pass/litmus/casdep/casdep.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/tests/genmc/pass/litmus/ccr/ccr.rs b/tests/genmc/pass/litmus/ccr/ccr.rs new file mode 100644 index 0000000000..68ccf2b74e --- /dev/null +++ b/tests/genmc/pass/litmus/ccr/ccr.rs @@ -0,0 +1,33 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + let expected = 0; + let _ = X.compare_exchange(expected, 42, Ordering::Relaxed, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + let expected = 0; + let _ = X.compare_exchange(expected, 17, Ordering::Relaxed, Ordering::Relaxed); + X.load(Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/ccr/ccr.stderr b/tests/genmc/pass/litmus/ccr/ccr.stderr new file mode 100644 index 0000000000..edecd38278 --- /dev/null +++ b/tests/genmc/pass/litmus/ccr/ccr.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/tests/genmc/pass/litmus/cii/cii.rs b/tests/genmc/pass/litmus/cii/cii.rs new file mode 100644 index 0000000000..0e25407d83 --- /dev/null +++ b/tests/genmc/pass/litmus/cii/cii.rs @@ -0,0 +1,36 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2, thread_3]) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + let expected = 1; + let _ = X.compare_exchange(expected, 2, Ordering::Relaxed, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/cii/cii.stderr b/tests/genmc/pass/litmus/cii/cii.stderr new file mode 100644 index 0000000000..e4151d346e --- /dev/null +++ b/tests/genmc/pass/litmus/cii/cii.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/cumul-release/cumul-release.rs b/tests/genmc/pass/litmus/cumul-release/cumul-release.rs new file mode 100644 index 0000000000..c414923e37 --- /dev/null +++ b/tests/genmc/pass/litmus/cumul-release/cumul-release.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); +static Z: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + let r1 = Y.load(Ordering::Relaxed); + Z.store(r1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + let _r2 = Z.load(Ordering::Relaxed); + std::sync::atomic::fence(Ordering::AcqRel); + let _r3 = X.load(Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/cumul-release/cumul-release.stderr b/tests/genmc/pass/litmus/cumul-release/cumul-release.stderr new file mode 100644 index 0000000000..c2e069848f --- /dev/null +++ b/tests/genmc/pass/litmus/cumul-release/cumul-release.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 8 diff --git a/tests/genmc/pass/litmus/default/default.order123.stderr b/tests/genmc/pass/litmus/default/default.order123.stderr new file mode 100644 index 0000000000..1ec3beefbf --- /dev/null +++ b/tests/genmc/pass/litmus/default/default.order123.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.order231.stderr b/tests/genmc/pass/litmus/default/default.order231.stderr new file mode 100644 index 0000000000..1ec3beefbf --- /dev/null +++ b/tests/genmc/pass/litmus/default/default.order231.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.order312.stderr b/tests/genmc/pass/litmus/default/default.order312.stderr new file mode 100644 index 0000000000..1ec3beefbf --- /dev/null +++ b/tests/genmc/pass/litmus/default/default.order312.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.order321.stderr b/tests/genmc/pass/litmus/default/default.order321.stderr new file mode 100644 index 0000000000..1ec3beefbf --- /dev/null +++ b/tests/genmc/pass/litmus/default/default.order321.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.rs b/tests/genmc/pass/litmus/default/default.rs new file mode 100644 index 0000000000..e45fd9b509 --- /dev/null +++ b/tests/genmc/pass/litmus/default/default.rs @@ -0,0 +1,49 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc +//@revisions: order123 order321 order312 order231 + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = if cfg!(order123) { + [thread_1, thread_2, thread_3] + } else if cfg!(order321) { + [thread_3, thread_2, thread_1] + } else if cfg!(order312) { + [thread_3, thread_1, thread_2] + } else if cfg!(order231) { + [thread_2, thread_3, thread_1] + } else { + unimplemented!(); + }; + + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.load(Ordering::Acquire); + X.load(Ordering::Acquire); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.store(2, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/detour/detour.rs b/tests/genmc/pass/litmus/detour/detour.rs new file mode 100644 index 0000000000..eee0dadcd8 --- /dev/null +++ b/tests/genmc/pass/litmus/detour/detour.rs @@ -0,0 +1,42 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicI64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicI64 = AtomicI64::new(0); +static Y: AtomicI64 = AtomicI64::new(0); +static Z: AtomicI64 = AtomicI64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + let a = Z.load(Ordering::Relaxed); + X.store(a.wrapping_sub(1), Ordering::Relaxed); + let b = X.load(Ordering::Relaxed); + Y.store(b, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + let c = Y.load(Ordering::Relaxed); + Z.store(c, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/detour/detour.stderr b/tests/genmc/pass/litmus/detour/detour.stderr new file mode 100644 index 0000000000..7e0204914a --- /dev/null +++ b/tests/genmc/pass/litmus/detour/detour.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 9 diff --git a/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs b/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs new file mode 100644 index 0000000000..19547d09b7 --- /dev/null +++ b/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs @@ -0,0 +1,45 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(2, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.store(3, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + let _r1 = X.load(Ordering::Relaxed); + let _r2 = X.load(Ordering::Relaxed); + let _r3 = X.load(Ordering::Relaxed); + let _r4 = X.load(Ordering::Relaxed); + null_mut() +} diff --git a/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr b/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr new file mode 100644 index 0000000000..528ebdfd2b --- /dev/null +++ b/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 210 diff --git a/tests/genmc/pass/litmus/inc2w/inc2w.rs b/tests/genmc/pass/litmus/inc2w/inc2w.rs new file mode 100644 index 0000000000..03552cac22 --- /dev/null +++ b/tests/genmc/pass/litmus/inc2w/inc2w.rs @@ -0,0 +1,37 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.store(4, Ordering::Release); + null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + X.fetch_add(2, Ordering::Relaxed); + null_mut() +} diff --git a/tests/genmc/pass/litmus/inc2w/inc2w.stderr b/tests/genmc/pass/litmus/inc2w/inc2w.stderr new file mode 100644 index 0000000000..e4151d346e --- /dev/null +++ b/tests/genmc/pass/litmus/inc2w/inc2w.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs b/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs new file mode 100644 index 0000000000..17213612ae --- /dev/null +++ b/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs @@ -0,0 +1,63 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicU64, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicU64 = AtomicU64::new(0); + +static mut A: u64 = 0; +static mut B: u64 = 0; +static mut C: u64 = 0; +static mut D: u64 = 0; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2, thread_3, thread_4, thread_5]; + let ids = unsafe { create_pthreads_no_params(thread_order) }; + unsafe { join_pthreads(ids) }; + + if unsafe { A == 42 && B == 2 && C == 1 && D == 42 } { + std::process::abort(); + } + + 0 +} + +pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + unsafe { + A = X.load(Ordering::Relaxed); + B = X.load(Ordering::Relaxed); + } + null_mut() +} + +pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { + X.store(42, Ordering::Relaxed); + null_mut() +} + +pub extern "C" fn thread_5(_value: *mut c_void) -> *mut c_void { + unsafe { + C = X.load(Ordering::Relaxed); + D = X.load(Ordering::Relaxed); + } + null_mut() +} diff --git a/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr b/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr new file mode 100644 index 0000000000..ad9e4b3a6e --- /dev/null +++ b/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 600 diff --git a/tests/genmc/pass/litmus/riwi/riwi.rs b/tests/genmc/pass/litmus/riwi/riwi.rs new file mode 100644 index 0000000000..1c210e7cea --- /dev/null +++ b/tests/genmc/pass/litmus/riwi/riwi.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_1, thread_2]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + Y.load(Ordering::Relaxed); + X.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + X.fetch_add(1, Ordering::Relaxed); + Y.store(1, Ordering::Release); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/riwi/riwi.stderr b/tests/genmc/pass/litmus/riwi/riwi.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/litmus/riwi/riwi.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs b/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs new file mode 100644 index 0000000000..83468eddc0 --- /dev/null +++ b/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs @@ -0,0 +1,43 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static LOCK: AtomicU64 = AtomicU64::new(0); + +use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let thread_order = [thread_ra, thread_r, thread_rr, thread_rs]; + let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + 0 +} + +extern "C" fn thread_ra(_value: *mut c_void) -> *mut c_void { + LOCK.fetch_add(1, Ordering::Acquire); + LOCK.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_r(_value: *mut c_void) -> *mut c_void { + LOCK.fetch_add(1, Ordering::Relaxed); + LOCK.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} + +extern "C" fn thread_rr(_value: *mut c_void) -> *mut c_void { + LOCK.fetch_add(1, Ordering::Release); + std::ptr::null_mut() +} + +extern "C" fn thread_rs(_value: *mut c_void) -> *mut c_void { + LOCK.fetch_add(1, Ordering::Relaxed); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr b/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr new file mode 100644 index 0000000000..5b01ae0789 --- /dev/null +++ b/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 180 diff --git a/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs b/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs new file mode 100644 index 0000000000..5c513ef561 --- /dev/null +++ b/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs @@ -0,0 +1,52 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +// #[path = "../../../../utils-dep/mod.rs"] +// mod utils_dep; + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +// use crate::utils_dep::*; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + // let thread_order = [thread_1, thread_2]; + // let _ids = unsafe { create_pthreads_no_params(thread_order) }; + + let spawn = |func| { + use libc::{pthread_attr_t, pthread_t}; + + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + let ret = unsafe { libc::pthread_create(&raw mut thread_id, attr, func, value) }; + if 0 != ret { + std::process::abort(); + } + thread_id + }; + + let _t1 = spawn(thread_1); + let _t2 = spawn(thread_2); + + 0 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + X.store(1, Ordering::SeqCst); + Y.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + Y.store(1, Ordering::Release); + X.store(2, Ordering::SeqCst); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr b/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr new file mode 100644 index 0000000000..61dc3f60ba --- /dev/null +++ b/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 4 diff --git a/tests/genmc/pass/simple/2w2w_seqcst.rs b/tests/genmc/pass/simple/2w2w_seqcst.rs new file mode 100644 index 0000000000..f8161e90f0 --- /dev/null +++ b/tests/genmc/pass/simple/2w2w_seqcst.rs @@ -0,0 +1,46 @@ +//@compile-flags: -Zmiri-genmc + +// TODO GENMC: this test currently takes 3 iterations, it this correct? + +#![no_main] + +use std::ffi::c_void; +use std::sync::atomic::{AtomicU64, Ordering}; + +use libc::{self, pthread_attr_t, pthread_t}; + +static X: AtomicU64 = AtomicU64::new(0); +static Y: AtomicU64 = AtomicU64::new(0); + +const LOAD_ORD: Ordering = Ordering::SeqCst; +const STORE_ORD: Ordering = Ordering::SeqCst; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + let ret_create = unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }; + assert!(ret_create == 0); + + X.store(1, STORE_ORD); + Y.store(2, STORE_ORD); + + let ret_join = unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }; + assert!(ret_join == 0); + + let x = X.load(LOAD_ORD); + let y = Y.load(LOAD_ORD); + if x == 1 && y == 1 { + unsafe { std::hint::unreachable_unchecked() }; + } + 0 +} + +extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { + Y.store(1, STORE_ORD); + X.store(2, STORE_ORD); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/simple/2w2w_seqcst.stderr b/tests/genmc/pass/simple/2w2w_seqcst.stderr new file mode 100644 index 0000000000..f2f3f904fb --- /dev/null +++ b/tests/genmc/pass/simple/2w2w_seqcst.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 3 diff --git a/tests/genmc/pass/simple/atomic_ptr.rs b/tests/genmc/pass/simple/atomic_ptr.rs new file mode 100644 index 0000000000..03fbd3e8b7 --- /dev/null +++ b/tests/genmc/pass/simple/atomic_ptr.rs @@ -0,0 +1,83 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::sync::atomic::*; + +static mut X: u64 = 0; +static mut Y: u64 = 0; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let atomic_ptr: AtomicPtr = AtomicPtr::new(&raw mut X); + + let x_ptr = atomic_ptr.load(Ordering::SeqCst); + *x_ptr = 10; + if X != 10 { + std::process::abort(); + } + atomic_ptr.store(&raw mut Y, Ordering::SeqCst); + Y = 42; + let y_ptr = atomic_ptr.load(Ordering::SeqCst); + if *y_ptr != 42 { + std::process::abort(); + } + *y_ptr = 1234; + if Y != 1234 { + std::process::abort(); + } else if X != 10 { + std::process::abort(); + } + let y_ptr_ = atomic_ptr.swap(&raw mut X, Ordering::SeqCst); + if y_ptr_ != y_ptr { + std::process::abort(); + } + // To make sure also the provenance info is correctly restored, we need to use the pointers: + if *y_ptr_ != *y_ptr { + std::process::abort(); + } + *y_ptr_ = *y_ptr; + + match atomic_ptr.compare_exchange( + y_ptr, // wrong, it should be `x_ptr`, so this should never succeed + std::ptr::dangling_mut(), + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_ptr) => std::process::abort(), + Err(ptr) => + if ptr != x_ptr { + std::process::abort(); + } else if *ptr != *x_ptr { + std::process::abort(); + } else { + *ptr = *ptr; + }, + } + + let mut array: [u64; 10] = [0xAAAA; 10]; + match atomic_ptr.compare_exchange( + x_ptr, + &raw mut array[2], + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(ptr) => + if ptr != x_ptr { + std::process::abort(); + }, + Err(_ptr) => std::process::abort(), + } + let ptr = atomic_ptr.load(Ordering::SeqCst); + *ptr = 0xB; + if array[2] != 0xB { + std::process::abort(); + } + array[2] = 0xC; + if *ptr != 0xC { + std::process::abort(); + } + } + 0 +} diff --git a/tests/genmc/pass/simple/atomic_ptr.stderr b/tests/genmc/pass/simple/atomic_ptr.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/simple/atomic_ptr.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/atomic_simple.rs b/tests/genmc/pass/simple/atomic_simple.rs new file mode 100644 index 0000000000..c9fdb89850 --- /dev/null +++ b/tests/genmc/pass/simple/atomic_simple.rs @@ -0,0 +1,17 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::sync::atomic::*; + +static FLAG: AtomicUsize = AtomicUsize::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + FLAG.store(42, Ordering::SeqCst); + let val = FLAG.load(Ordering::SeqCst); + if val != 42 { + std::process::abort(); + } + 0 +} diff --git a/tests/genmc/pass/simple/atomic_simple.stderr b/tests/genmc/pass/simple/atomic_simple.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/simple/atomic_simple.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/cas_simple.rs b/tests/genmc/pass/simple/cas_simple.rs new file mode 100644 index 0000000000..cd42084a54 --- /dev/null +++ b/tests/genmc/pass/simple/cas_simple.rs @@ -0,0 +1,47 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::sync::atomic::*; + +static VALUE: AtomicUsize = AtomicUsize::new(0); + +const SUCCESS_ORD: Ordering = Ordering::SeqCst; +const FAILURE_ORD: Ordering = Ordering::SeqCst; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + VALUE.store(1, SUCCESS_ORD); + + let current = 1; + let new_value = 2; + // Expect success: + match VALUE.compare_exchange(current, new_value, SUCCESS_ORD, FAILURE_ORD) { + Ok(old_value) => + if old_value != current { + std::process::abort(); + }, + Err(_value) => std::process::abort(), + } + + if new_value != VALUE.load(SUCCESS_ORD) { + std::process::abort() + } + + let dummy_value = 42; + let wrong_value = 1234; + + // Expect failure: + match VALUE.compare_exchange(wrong_value, dummy_value, SUCCESS_ORD, FAILURE_ORD) { + Ok(_old_value) => std::process::abort(), + Err(old_value) => + if old_value != new_value { + std::process::abort(); + }, + } + + if new_value != VALUE.load(SUCCESS_ORD) { + std::process::abort() + } + 0 +} diff --git a/tests/genmc/pass/simple/cas_simple.stderr b/tests/genmc/pass/simple/cas_simple.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/simple/cas_simple.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_main.rs b/tests/genmc/pass/simple/simple_main.rs new file mode 100644 index 0000000000..ac3c81a91b --- /dev/null +++ b/tests/genmc/pass/simple/simple_main.rs @@ -0,0 +1,3 @@ +//@compile-flags: -Zmiri-genmc + +fn main() {} diff --git a/tests/genmc/pass/simple/simple_main.stderr b/tests/genmc/pass/simple/simple_main.stderr new file mode 100644 index 0000000000..2184c16ce9 --- /dev/null +++ b/tests/genmc/pass/simple/simple_main.stderr @@ -0,0 +1,7 @@ +warning: GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)! + +warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Relaxed' is treated like 'Acquire', which means that Miri might miss bugs related to this memory access (possible unsoundness)! + + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_main_spawn_threads.rs b/tests/genmc/pass/simple/simple_main_spawn_threads.rs new file mode 100644 index 0000000000..ec1af0dde8 --- /dev/null +++ b/tests/genmc/pass/simple/simple_main_spawn_threads.rs @@ -0,0 +1,10 @@ +//@compile-flags: -Zmiri-genmc + +const N: usize = 1; + +fn main() { + let handles: Vec<_> = (0..N).map(|_| std::thread::spawn(thread_func)).collect(); + handles.into_iter().for_each(|handle| handle.join().unwrap()); +} + +fn thread_func() {} diff --git a/tests/genmc/pass/simple/simple_main_spawn_threads.stderr b/tests/genmc/pass/simple/simple_main_spawn_threads.stderr new file mode 100644 index 0000000000..c6bd55a4f8 --- /dev/null +++ b/tests/genmc/pass/simple/simple_main_spawn_threads.stderr @@ -0,0 +1,9 @@ +warning: GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)! + +warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Relaxed' is treated like 'Acquire', which means that Miri might miss bugs related to this memory access (possible unsoundness)! + +warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Acquire' is treated like 'Relaxed', which means that Miri might incorrectly detect errors related to this memory access (possible false positives). + + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs b/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs new file mode 100644 index 0000000000..12d90869c0 --- /dev/null +++ b/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs @@ -0,0 +1,35 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::ffi::c_void; + +use libc::{self, pthread_attr_t, pthread_t}; + +const N: usize = 1; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let mut handles: Vec = vec![0; N]; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + handles.iter_mut().for_each(|thread_id| { + if 0 != unsafe { libc::pthread_create(thread_id, attr, thread_func, value) } { + std::process::abort(); + } + }); + + handles.into_iter().for_each(|thread_id| { + if 0 != unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) } { + std::process::abort(); + } + }); + + 0 +} + +extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr b/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs b/tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs new file mode 100644 index 0000000000..69a0d00f26 --- /dev/null +++ b/tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs @@ -0,0 +1,15 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +const N: usize = 1; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let handles: Vec<_> = (0..N).map(|_| std::thread::spawn(thread_func)).collect(); + handles.into_iter().for_each(|handle| handle.join().unwrap()); + + 0 +} + +fn thread_func() {} diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr b/tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr new file mode 100644 index 0000000000..8ac3e9f5cf --- /dev/null +++ b/tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr @@ -0,0 +1,9 @@ +warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Relaxed' is treated like 'Acquire', which means that Miri might miss bugs related to this memory access (possible unsoundness)! + +warning: GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)! + +warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Acquire' is treated like 'Relaxed', which means that Miri might incorrectly detect errors related to this memory access (possible false positives). + + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/stack_alloc_atomic.rs b/tests/genmc/pass/simple/stack_alloc_atomic.rs new file mode 100644 index 0000000000..fa595845f9 --- /dev/null +++ b/tests/genmc/pass/simple/stack_alloc_atomic.rs @@ -0,0 +1,18 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::sync::atomic::*; + +const ORD: Ordering = Ordering::SeqCst; + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let x = AtomicU64::new(1234); + let a = x.load(ORD); + if a != 1234 { + std::process::abort(); + } + + 0 +} diff --git a/tests/genmc/pass/simple/stack_alloc_atomic.stderr b/tests/genmc/pass/simple/stack_alloc_atomic.stderr new file mode 100644 index 0000000000..2382cc5a78 --- /dev/null +++ b/tests/genmc/pass/simple/stack_alloc_atomic.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/thread_locals.rs b/tests/genmc/pass/simple/thread_locals.rs new file mode 100644 index 0000000000..b37ced017e --- /dev/null +++ b/tests/genmc/pass/simple/thread_locals.rs @@ -0,0 +1,54 @@ +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc + +#![no_main] + +#[path = "../../../utils-dep/mod.rs"] +mod utils_dep; + +use std::cell::Cell; +use std::ffi::c_void; +use std::sync::atomic::{AtomicPtr, Ordering}; + +use crate::utils_dep::*; + +static X: AtomicPtr = AtomicPtr::new(std::ptr::null_mut()); + +thread_local! { + static R: Cell<*mut u64> = Cell::new(std::ptr::null_mut()); +} + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2, thread_3]) }; + + 0 +} + +pub unsafe fn malloc() -> *mut u64 { + Box::into_raw(Box::::new_uninit()) as *mut u64 +} + +extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { + unsafe { + R.set(malloc()); + let r_ptr = R.get(); + let _ = X.compare_exchange(std::ptr::null_mut(), r_ptr, Ordering::SeqCst, Ordering::SeqCst); + std::ptr::null_mut() + } +} + +extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { + unsafe { + R.set(malloc()); + std::ptr::null_mut() + } +} + +extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { + unsafe { + R.set(malloc()); + let r_ptr = R.get(); + let _ = X.compare_exchange(std::ptr::null_mut(), r_ptr, Ordering::SeqCst, Ordering::SeqCst); + std::ptr::null_mut() + } +} diff --git a/tests/genmc/pass/simple/thread_locals.stderr b/tests/genmc/pass/simple/thread_locals.stderr new file mode 100644 index 0000000000..edecd38278 --- /dev/null +++ b/tests/genmc/pass/simple/thread_locals.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/tests/genmc/pass/simple/thread_simple.rs b/tests/genmc/pass/simple/thread_simple.rs new file mode 100644 index 0000000000..74da7f98ad --- /dev/null +++ b/tests/genmc/pass/simple/thread_simple.rs @@ -0,0 +1,34 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +use std::ffi::c_void; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering::SeqCst; + +use libc::{self, pthread_attr_t, pthread_t}; + +static FLAG: AtomicU64 = AtomicU64::new(0); + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + assert!(0 == unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }); + + FLAG.store(1, SeqCst); + + assert!(0 == unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }); + + let flag = FLAG.load(SeqCst); + assert!(flag == 1 || flag == 2); + return 0; +} + +extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { + FLAG.store(2, SeqCst); + std::ptr::null_mut() +} diff --git a/tests/genmc/pass/simple/thread_simple.stderr b/tests/genmc/pass/simple/thread_simple.stderr new file mode 100644 index 0000000000..edecd38278 --- /dev/null +++ b/tests/genmc/pass/simple/thread_simple.stderr @@ -0,0 +1,3 @@ + +(GenMC) Verification complete. No errors were detected. +Number of complete executions explored: 2 diff --git a/tests/ui.rs b/tests/ui.rs index cb915b11b6..a1c2402c47 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -337,6 +337,10 @@ fn main() -> Result<()> { ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?; ui(Mode::Fail, "tests/native-lib/fail", &target, WithoutDependencies, tmpdir.path())?; } + if cfg!(feature = "genmc") { + ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?; + ui(Mode::Fail, "tests/genmc/fail", &target, WithDependencies, tmpdir.path())?; + } Ok(()) } diff --git a/tests/utils-dep/genmc.rs b/tests/utils-dep/genmc.rs new file mode 100644 index 0000000000..f6cdab63a7 --- /dev/null +++ b/tests/utils-dep/genmc.rs @@ -0,0 +1,27 @@ +use std::ffi::c_void; + +use libc::{self, pthread_attr_t, pthread_t}; + +pub unsafe fn create_pthreads_no_params( + functions: [extern "C" fn(*mut c_void) -> *mut c_void; N], +) -> [pthread_t; N] { + functions.map(|func| { + let mut thread_id: pthread_t = 0; + + let attr: *const pthread_attr_t = std::ptr::null(); + let value: *mut c_void = std::ptr::null_mut(); + + if 0 != unsafe { libc::pthread_create(&raw mut thread_id, attr, func, value) } { + std::process::abort(); + } + thread_id + }) +} + +pub unsafe fn join_pthreads(thread_ids: [pthread_t; N]) { + let _ = thread_ids.map(|id| { + if 0 != unsafe { libc::pthread_join(id, std::ptr::null_mut()) } { + std::process::abort(); + } + }); +} diff --git a/tests/utils-dep/miri_extern.rs b/tests/utils-dep/miri_extern.rs new file mode 100644 index 0000000000..dbd4cdb48d --- /dev/null +++ b/tests/utils-dep/miri_extern.rs @@ -0,0 +1,2 @@ +// TODO GENMC: is this ok or is there a better solution? +include!("../utils/miri_extern.rs"); diff --git a/tests/utils-dep/mod.rs b/tests/utils-dep/mod.rs new file mode 100644 index 0000000000..ab35b8e3c4 --- /dev/null +++ b/tests/utils-dep/mod.rs @@ -0,0 +1,8 @@ +#![allow(dead_code)] +#![allow(unused_imports)] + +pub mod genmc; +mod miri_extern; + +pub use self::genmc::*; +pub use self::miri_extern::*; diff --git a/tests/utils/miri_extern.rs b/tests/utils/miri_extern.rs index d6c43b1882..4ce7d27539 100644 --- a/tests/utils/miri_extern.rs +++ b/tests/utils/miri_extern.rs @@ -147,4 +147,7 @@ extern "Rust" { /// "symbolic" alignment checks. Will fail if the pointer is not actually aligned or `align` is /// not a power of two. Has no effect when alignment checks are concrete (which is the default). pub fn miri_promise_symbolic_alignment(ptr: *const (), align: usize); + + /// Blocks the current execution if the argument is false + pub fn miri_genmc_verifier_assume(condition: bool); } From f5082fa38f7399eee70a9e470d6472034787e535 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 10:02:31 +0200 Subject: [PATCH 02/64] Miri-GenMC build PR: Clear out tests directory --- .../_disabled/fail/weak_memory/weak_uninit.rs | 57 ----- tests/genmc/fail/simple/2w2w_acq_rel.rs | 44 ---- tests/genmc/fail/simple/2w2w_acq_rel.stderr | 15 -- tests/genmc/fail/simple/2w2w_relaxed.rs | 44 ---- tests/genmc/fail/simple/2w2w_relaxed.stderr | 15 -- .../read_global_init.rs | 20 -- .../read_global_init.stderr | 15 -- .../wna_wrlx_rrlx.return1234.stderr | 15 -- .../wna_wrlx_rrlx.return42.stderr | 15 -- .../mixed-atomic-non-atomic/wna_wrlx_rrlx.rs | 58 ----- .../basics/mutex/TODO_mutex_get_mut.rs.txt | 0 tests/genmc/pass/basics/mutex/mutex_simple.c | 72 ------ .../mutex/mutex_simple.order12reps1.stderr | 3 - .../mutex/mutex_simple.order12reps2.stderr | 3 - .../mutex/mutex_simple.order21reps1.stderr | 3 - .../mutex/mutex_simple.order21reps2.stderr | 3 - tests/genmc/pass/basics/mutex/mutex_simple.rs | 73 ------ .../basics/rmw/rmw_edge_cases.i16_.stderr | 3 - .../basics/rmw/rmw_edge_cases.i32_.stderr | 3 - .../basics/rmw/rmw_edge_cases.i64_.stderr | 3 - .../pass/basics/rmw/rmw_edge_cases.i8_.stderr | 3 - .../basics/rmw/rmw_edge_cases.isize_.stderr | 3 - tests/genmc/pass/basics/rmw/rmw_edge_cases.rs | 89 ------- .../basics/rmw/rmw_edge_cases.u16_.stderr | 3 - .../basics/rmw/rmw_edge_cases.u32_.stderr | 3 - .../basics/rmw/rmw_edge_cases.u64_.stderr | 3 - .../pass/basics/rmw/rmw_edge_cases.u8_.stderr | 3 - .../basics/rmw/rmw_edge_cases.usize_.stderr | 3 - tests/genmc/pass/basics/rmw/rmw_simple.rs | 29 --- tests/genmc/pass/basics/rmw/rmw_simple.stderr | 3 - .../pass/data-structures/ms_queue_dynamic.rs | 224 ------------------ .../data-structures/ms_queue_dynamic.stderr | 3 - .../data-structures/treiber_stack_dynamic.rs | 211 ----------------- .../treiber_stack_dynamic.stderr | 3 - .../2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr | 3 - .../2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr | 3 - .../pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs | 43 ---- .../litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs | 33 --- .../litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr | 3 - tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs | 33 --- .../pass/litmus/2+2W+4sc/2_2w_4sc.stderr | 3 - .../genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs | 35 --- .../pass/litmus/2+2W+scfs/2_2w_scfs.stderr | 3 - .../pass/litmus/2+2w/2W2W.order12.stderr | 3 - .../pass/litmus/2+2w/2W2W.order21.stderr | 3 - tests/genmc/pass/litmus/2+2w/2W2W.rs | 42 ---- .../pass/litmus/2CoWR/2cowr.order1234.stderr | 3 - .../pass/litmus/2CoWR/2cowr.order2341.stderr | 3 - .../pass/litmus/2CoWR/2cowr.order3412.stderr | 3 - .../pass/litmus/2CoWR/2cowr.order4123.stderr | 3 - .../pass/litmus/2CoWR/2cowr.order4321.stderr | 3 - tests/genmc/pass/litmus/2CoWR/2cowr.rs | 57 ----- .../pass/litmus/CoRR/corr.order12.stderr | 3 - .../pass/litmus/CoRR/corr.order21.stderr | 3 - tests/genmc/pass/litmus/CoRR/corr.rs | 41 ---- .../pass/litmus/CoRR0/corr0.order123.stderr | 3 - .../pass/litmus/CoRR0/corr0.order231.stderr | 3 - .../pass/litmus/CoRR0/corr0.order312.stderr | 3 - .../pass/litmus/CoRR0/corr0.order321.stderr | 3 - tests/genmc/pass/litmus/CoRR0/corr0.rs | 48 ---- .../pass/litmus/CoRR1/corr1.order1234.stderr | 3 - .../pass/litmus/CoRR1/corr1.order2341.stderr | 3 - .../pass/litmus/CoRR1/corr1.order3412.stderr | 3 - .../pass/litmus/CoRR1/corr1.order4123.stderr | 3 - .../pass/litmus/CoRR1/corr1.order4321.stderr | 3 - tests/genmc/pass/litmus/CoRR1/corr1.rs | 57 ----- .../pass/litmus/CoRR2/corr2.order1234.stderr | 3 - .../pass/litmus/CoRR2/corr2.order2341.stderr | 3 - .../pass/litmus/CoRR2/corr2.order3412.stderr | 3 - .../pass/litmus/CoRR2/corr2.order4123.stderr | 3 - .../pass/litmus/CoRR2/corr2.order4321.stderr | 3 - tests/genmc/pass/litmus/CoRR2/corr2.rs | 57 ----- .../pass/litmus/CoRW/corw.order12.stderr | 3 - .../pass/litmus/CoRW/corw.order21.stderr | 3 - tests/genmc/pass/litmus/CoRW/corw.rs | 40 ---- .../pass/litmus/CoWR/cowr.order12.stderr | 3 - .../pass/litmus/CoWR/cowr.order21.stderr | 3 - tests/genmc/pass/litmus/CoWR/cowr.rs | 40 ---- .../pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs | 45 ---- .../litmus/IRIW-acq-sc/IRIW-acq-sc.stderr | 3 - tests/genmc/pass/litmus/IRIWish/IRIWish.rs | 48 ---- .../genmc/pass/litmus/IRIWish/IRIWish.stderr | 3 - .../genmc/pass/litmus/LB+incMPs/LB_incMPs.rs | 48 ---- .../pass/litmus/LB+incMPs/LB_incMPs.stderr | 3 - tests/genmc/pass/litmus/LB/LB.order12.stderr | 3 - tests/genmc/pass/litmus/LB/LB.order21.stderr | 3 - tests/genmc/pass/litmus/LB/LB.rs | 42 ---- .../genmc/pass/litmus/MP+incMPs/MP_incMPs.rs | 41 ---- .../pass/litmus/MP+incMPs/MP_incMPs.stderr | 3 - .../pass/litmus/MP+rels+acqf/MP_rels_acqf.rs | 40 ---- .../litmus/MP+rels+acqf/MP_rels_acqf.stderr | 3 - tests/genmc/pass/litmus/MP/MP.order12.stderr | 3 - tests/genmc/pass/litmus/MP/MP.order21.stderr | 3 - tests/genmc/pass/litmus/MP/MP.rs | 42 ---- .../pass/litmus/MPU+rels+acq/MPU_rels_acq.rs | 43 ---- .../litmus/MPU+rels+acq/MPU_rels_acq.stderr | 3 - .../litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs | 51 ---- .../MPU2+rels+acqf/MPU2_rels_acqf.stderr | 3 - .../pass/litmus/SB+2sc+scf/SB_2sc_scf.rs | 35 --- .../pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr | 3 - tests/genmc/pass/litmus/SB/SB.order12.stderr | 3 - tests/genmc/pass/litmus/SB/SB.order21.stderr | 3 - tests/genmc/pass/litmus/SB/SB.rs | 42 ---- .../pass/litmus/Z6+acq/Z6_acq.order123.stderr | 3 - .../pass/litmus/Z6+acq/Z6_acq.order321.stderr | 3 - tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs | 51 ---- tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs | 40 ---- tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr | 3 - .../pass/litmus/assume-ctrl/assume-ctrl.rs | 42 ---- .../litmus/assume-ctrl/assume-ctrl.stderr | 4 - tests/genmc/pass/litmus/atomicpo/atomicpo.rs | 34 --- .../pass/litmus/atomicpo/atomicpo.stderr | 3 - tests/genmc/pass/litmus/casdep/casdep.rs | 34 --- tests/genmc/pass/litmus/casdep/casdep.stderr | 3 - tests/genmc/pass/litmus/ccr/ccr.rs | 33 --- tests/genmc/pass/litmus/ccr/ccr.stderr | 3 - tests/genmc/pass/litmus/cii/cii.rs | 36 --- tests/genmc/pass/litmus/cii/cii.stderr | 3 - .../litmus/cumul-release/cumul-release.rs | 42 ---- .../litmus/cumul-release/cumul-release.stderr | 3 - .../litmus/default/default.order123.stderr | 3 - .../litmus/default/default.order231.stderr | 3 - .../litmus/default/default.order312.stderr | 3 - .../litmus/default/default.order321.stderr | 3 - tests/genmc/pass/litmus/default/default.rs | 49 ---- tests/genmc/pass/litmus/detour/detour.rs | 42 ---- tests/genmc/pass/litmus/detour/detour.stderr | 3 - .../litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs | 45 ---- .../fr_w_w_w_reads/fr_w_w_w_reads.stderr | 3 - tests/genmc/pass/litmus/inc2w/inc2w.rs | 37 --- tests/genmc/pass/litmus/inc2w/inc2w.stderr | 3 - .../litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs | 63 ----- .../inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr | 3 - tests/genmc/pass/litmus/riwi/riwi.rs | 34 --- tests/genmc/pass/litmus/riwi/riwi.stderr | 3 - .../litmus/viktor-relseq/viktor-relseq.rs | 43 ---- .../litmus/viktor-relseq/viktor-relseq.stderr | 3 - .../simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs | 52 ---- .../simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr | 3 - tests/genmc/pass/simple/2w2w_seqcst.rs | 46 ---- tests/genmc/pass/simple/2w2w_seqcst.stderr | 3 - tests/genmc/pass/simple/atomic_ptr.rs | 83 ------- tests/genmc/pass/simple/atomic_ptr.stderr | 3 - tests/genmc/pass/simple/atomic_simple.rs | 17 -- tests/genmc/pass/simple/atomic_simple.stderr | 3 - tests/genmc/pass/simple/cas_simple.rs | 47 ---- tests/genmc/pass/simple/cas_simple.stderr | 3 - tests/genmc/pass/simple/simple_main.rs | 3 - tests/genmc/pass/simple/simple_main.stderr | 7 - .../pass/simple/simple_main_spawn_threads.rs | 10 - .../simple/simple_main_spawn_threads.stderr | 9 - .../simple/simple_miri_main_spawn_pthreads.rs | 35 --- .../simple_miri_main_spawn_pthreads.stderr | 3 - .../simple/simple_miri_main_spawn_threads.rs | 15 -- .../simple_miri_main_spawn_threads.stderr | 9 - tests/genmc/pass/simple/stack_alloc_atomic.rs | 18 -- .../pass/simple/stack_alloc_atomic.stderr | 3 - tests/genmc/pass/simple/thread_locals.rs | 54 ----- tests/genmc/pass/simple/thread_locals.stderr | 3 - tests/genmc/pass/simple/thread_simple.rs | 34 --- tests/genmc/pass/simple/thread_simple.stderr | 3 - tests/utils-dep/genmc.rs | 27 --- tests/utils-dep/miri_extern.rs | 2 - tests/utils-dep/mod.rs | 8 - tests/utils/miri_extern.rs | 3 - 165 files changed, 3377 deletions(-) delete mode 100644 tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs delete mode 100644 tests/genmc/fail/simple/2w2w_acq_rel.rs delete mode 100644 tests/genmc/fail/simple/2w2w_acq_rel.stderr delete mode 100644 tests/genmc/fail/simple/2w2w_relaxed.rs delete mode 100644 tests/genmc/fail/simple/2w2w_relaxed.stderr delete mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs delete mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr delete mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr delete mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr delete mode 100644 tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs delete mode 100644 tests/genmc/pass/basics/mutex/TODO_mutex_get_mut.rs.txt delete mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.c delete mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr delete mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr delete mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr delete mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr delete mode 100644 tests/genmc/pass/basics/mutex/mutex_simple.rs delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.rs delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr delete mode 100644 tests/genmc/pass/basics/rmw/rmw_simple.rs delete mode 100644 tests/genmc/pass/basics/rmw/rmw_simple.stderr delete mode 100644 tests/genmc/pass/data-structures/ms_queue_dynamic.rs delete mode 100644 tests/genmc/pass/data-structures/ms_queue_dynamic.stderr delete mode 100644 tests/genmc/pass/data-structures/treiber_stack_dynamic.rs delete mode 100644 tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr delete mode 100644 tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr delete mode 100644 tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr delete mode 100644 tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs delete mode 100644 tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs delete mode 100644 tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr delete mode 100644 tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs delete mode 100644 tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr delete mode 100644 tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs delete mode 100644 tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr delete mode 100644 tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr delete mode 100644 tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr delete mode 100644 tests/genmc/pass/litmus/2+2w/2W2W.rs delete mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr delete mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr delete mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr delete mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr delete mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr delete mode 100644 tests/genmc/pass/litmus/2CoWR/2cowr.rs delete mode 100644 tests/genmc/pass/litmus/CoRR/corr.order12.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR/corr.order21.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR/corr.rs delete mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR0/corr0.rs delete mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR1/corr1.rs delete mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr delete mode 100644 tests/genmc/pass/litmus/CoRR2/corr2.rs delete mode 100644 tests/genmc/pass/litmus/CoRW/corw.order12.stderr delete mode 100644 tests/genmc/pass/litmus/CoRW/corw.order21.stderr delete mode 100644 tests/genmc/pass/litmus/CoRW/corw.rs delete mode 100644 tests/genmc/pass/litmus/CoWR/cowr.order12.stderr delete mode 100644 tests/genmc/pass/litmus/CoWR/cowr.order21.stderr delete mode 100644 tests/genmc/pass/litmus/CoWR/cowr.rs delete mode 100644 tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs delete mode 100644 tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr delete mode 100644 tests/genmc/pass/litmus/IRIWish/IRIWish.rs delete mode 100644 tests/genmc/pass/litmus/IRIWish/IRIWish.stderr delete mode 100644 tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs delete mode 100644 tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr delete mode 100644 tests/genmc/pass/litmus/LB/LB.order12.stderr delete mode 100644 tests/genmc/pass/litmus/LB/LB.order21.stderr delete mode 100644 tests/genmc/pass/litmus/LB/LB.rs delete mode 100644 tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs delete mode 100644 tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr delete mode 100644 tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs delete mode 100644 tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr delete mode 100644 tests/genmc/pass/litmus/MP/MP.order12.stderr delete mode 100644 tests/genmc/pass/litmus/MP/MP.order21.stderr delete mode 100644 tests/genmc/pass/litmus/MP/MP.rs delete mode 100644 tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs delete mode 100644 tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr delete mode 100644 tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs delete mode 100644 tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr delete mode 100644 tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs delete mode 100644 tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr delete mode 100644 tests/genmc/pass/litmus/SB/SB.order12.stderr delete mode 100644 tests/genmc/pass/litmus/SB/SB.order21.stderr delete mode 100644 tests/genmc/pass/litmus/SB/SB.rs delete mode 100644 tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr delete mode 100644 tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr delete mode 100644 tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs delete mode 100644 tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs delete mode 100644 tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr delete mode 100644 tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs delete mode 100644 tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr delete mode 100644 tests/genmc/pass/litmus/atomicpo/atomicpo.rs delete mode 100644 tests/genmc/pass/litmus/atomicpo/atomicpo.stderr delete mode 100644 tests/genmc/pass/litmus/casdep/casdep.rs delete mode 100644 tests/genmc/pass/litmus/casdep/casdep.stderr delete mode 100644 tests/genmc/pass/litmus/ccr/ccr.rs delete mode 100644 tests/genmc/pass/litmus/ccr/ccr.stderr delete mode 100644 tests/genmc/pass/litmus/cii/cii.rs delete mode 100644 tests/genmc/pass/litmus/cii/cii.stderr delete mode 100644 tests/genmc/pass/litmus/cumul-release/cumul-release.rs delete mode 100644 tests/genmc/pass/litmus/cumul-release/cumul-release.stderr delete mode 100644 tests/genmc/pass/litmus/default/default.order123.stderr delete mode 100644 tests/genmc/pass/litmus/default/default.order231.stderr delete mode 100644 tests/genmc/pass/litmus/default/default.order312.stderr delete mode 100644 tests/genmc/pass/litmus/default/default.order321.stderr delete mode 100644 tests/genmc/pass/litmus/default/default.rs delete mode 100644 tests/genmc/pass/litmus/detour/detour.rs delete mode 100644 tests/genmc/pass/litmus/detour/detour.stderr delete mode 100644 tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs delete mode 100644 tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr delete mode 100644 tests/genmc/pass/litmus/inc2w/inc2w.rs delete mode 100644 tests/genmc/pass/litmus/inc2w/inc2w.stderr delete mode 100644 tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs delete mode 100644 tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr delete mode 100644 tests/genmc/pass/litmus/riwi/riwi.rs delete mode 100644 tests/genmc/pass/litmus/riwi/riwi.stderr delete mode 100644 tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs delete mode 100644 tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr delete mode 100644 tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs delete mode 100644 tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr delete mode 100644 tests/genmc/pass/simple/2w2w_seqcst.rs delete mode 100644 tests/genmc/pass/simple/2w2w_seqcst.stderr delete mode 100644 tests/genmc/pass/simple/atomic_ptr.rs delete mode 100644 tests/genmc/pass/simple/atomic_ptr.stderr delete mode 100644 tests/genmc/pass/simple/atomic_simple.rs delete mode 100644 tests/genmc/pass/simple/atomic_simple.stderr delete mode 100644 tests/genmc/pass/simple/cas_simple.rs delete mode 100644 tests/genmc/pass/simple/cas_simple.stderr delete mode 100644 tests/genmc/pass/simple/simple_main.rs delete mode 100644 tests/genmc/pass/simple/simple_main.stderr delete mode 100644 tests/genmc/pass/simple/simple_main_spawn_threads.rs delete mode 100644 tests/genmc/pass/simple/simple_main_spawn_threads.stderr delete mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs delete mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr delete mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs delete mode 100644 tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr delete mode 100644 tests/genmc/pass/simple/stack_alloc_atomic.rs delete mode 100644 tests/genmc/pass/simple/stack_alloc_atomic.stderr delete mode 100644 tests/genmc/pass/simple/thread_locals.rs delete mode 100644 tests/genmc/pass/simple/thread_locals.stderr delete mode 100644 tests/genmc/pass/simple/thread_simple.rs delete mode 100644 tests/genmc/pass/simple/thread_simple.stderr delete mode 100644 tests/utils-dep/genmc.rs delete mode 100644 tests/utils-dep/miri_extern.rs delete mode 100644 tests/utils-dep/mod.rs diff --git a/tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs b/tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs deleted file mode 100644 index ef06bbfd0c..0000000000 --- a/tests/genmc/_disabled/fail/weak_memory/weak_uninit.rs +++ /dev/null @@ -1,57 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -// NOTE: Disabled due to incomplete uninitialized memory support in Miri-GenMC mode. - -// Tests showing weak memory behaviours are exhibited. All tests -// return true when the desired behaviour is seen. -// This is scheduler and pseudo-RNG dependent, so each test is -// run multiple times until one try returns true. -// Spurious failure is possible, if you are really unlucky with -// the RNG and always read the latest value from the store buffer. - -#![no_main] - -#[path = "../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::mem::MaybeUninit; -use std::sync::atomic::*; - -use crate::utils_dep::*; - -#[allow(dead_code)] -#[derive(Copy, Clone)] -struct EvilSend(pub T); - -unsafe impl Send for EvilSend {} -unsafe impl Sync for EvilSend {} - -static mut F: MaybeUninit = MaybeUninit::uninit(); - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - unsafe { - let x = AtomicUsize::from_ptr(&raw mut F as *mut usize); - x.store(1, Ordering::Relaxed); - std::ptr::null_mut() - } -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - unsafe { - let x = AtomicUsize::from_ptr(&raw mut F as *mut usize); - x.load(Ordering::Relaxed); //~ERROR: using uninitialized data - std::ptr::null_mut() - } -} - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - // Unlike with the non-GenMC version of this test, we should only need 1 iteration to detect the bug: - unsafe { - let ids = create_pthreads_no_params([thread_1, thread_2]); - join_pthreads(ids); - } - - 0 -} diff --git a/tests/genmc/fail/simple/2w2w_acq_rel.rs b/tests/genmc/fail/simple/2w2w_acq_rel.rs deleted file mode 100644 index 586bdd0428..0000000000 --- a/tests/genmc/fail/simple/2w2w_acq_rel.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use libc::{self, pthread_attr_t, pthread_t}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -const LOAD_ORD: Ordering = Ordering::Acquire; -const STORE_ORD: Ordering = Ordering::Release; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let mut thread_id: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - let ret_create = unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }; - assert!(ret_create == 0); - - X.store(1, STORE_ORD); - Y.store(2, STORE_ORD); - - let ret_join = unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }; - assert!(ret_join == 0); - - let x = X.load(LOAD_ORD); - let y = Y.load(LOAD_ORD); - if x == 1 && y == 1 { - unsafe { std::hint::unreachable_unchecked() }; //~ ERROR: entering unreachable code - } - 0 -} - -extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { - Y.store(1, STORE_ORD); - X.store(2, STORE_ORD); - std::ptr::null_mut() -} diff --git a/tests/genmc/fail/simple/2w2w_acq_rel.stderr b/tests/genmc/fail/simple/2w2w_acq_rel.stderr deleted file mode 100644 index c05a405cfe..0000000000 --- a/tests/genmc/fail/simple/2w2w_acq_rel.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/genmc/fail/simple/2w2w_acq_rel.rs:LL:CC - | -LL | unsafe { std::hint::unreachable_unchecked() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_acq_rel.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/tests/genmc/fail/simple/2w2w_relaxed.rs b/tests/genmc/fail/simple/2w2w_relaxed.rs deleted file mode 100644 index d01780e375..0000000000 --- a/tests/genmc/fail/simple/2w2w_relaxed.rs +++ /dev/null @@ -1,44 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use libc::{self, pthread_attr_t, pthread_t}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -const LOAD_ORD: Ordering = Ordering::Relaxed; -const STORE_ORD: Ordering = Ordering::Relaxed; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let mut thread_id: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - let ret_create = unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }; - assert!(ret_create == 0); - - X.store(1, STORE_ORD); - Y.store(2, STORE_ORD); - - let ret_join = unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }; - assert!(ret_join == 0); - - let x = X.load(LOAD_ORD); - let y = Y.load(LOAD_ORD); - if x == 1 && y == 1 { - unsafe { std::hint::unreachable_unchecked() }; //~ ERROR: entering unreachable code - } - 0 -} - -extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { - Y.store(1, STORE_ORD); - X.store(2, STORE_ORD); - std::ptr::null_mut() -} diff --git a/tests/genmc/fail/simple/2w2w_relaxed.stderr b/tests/genmc/fail/simple/2w2w_relaxed.stderr deleted file mode 100644 index 93ddf7de53..0000000000 --- a/tests/genmc/fail/simple/2w2w_relaxed.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/genmc/fail/simple/2w2w_relaxed.rs:LL:CC - | -LL | unsafe { std::hint::unreachable_unchecked() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `miri_start` at tests/genmc/fail/simple/2w2w_relaxed.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs b/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs deleted file mode 100644 index c244f5bf81..0000000000 --- a/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(1234); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - // TODO GENMC: make this a "pass" test - if 1234 != unsafe { *X.as_ptr() } { - unsafe { std::hint::unreachable_unchecked() }; - } - if 1234 == X.load(Ordering::SeqCst) { - unsafe { std::hint::unreachable_unchecked() }; //~ ERROR: entering unreachable code - } - - 0 -} diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr b/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr deleted file mode 100644 index ec779aa7c4..0000000000 --- a/tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs:LL:CC - | -LL | unsafe { std::hint::unreachable_unchecked() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `miri_start` at tests/genmc/fail/simple/mixed-atomic-non-atomic/read_global_init.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr deleted file mode 100644 index 28a8b74c86..0000000000 --- a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return1234.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC - | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside `read_relaxed` at tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr deleted file mode 100644 index 28a8b74c86..0000000000 --- a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.return42.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC - | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE on thread `unnamed-ID`: - = note: inside `read_relaxed` at tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs b/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs deleted file mode 100644 index 0ebac090ad..0000000000 --- a/tests/genmc/fail/simple/mixed-atomic-non-atomic/wna_wrlx_rrlx.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@compile-flags: -Zmiri-genmc -//@revisions: return1234 return42 - -#![no_main] - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use libc::{self, pthread_attr_t, pthread_t}; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let mut t0: pthread_t = 0; - let mut t1: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - - let mut x: AtomicU64 = AtomicU64::new(1); - *x.get_mut() = 42; - // x.store(42, STORE_ORD); - - let value: *mut c_void = x.as_ptr() as *mut c_void; - - assert!(0 == unsafe { libc::pthread_create(&raw mut t0, attr, read_relaxed, value) }); - assert!(0 == unsafe { libc::pthread_create(&raw mut t1, attr, write_relaxed, value) }); - - assert!(0 == unsafe { libc::pthread_join(t0, std::ptr::null_mut()) }); - assert!(0 == unsafe { libc::pthread_join(t1, std::ptr::null_mut()) }); - - 0 -} - -extern "C" fn read_relaxed(value: *mut c_void) -> *mut c_void { - unsafe { - let x = (value as *const AtomicU64).as_ref().unwrap(); - let val = x.load(Ordering::Relaxed); - - let mut flag = false; - if cfg!(return1234) && 1234 == val { - flag = true; - } - if cfg!(return42) && 42 == val { - flag = true; - } - if flag { - std::hint::unreachable_unchecked(); //~ ERROR: entering unreachable code - } - std::ptr::null_mut() - } -} - -extern "C" fn write_relaxed(value: *mut c_void) -> *mut c_void { - unsafe { - let x = (value as *const AtomicU64).as_ref().unwrap(); - x.store(1234, Ordering::Relaxed); - std::ptr::null_mut() - } -} diff --git a/tests/genmc/pass/basics/mutex/TODO_mutex_get_mut.rs.txt b/tests/genmc/pass/basics/mutex/TODO_mutex_get_mut.rs.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.c b/tests/genmc/pass/basics/mutex/mutex_simple.c deleted file mode 100644 index eb9c87aa82..0000000000 --- a/tests/genmc/pass/basics/mutex/mutex_simple.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include -#include - -#define REPS 1 - -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -static uint64_t data[32]; - -void* thread_1(void* arg) { - for (uint64_t i = 0; i < REPS; i++) { - pthread_mutex_lock(&lock); - data[0] += 2; - pthread_mutex_unlock(&lock); - } - return NULL; -} - -void* thread_2(void* arg) { - for (uint64_t i = 0; i < REPS; i++) { - pthread_mutex_lock(&lock); - data[0] += 4; - pthread_mutex_unlock(&lock); - } - return NULL; -} - -int main(int argc, char** argv) { - // Initialize data - for (int i = 0; i < 32; i++) { - data[i] = 1234; - } - - pthread_mutex_lock(&lock); - for (int i = 0; i < 32; i++) { - assert(data[i] == 1234); - } - data[0] = 0; - data[1] = 10; - assert(data[0] == 0 && data[1] == 10); - pthread_mutex_unlock(&lock); - - // Thread order: can be changed for different test orders -#ifdef ORDER21 - void* (*thread_order[2])(void*) = {thread_2, thread_1}; -#else - void* (*thread_order[2])(void*) = {thread_1, thread_2}; -#endif - - pthread_t ids[2]; - for (int i = 0; i < 2; i++) { - int ret = pthread_create(&ids[i], NULL, thread_order[i], NULL); - assert(ret == 0); - } - - for (int i = 0; i < 2; i++) { - int ret = pthread_join(ids[i], NULL); - assert(ret == 0); - } - - pthread_mutex_lock(&lock); - // assert(data[0] == REPS * 6); // Not checked, but can be enabled - assert(data[1] == 10); - for (int i = 2; i < 32; i++) { - assert(data[i] == 1234); - } - pthread_mutex_unlock(&lock); - - return 0; -} diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr deleted file mode 100644 index edecd38278..0000000000 --- a/tests/genmc/pass/basics/mutex/mutex_simple.order12reps1.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr deleted file mode 100644 index e4151d346e..0000000000 --- a/tests/genmc/pass/basics/mutex/mutex_simple.order12reps2.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr deleted file mode 100644 index edecd38278..0000000000 --- a/tests/genmc/pass/basics/mutex/mutex_simple.order21reps1.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr b/tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr deleted file mode 100644 index e4151d346e..0000000000 --- a/tests/genmc/pass/basics/mutex/mutex_simple.order21reps2.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 diff --git a/tests/genmc/pass/basics/mutex/mutex_simple.rs b/tests/genmc/pass/basics/mutex/mutex_simple.rs deleted file mode 100644 index 1c91126316..0000000000 --- a/tests/genmc/pass/basics/mutex/mutex_simple.rs +++ /dev/null @@ -1,73 +0,0 @@ -//@compile-flags: -Zmiri-genmc -//@revisions: order12reps1 order21reps1 order12reps2 order21reps2 - -#![no_main] -#![feature(abort_unwind)] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::Mutex; - -use crate::utils_dep::*; - -#[cfg(not(any(order12reps2, order21reps2)))] -const REPS: u64 = 1; -#[cfg(any(order12reps2, order21reps2))] -const REPS: u64 = 2; - -static LOCK: Mutex<[u64; 32]> = Mutex::new([1234; 32]); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - std::panic::abort_unwind(main_); - 0 -} - -fn main_() { - let mut guard = LOCK.lock().unwrap(); - for &v in guard.iter() { - assert!(v == 1234); // Check that mutex values are initialized correctly - } - guard[0] = 0; - guard[1] = 10; - assert!(guard[0] == 0 && guard[1] == 10); // Check if changes are accepted - - assert!(LOCK.try_lock().is_err()); // Trying to lock should fail if the lock is already held - - drop(guard); // Dropping the guard should unlock the mutex correctly. - { - assert!(LOCK.try_lock().is_ok()); // Trying to lock now should *not* fail since the lock is not held. - } - - // Thread spawning order should not matter for the result - let thread_order = if cfg!(order21) { [thread_2, thread_1] } else { [thread_1, thread_2] }; - // let thread_order = [thread_1 as extern "C" fn(*mut libc::c_void) -> *mut libc::c_void]; - let ids = unsafe { create_pthreads_no_params(thread_order) }; - unsafe { join_pthreads(ids) }; - - let guard = LOCK.lock().unwrap(); - assert!(guard[0] == REPS * 6); // Due to locking, no weird values should be here - assert!(guard[1] == 10); // Rest should be unchanged - for &v in guard.iter().skip(2) { - assert!(v == 1234); - } - drop(guard); -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - for _ in 0..REPS { - let mut guard = LOCK.lock().unwrap(); - guard[0] += 2; - } - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - for _ in 0..REPS { - let mut guard = LOCK.lock().unwrap(); - guard[0] += 4; - } - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i16_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i32_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i64_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.i8_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.isize_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.rs b/tests/genmc/pass/basics/rmw/rmw_edge_cases.rs deleted file mode 100644 index 4bb98caf03..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.rs +++ /dev/null @@ -1,89 +0,0 @@ -//@compile-flags: -Zmiri-genmc -//@revisions: u8_ u16_ u32_ u64_ usize_ i8_ i16_ i32_ i64_ isize_ - -// FIXME(genmc): ensure that 64 bit tests don't run on platforms without 64 bit atomics -// FIXME(genmc): add 128 bit tests for platforms that support it, once GenMC gets 128 bit atomic support - -// This test check for correct handling of some edge cases with atomic read-modify-write operations for all integer sizes. -// Atomic max and min should return the previous value, and store the result in the atomic. -// Atomic addition and subtraction should have wrapping semantics. - -#![no_main] - -#[cfg(u8_)] -type Int = u8; -#[cfg(u8_)] -type AtomicInt = AtomicU8; - -#[cfg(u16_)] -type Int = u16; -#[cfg(u16_)] -type AtomicInt = AtomicU16; - -#[cfg(u32_)] -type Int = u32; -#[cfg(u32_)] -type AtomicInt = AtomicU32; - -#[cfg(u64_)] -type Int = u64; -#[cfg(u64_)] -type AtomicInt = AtomicU64; - -#[cfg(usize_)] -type Int = usize; -#[cfg(usize_)] -type AtomicInt = AtomicUsize; - - -#[cfg(i8_)] -type Int = i8; -#[cfg(i8_)] -type AtomicInt = AtomicI8; - -#[cfg(i16_)] -type Int = i16; -#[cfg(i16_)] -type AtomicInt = AtomicI16; - -#[cfg(i32_)] -type Int = i32; -#[cfg(i32_)] -type AtomicInt = AtomicI32; - -#[cfg(i64_)] -type Int = i64; -#[cfg(i64_)] -type AtomicInt = AtomicI64; - -#[cfg(isize_)] -type Int = isize; -#[cfg(isize_)] -type AtomicInt = AtomicIsize; - -use std::sync::atomic::*; - -const ORD: Ordering = Ordering::SeqCst; - -fn assert_eq(x: T, y: T) { - if x != y { - std::process::abort(); - } -} - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let x = AtomicInt::new(123); - assert_eq(123, x.fetch_max(0, ORD)); // `max` keeps existing value - assert_eq(123, x.fetch_max(Int::MAX, ORD)); // `max` stores the new value - assert_eq(Int::MAX, x.fetch_add(10, ORD)); // `fetch_add` should be wrapping - assert_eq(Int::MAX.wrapping_add(10), x.load(ORD)); - - x.store(42, ORD); - assert_eq(42, x.fetch_min(Int::MAX, ORD)); // `max` keeps existing value - assert_eq(42, x.fetch_min(Int::MIN, ORD)); // `max` stores the new value - assert_eq(Int::MIN, x.fetch_sub(10, ORD)); // `fetch_sub` should be wrapping - assert_eq(Int::MIN.wrapping_sub(10), x.load(ORD)); - - 0 -} diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u16_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u32_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u64_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.u8_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr b/tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_edge_cases.usize_.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/basics/rmw/rmw_simple.rs b/tests/genmc/pass/basics/rmw/rmw_simple.rs deleted file mode 100644 index 2f72ea2c4d..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_simple.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::sync::atomic::*; - -static VALUE: AtomicUsize = AtomicUsize::new(0); - -const ORD: Ordering = Ordering::SeqCst; - -fn assert_eq(x: usize, y: usize) { - if x != y { - std::process::abort(); - } -} - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - VALUE.store(1, ORD); - - assert_eq(1, VALUE.fetch_add(7, ORD)); - assert_eq(8, VALUE.fetch_sub(2, ORD)); - assert_eq(6, VALUE.fetch_max(16, ORD)); - assert_eq(16, VALUE.fetch_min(4, ORD)); - assert_eq(4, VALUE.swap(42, ORD)); - - assert_eq(42, VALUE.load(ORD)); - 0 -} diff --git a/tests/genmc/pass/basics/rmw/rmw_simple.stderr b/tests/genmc/pass/basics/rmw/rmw_simple.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/basics/rmw/rmw_simple.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/data-structures/ms_queue_dynamic.rs b/tests/genmc/pass/data-structures/ms_queue_dynamic.rs deleted file mode 100644 index a30c3957df..0000000000 --- a/tests/genmc/pass/data-structures/ms_queue_dynamic.rs +++ /dev/null @@ -1,224 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -// TODO GENMC: maybe use `-Zmiri-genmc-symmetry-reduction`? -// TODO GENMC: investigate why `-Zmiri-ignore-leaks ` is required - -#![no_main] -#![allow(static_mut_refs)] -#![allow(unused)] - -use std::alloc::{Layout, alloc, dealloc}; -use std::ffi::c_void; -use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicPtr, AtomicU64}; - -use libc::{self, pthread_attr_t, pthread_t}; - -const MAX_THREADS: usize = 32; - -const POISON_IDX: u64 = 0xAAAABBBBBBBBAAAA; - -static mut QUEUE: MyStack = MyStack::new(); -static mut PARAMS: [u64; MAX_THREADS] = [POISON_IDX; MAX_THREADS]; -static mut INPUT: [u64; MAX_THREADS] = [POISON_IDX; MAX_THREADS]; -static mut OUTPUT: [Option; MAX_THREADS] = [None; MAX_THREADS]; -static mut THREADS: [pthread_t; MAX_THREADS] = [0; MAX_THREADS]; - -#[repr(C)] -struct Node { - value: u64, - next: AtomicPtr, -} - -struct MyStack { - head: AtomicPtr, - tail: AtomicPtr, -} - -impl Node { - pub unsafe fn new_alloc() -> *mut Self { - alloc(Layout::new::()) as *mut Self - } - - pub unsafe fn free(node: *mut Self) { - dealloc(node as *mut u8, Layout::new::()) - } - - pub unsafe fn reclaim(_node: *mut Self) { - // __VERIFIER_hp_retire(node); - } -} - -impl MyStack { - pub const fn new() -> Self { - let head = AtomicPtr::new(std::ptr::null_mut()); - let tail = AtomicPtr::new(std::ptr::null_mut()); - Self { head, tail } - } - - pub unsafe fn init_queue(&mut self, _num_threads: usize) { - /* initialize queue */ - let mut dummy = Node::new_alloc(); - - (*dummy).next = AtomicPtr::new(std::ptr::null_mut()); - self.head = AtomicPtr::new(dummy); - self.tail = AtomicPtr::new(dummy); - } - - pub unsafe fn clear_queue(&mut self, _num_threads: usize) { - let mut next; - let mut head = *self.head.get_mut(); - while !head.is_null() { - next = *(*head).next.get_mut(); - Node::free(head); - head = next; - } - } - - pub unsafe fn enqueue(&self, value: u64) { - let mut tail; - let node = Node::new_alloc(); - (*node).value = value; - (*node).next = AtomicPtr::new(std::ptr::null_mut()); - - loop { - tail = self.tail.load(Acquire); - let next = (*tail).next.load(Acquire); - if tail != self.tail.load(Acquire) { - continue; - } - - if next.is_null() { - // TODO GENMC: what if anything has to be done for `__VERIFIER_final_CAS`? - if (*tail).next.compare_exchange(next, node, Release, Relaxed).is_ok() { - break; - } - } else { - // TODO GENMC: what if anything has to be done for `__VERIFIER_helping_CAS`? - let _ = self.tail.compare_exchange(tail, next, Release, Relaxed); - } - } - - // TODO GENMC: what if anything has to be done for `__VERIFIER_helped_CAS`? - let _ = self.tail.compare_exchange(tail, node, Release, Relaxed); - } - - pub unsafe fn dequeue(&self) -> Option { - loop { - let head = self.head.load(Acquire); - let tail = self.tail.load(Acquire); - - let next_ref = &(*head).next; - let next = next_ref.load(Acquire); - if self.head.load(Acquire) != head { - continue; - } - if head == tail { - if next.is_null() { - return None; - } - let _ = self.tail.compare_exchange(tail, next, Release, Relaxed); - } else { - let ret_val = (*next).value; - if self.head.compare_exchange(head, next, Release, Relaxed).is_ok() { - // reclaim(head); - // __VERIFIER_hp_free(hp_head); - // __VERIFIER_hp_free(hp_next); - return Some(ret_val); - } - } - } - } -} - -extern "C" fn thread_w(value: *mut c_void) -> *mut c_void { - unsafe { - let pid = *(value as *mut u64); - - INPUT[pid as usize] = pid * 10; - QUEUE.enqueue(INPUT[pid as usize]); - - std::ptr::null_mut() - } -} - -extern "C" fn thread_r(value: *mut c_void) -> *mut c_void { - unsafe { - let pid = *(value as *mut u64); - - OUTPUT[pid as usize] = QUEUE.dequeue(); - - std::ptr::null_mut() - } -} - -extern "C" fn thread_rw(value: *mut c_void) -> *mut c_void { - unsafe { - let pid = *(value as *mut u64); - - INPUT[pid as usize] = pid * 10; - QUEUE.enqueue(INPUT[pid as usize]); - - OUTPUT[pid as usize] = QUEUE.dequeue(); - - std::ptr::null_mut() - } -} - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let attr: *const pthread_attr_t = std::ptr::null(); - - // TODO GENMC (TESTS): make different tests: - let readers = 0; - let writers = 0; - let rdwr = 2; - - let num_threads = readers + writers + rdwr; - - if num_threads > MAX_THREADS { - std::process::abort(); - } - - let mut i = 0; - unsafe { - MyStack::init_queue(&mut QUEUE, num_threads); - - for j in 0..num_threads { - PARAMS[j] = j as u64; - } - - /* Spawn threads */ - for _ in 0..writers { - let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; - if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_w, value) { - std::process::abort(); - } - i += 1; - } - for _ in 0..readers { - let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; - if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_r, value) { - std::process::abort(); - } - i += 1; - } - for _ in 0..rdwr { - let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; - if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_rw, value) { - std::process::abort(); - } - i += 1; - } - - for i in 0..num_threads { - if 0 != libc::pthread_join(THREADS[i], std::ptr::null_mut()) { - std::process::abort(); - } - } - - MyStack::clear_queue(&mut QUEUE, num_threads); - } - - 0 -} diff --git a/tests/genmc/pass/data-structures/ms_queue_dynamic.stderr b/tests/genmc/pass/data-structures/ms_queue_dynamic.stderr deleted file mode 100644 index 2ed05b58e8..0000000000 --- a/tests/genmc/pass/data-structures/ms_queue_dynamic.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 222 diff --git a/tests/genmc/pass/data-structures/treiber_stack_dynamic.rs b/tests/genmc/pass/data-structures/treiber_stack_dynamic.rs deleted file mode 100644 index ba188aa270..0000000000 --- a/tests/genmc/pass/data-structures/treiber_stack_dynamic.rs +++ /dev/null @@ -1,211 +0,0 @@ -//@compile-flags: -Zmiri-genmc -Zmiri-ignore-leaks - -// TODO GENMC: maybe use `-Zmiri-genmc-symmetry-reduction`? - -#![no_main] -#![allow(static_mut_refs)] -#![allow(unused)] - -use std::alloc::{Layout, alloc, dealloc}; -use std::ffi::c_void; -use std::sync::atomic::{AtomicPtr, AtomicU64, Ordering}; - -use libc::{self, pthread_attr_t, pthread_t}; - -const MAX_THREADS: usize = 32; - -const MAX_NODES: usize = 0xFF; - -const POISON_IDX: u64 = 0xDEADBEEF; - -// TODO GENMC: thread local (for GenMC hazard pointer API) -// static mut TID: u64 = POISON_IDX; - -static mut STACK: MyStack = MyStack::new(); -static mut THREADS: [pthread_t; MAX_THREADS] = [0; MAX_THREADS]; -static mut PARAMS: [u64; MAX_THREADS] = [POISON_IDX; MAX_THREADS]; - -unsafe fn set_thread_num(_i: u64) { - // TID = i; -} - -#[allow(unused)] // TODO GENMC: what is the purpose of this in the GenMC version? -unsafe fn get_thread_num() -> u64 { - // TID - todo!() -} - -#[repr(C)] -struct Node { - value: u64, - next: AtomicPtr, -} - -struct MyStack { - top: AtomicPtr, -} - -impl Node { - pub unsafe fn new_alloc() -> *mut Self { - alloc(Layout::new::()) as *mut Self - } - - pub unsafe fn free(node: *mut Self) { - dealloc(node as *mut u8, Layout::new::()) - } - - pub unsafe fn reclaim(_node: *mut Self) { - // __VERIFIER_hp_retire(node); - } -} - -impl MyStack { - pub const fn new() -> Self { - Self { top: AtomicPtr::new(std::ptr::null_mut()) } - } - - pub unsafe fn init_stack(&mut self, _num_threads: usize) { - self.top = AtomicPtr::new(std::ptr::null_mut()); - } - - pub unsafe fn clear_stack(&mut self, _num_threads: usize) { - let mut next; - let mut top = *self.top.get_mut(); - while !top.is_null() { - next = *(*top).next.get_mut(); - Node::free(top); - top = next; - } - } - - pub unsafe fn push(&self, value: u64) { - let node = Node::new_alloc(); - (*node).value = value; - - loop { - let top = self.top.load(Ordering::Acquire); - (*node).next.store(top, Ordering::Relaxed); - if self.top.compare_exchange(top, node, Ordering::Release, Ordering::Relaxed).is_ok() { - break; - } - } - } - - pub unsafe fn pop(&self) -> u64 { - let mut top; - - // TODO GENMC: enable if GenMC hazard pointer API is implemented in MIRI - // __VERIFIER_hp_t *hp = __VERIFIER_hp_alloc(); - loop { - top = STACK.top.load(Ordering::Acquire); - // top = __VERIFIER_hp_protect(hp, &s->top); - if top.is_null() { - // __VERIFIER_hp_free(hp); - return 0; - } - - let next = (*top).next.load(Ordering::Relaxed); - if self.top.compare_exchange(top, next, Ordering::Release, Ordering::Relaxed).is_ok() { - break; - } - } - - let value = (*top).value; - /* Reclaim the used slot */ - // Node::reclaim(top); - // Node::free(top); - // __VERIFIER_hp_free(hp); - return value; - } -} - -extern "C" fn thread_w(value: *mut c_void) -> *mut c_void { - unsafe { - let pid = *(value as *mut u64); - set_thread_num(pid); - - STACK.push(pid); - - std::ptr::null_mut() - } -} - -extern "C" fn thread_r(value: *mut c_void) -> *mut c_void { - unsafe { - let pid = *(value as *mut u64); - set_thread_num(pid); - - let _idx = STACK.pop(); - - std::ptr::null_mut() - } -} - -extern "C" fn thread_rw(value: *mut c_void) -> *mut c_void { - unsafe { - let pid = *(value as *mut u64); - set_thread_num(pid); - - STACK.push(pid); - - let _idx = STACK.pop(); - - std::ptr::null_mut() - } -} - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let attr: *const pthread_attr_t = std::ptr::null(); - - // TODO GENMC: make different tests: - let readers = 1; - let writers = 2; - let rdwr = 0; - - let num_threads = readers + writers + rdwr; - - if num_threads > MAX_THREADS { - std::process::abort(); - } - - let mut i = 0; - unsafe { - MyStack::init_stack(&mut STACK, num_threads); - - for j in 0..num_threads { - PARAMS[j] = j as u64; - } - for _ in 0..readers { - let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; - if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_r, value) { - std::process::abort(); - } - i += 1; - } - for _ in 0..writers { - let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; - if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_w, value) { - std::process::abort(); - } - i += 1; - } - for _ in 0..rdwr { - let value: *mut c_void = (&raw mut PARAMS[i]) as *mut c_void; - if 0 != libc::pthread_create(&raw mut THREADS[i], attr, thread_rw, value) { - std::process::abort(); - } - i += 1; - } - - for i in 0..num_threads { - if 0 != libc::pthread_join(THREADS[i], std::ptr::null_mut()) { - std::process::abort(); - } - } - - MyStack::clear_stack(&mut STACK, num_threads); - } - - 0 -} diff --git a/tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr b/tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr deleted file mode 100644 index fbd9adb20b..0000000000 --- a/tests/genmc/pass/data-structures/treiber_stack_dynamic.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 22 diff --git a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs b/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs deleted file mode 100644 index be549401c7..0000000000 --- a/tests/genmc/pass/litmus/2+2W+2sc+scf/2w2w_2sc_scf.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - Y.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - X.store(2, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs b/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs deleted file mode 100644 index 4c2af1b5e9..0000000000 --- a/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - Y.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Release); - X.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr b/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs b/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs deleted file mode 100644 index dc6616d37e..0000000000 --- a/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - Y.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::SeqCst); - X.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr b/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/2+2W+4sc/2_2w_4sc.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs b/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs deleted file mode 100644 index db29ab9f84..0000000000 --- a/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - Y.store(2, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - X.store(2, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr b/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/2+2W+scfs/2_2w_scfs.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr b/tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2+2w/2W2W.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr b/tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2+2w/2W2W.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2+2w/2W2W.rs b/tests/genmc/pass/litmus/2+2w/2W2W.rs deleted file mode 100644 index 712e55ed9b..0000000000 --- a/tests/genmc/pass/litmus/2+2w/2W2W.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Release); - X.store(2, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Release); - X.store(2, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2CoWR/2cowr.order1234.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2CoWR/2cowr.order2341.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2CoWR/2cowr.order3412.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2CoWR/2cowr.order4123.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr b/tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/2CoWR/2cowr.order4321.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/2CoWR/2cowr.rs b/tests/genmc/pass/litmus/2CoWR/2cowr.rs deleted file mode 100644 index 2fd4abc528..0000000000 --- a/tests/genmc/pass/litmus/2CoWR/2cowr.rs +++ /dev/null @@ -1,57 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order1234 order2341 order3412 order4123 order4321 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::ptr::null_mut; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order1234) { - [thread_1, thread_2, thread_3, thread_4] - } else if cfg!(order2341) { - [thread_2, thread_3, thread_4, thread_1] - } else if cfg!(order3412) { - [thread_3, thread_4, thread_1, thread_2] - } else if cfg!(order4123) { - [thread_4, thread_1, thread_2, thread_3] - } else if cfg!(order4321) { - [thread_4, thread_3, thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - null_mut() -} - -pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - null_mut() -} - -pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - null_mut() -} - -pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Release); - null_mut() -} diff --git a/tests/genmc/pass/litmus/CoRR/corr.order12.stderr b/tests/genmc/pass/litmus/CoRR/corr.order12.stderr deleted file mode 100644 index e4151d346e..0000000000 --- a/tests/genmc/pass/litmus/CoRR/corr.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/CoRR/corr.order21.stderr b/tests/genmc/pass/litmus/CoRR/corr.order21.stderr deleted file mode 100644 index e4151d346e..0000000000 --- a/tests/genmc/pass/litmus/CoRR/corr.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/CoRR/corr.rs b/tests/genmc/pass/litmus/CoRR/corr.rs deleted file mode 100644 index 3159d3e566..0000000000 --- a/tests/genmc/pass/litmus/CoRR/corr.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - X.store(2, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/CoRR0/corr0.order123.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/CoRR0/corr0.order231.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/CoRR0/corr0.order312.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr b/tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/CoRR0/corr0.order321.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/CoRR0/corr0.rs b/tests/genmc/pass/litmus/CoRR0/corr0.rs deleted file mode 100644 index edf949b5e6..0000000000 --- a/tests/genmc/pass/litmus/CoRR0/corr0.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order123 order321 order312 order231 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order123) { - [thread_1, thread_2, thread_3] - } else if cfg!(order321) { - [thread_3, thread_2, thread_1] - } else if cfg!(order312) { - [thread_3, thread_1, thread_2] - } else if cfg!(order231) { - [thread_2, thread_3, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr deleted file mode 100644 index c2ffa8ec3c..0000000000 --- a/tests/genmc/pass/litmus/CoRR1/corr1.order1234.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr deleted file mode 100644 index c2ffa8ec3c..0000000000 --- a/tests/genmc/pass/litmus/CoRR1/corr1.order2341.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr deleted file mode 100644 index c2ffa8ec3c..0000000000 --- a/tests/genmc/pass/litmus/CoRR1/corr1.order3412.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr deleted file mode 100644 index c2ffa8ec3c..0000000000 --- a/tests/genmc/pass/litmus/CoRR1/corr1.order4123.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr b/tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr deleted file mode 100644 index c2ffa8ec3c..0000000000 --- a/tests/genmc/pass/litmus/CoRR1/corr1.order4321.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/CoRR1/corr1.rs b/tests/genmc/pass/litmus/CoRR1/corr1.rs deleted file mode 100644 index acc1a3d7ff..0000000000 --- a/tests/genmc/pass/litmus/CoRR1/corr1.rs +++ /dev/null @@ -1,57 +0,0 @@ -//@compile-flags: -Zmiri-genmc -//@revisions: order1234 order4321 order4123 order3412 order2341 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order1234) { - [thread_1, thread_2, thread_3, thread_4] - } else if cfg!(order4321) { - [thread_4, thread_3, thread_2, thread_1] - } else if cfg!(order4123) { - [thread_4, thread_1, thread_2, thread_3] - } else if cfg!(order3412) { - [thread_3, thread_4, thread_1, thread_2] - } else if cfg!(order2341) { - [thread_2, thread_3, thread_4, thread_1] - } else { - unimplemented!(); - }; - - let ids = unsafe { create_pthreads_no_params(thread_order) }; - unsafe { join_pthreads(ids) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(2, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr deleted file mode 100644 index c8cd87ff6b..0000000000 --- a/tests/genmc/pass/litmus/CoRR2/corr2.order1234.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr deleted file mode 100644 index c8cd87ff6b..0000000000 --- a/tests/genmc/pass/litmus/CoRR2/corr2.order2341.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr deleted file mode 100644 index c8cd87ff6b..0000000000 --- a/tests/genmc/pass/litmus/CoRR2/corr2.order3412.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr deleted file mode 100644 index c8cd87ff6b..0000000000 --- a/tests/genmc/pass/litmus/CoRR2/corr2.order4123.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr b/tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr deleted file mode 100644 index c8cd87ff6b..0000000000 --- a/tests/genmc/pass/litmus/CoRR2/corr2.order4321.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 72 diff --git a/tests/genmc/pass/litmus/CoRR2/corr2.rs b/tests/genmc/pass/litmus/CoRR2/corr2.rs deleted file mode 100644 index 1a3f2e10b7..0000000000 --- a/tests/genmc/pass/litmus/CoRR2/corr2.rs +++ /dev/null @@ -1,57 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order1234 order4321 order4123 order3412 order2341 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order1234) { - [thread_1, thread_2, thread_3, thread_4] - } else if cfg!(order4321) { - [thread_4, thread_3, thread_2, thread_1] - } else if cfg!(order4123) { - [thread_4, thread_1, thread_2, thread_3] - } else if cfg!(order3412) { - [thread_3, thread_4, thread_1, thread_2] - } else if cfg!(order2341) { - [thread_2, thread_3, thread_4, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(2, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/CoRW/corw.order12.stderr b/tests/genmc/pass/litmus/CoRW/corw.order12.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/CoRW/corw.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoRW/corw.order21.stderr b/tests/genmc/pass/litmus/CoRW/corw.order21.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/CoRW/corw.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoRW/corw.rs b/tests/genmc/pass/litmus/CoRW/corw.rs deleted file mode 100644 index 4776ae61ed..0000000000 --- a/tests/genmc/pass/litmus/CoRW/corw.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - X.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(2, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/CoWR/cowr.order12.stderr b/tests/genmc/pass/litmus/CoWR/cowr.order12.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/CoWR/cowr.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoWR/cowr.order21.stderr b/tests/genmc/pass/litmus/CoWR/cowr.order21.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/CoWR/cowr.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/CoWR/cowr.rs b/tests/genmc/pass/litmus/CoWR/cowr.rs deleted file mode 100644 index 8d3773bbfc..0000000000 --- a/tests/genmc/pass/litmus/CoWR/cowr.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(2, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs b/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs deleted file mode 100644 index d6dc8c755b..0000000000 --- a/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::ptr::null_mut; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3, thread_4]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - null_mut() -} - -pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - Y.load(Ordering::SeqCst); - null_mut() -} - -pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - X.load(Ordering::SeqCst); - null_mut() -} - -pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::SeqCst); - null_mut() -} diff --git a/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr b/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr deleted file mode 100644 index f5e120ea47..0000000000 --- a/tests/genmc/pass/litmus/IRIW-acq-sc/IRIW-acq-sc.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 16 diff --git a/tests/genmc/pass/litmus/IRIWish/IRIWish.rs b/tests/genmc/pass/litmus/IRIWish/IRIWish.rs deleted file mode 100644 index b424c11208..0000000000 --- a/tests/genmc/pass/litmus/IRIWish/IRIWish.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::ptr::null_mut; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3, thread_4]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - let r1 = X.load(Ordering::Relaxed); - Y.store(r1, Ordering::Release); - null_mut() -} - -pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - let _r1 = X.load(Ordering::Relaxed); - std::sync::atomic::fence(Ordering::AcqRel); - let _r2 = Y.load(Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - let _r1 = Y.load(Ordering::Relaxed); - std::sync::atomic::fence(Ordering::AcqRel); - let _r2 = X.load(Ordering::Relaxed); - null_mut() -} diff --git a/tests/genmc/pass/litmus/IRIWish/IRIWish.stderr b/tests/genmc/pass/litmus/IRIWish/IRIWish.stderr deleted file mode 100644 index 452fca4856..0000000000 --- a/tests/genmc/pass/litmus/IRIWish/IRIWish.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 28 diff --git a/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs b/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs deleted file mode 100644 index beb8c47480..0000000000 --- a/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); -static W: AtomicU64 = AtomicU64::new(0); -static Z: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3, thread_4]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - Z.fetch_add(1, Ordering::AcqRel); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Z.fetch_add(1, Ordering::AcqRel); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - W.fetch_add(1, Ordering::AcqRel); - std::ptr::null_mut() -} - -extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - W.fetch_add(1, Ordering::AcqRel); - X.store(1, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr b/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr deleted file mode 100644 index 978d7c1ff3..0000000000 --- a/tests/genmc/pass/litmus/LB+incMPs/LB_incMPs.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 15 diff --git a/tests/genmc/pass/litmus/LB/LB.order12.stderr b/tests/genmc/pass/litmus/LB/LB.order12.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/LB/LB.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/LB/LB.order21.stderr b/tests/genmc/pass/litmus/LB/LB.order21.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/LB/LB.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/LB/LB.rs b/tests/genmc/pass/litmus/LB/LB.rs deleted file mode 100644 index 0247ea9634..0000000000 --- a/tests/genmc/pass/litmus/LB/LB.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - X.store(2, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs b/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs deleted file mode 100644 index aa089d3d39..0000000000 --- a/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); -static Z: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - Z.fetch_add(1, Ordering::AcqRel); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Z.fetch_add(1, Ordering::AcqRel); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr b/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr deleted file mode 100644 index 708f4aab1b..0000000000 --- a/tests/genmc/pass/litmus/MP+incMPs/MP_incMPs.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 7 diff --git a/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs b/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs deleted file mode 100644 index f11f6b9a0c..0000000000 --- a/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -// -Zmiri-disable-data-race-detector - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MP+rels+acqf/mp+rels+acqf.c) uses non-atomic accesses for `X` with disabled race detection. -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - - Y.store(0, Ordering::Release); - Y.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - if Y.load(Ordering::Relaxed) != 0 { - std::sync::atomic::fence(Ordering::Acquire); - let _x = X.load(Ordering::Relaxed); - } - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr b/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/MP+rels+acqf/MP_rels_acqf.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/MP/MP.order12.stderr b/tests/genmc/pass/litmus/MP/MP.order12.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/MP/MP.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/MP/MP.order21.stderr b/tests/genmc/pass/litmus/MP/MP.order21.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/MP/MP.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/MP/MP.rs b/tests/genmc/pass/litmus/MP/MP.rs deleted file mode 100644 index c298280f0f..0000000000 --- a/tests/genmc/pass/litmus/MP/MP.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs b/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs deleted file mode 100644 index 3ff6c5f2fd..0000000000 --- a/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MPU+rels+acq/mpu+rels+acq.c) uses non-atomic accesses for `X` with disabled race detection. -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - - Y.store(0, Ordering::Release); - Y.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - if Y.load(Ordering::Acquire) > 1 { - X.store(2, Ordering::Relaxed); - } - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr b/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr deleted file mode 100644 index 89aa5eb69c..0000000000 --- a/tests/genmc/pass/litmus/MPU+rels+acq/MPU_rels_acq.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 13 diff --git a/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs b/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs deleted file mode 100644 index c98e9f23ba..0000000000 --- a/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.rs +++ /dev/null @@ -1,51 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -// Note: the GenMC equivalent of this test (genmc/tests/correct/litmus/MPU2+rels+acqf/mpu2+rels+acqf.c) uses non-atomic accesses for `X` with disabled race detection. -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3, thread_4]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - - Y.store(0, Ordering::Release); - Y.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - let expected = 2; - let _ = Y.compare_exchange(expected, 3, Ordering::Relaxed, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - let expected = 1; - let _ = Y.compare_exchange(expected, 2, Ordering::Relaxed, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - if Y.load(Ordering::Acquire) > 2 { - std::sync::atomic::fence(Ordering::Acquire); - X.store(2, Ordering::Relaxed); - } - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr b/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr deleted file mode 100644 index c2ffa8ec3c..0000000000 --- a/tests/genmc/pass/litmus/MPU2+rels+acqf/MPU2_rels_acqf.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 36 diff --git a/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs b/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs deleted file mode 100644 index 27d63b605e..0000000000 --- a/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - Y.load(Ordering::SeqCst); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - X.load(Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr b/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/SB+2sc+scf/SB_2sc_scf.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/SB/SB.order12.stderr b/tests/genmc/pass/litmus/SB/SB.order12.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/SB/SB.order12.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/SB/SB.order21.stderr b/tests/genmc/pass/litmus/SB/SB.order21.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/SB/SB.order21.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/SB/SB.rs b/tests/genmc/pass/litmus/SB/SB.rs deleted file mode 100644 index 645291d088..0000000000 --- a/tests/genmc/pass/litmus/SB/SB.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order12 order21 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order12) { - [thread_1, thread_2] - } else if cfg!(order21) { - [thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - Y.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Release); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr deleted file mode 100644 index 708f4aab1b..0000000000 --- a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order123.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 7 diff --git a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr deleted file mode 100644 index 708f4aab1b..0000000000 --- a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.order321.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 7 diff --git a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs b/tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs deleted file mode 100644 index 65f87925f2..0000000000 --- a/tests/genmc/pass/litmus/Z6+acq/Z6_acq.rs +++ /dev/null @@ -1,51 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order123 order321 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); -static Z: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order123) { - [thread_1, thread_2, thread_3] - } else if cfg!(order321) { - [thread_3, thread_2, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - Y.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Acquire); - Z.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - Z.store(2, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - X.load(Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs b/tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs deleted file mode 100644 index 3459fbe6e5..0000000000 --- a/tests/genmc/pass/litmus/Z6.U0/Z6_U0.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.fetch_add(1, Ordering::SeqCst); - Y.load(Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - Y.store(3, Ordering::SeqCst); - X.load(Ordering::SeqCst); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr b/tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr deleted file mode 100644 index fbd9adb20b..0000000000 --- a/tests/genmc/pass/litmus/Z6.U0/Z6_U0.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 22 diff --git a/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs b/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs deleted file mode 100644 index 351b65d0e6..0000000000 --- a/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - // TODO GENMC: do these have to be unsafe? - unsafe { - miri_genmc_verifier_assume(2 > Y.load(Ordering::Relaxed) || Y.load(Ordering::Relaxed) > 3); - } - X.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - // TODO GENMC: do these have to be unsafe? - unsafe { - miri_genmc_verifier_assume(X.load(Ordering::Relaxed) < 3); - } - - Y.store(3, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::SeqCst); - Y.store(4, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr b/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr deleted file mode 100644 index bcd0ece9c7..0000000000 --- a/tests/genmc/pass/litmus/assume-ctrl/assume-ctrl.stderr +++ /dev/null @@ -1,4 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 -Number of blocked executions seen: 1 diff --git a/tests/genmc/pass/litmus/atomicpo/atomicpo.rs b/tests/genmc/pass/litmus/atomicpo/atomicpo.rs deleted file mode 100644 index 5c42605715..0000000000 --- a/tests/genmc/pass/litmus/atomicpo/atomicpo.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - std::sync::atomic::fence(Ordering::AcqRel); - Y.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.swap(1, Ordering::Relaxed); - X.swap(1, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/atomicpo/atomicpo.stderr b/tests/genmc/pass/litmus/atomicpo/atomicpo.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/litmus/atomicpo/atomicpo.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/litmus/casdep/casdep.rs b/tests/genmc/pass/litmus/casdep/casdep.rs deleted file mode 100644 index ad70af27a9..0000000000 --- a/tests/genmc/pass/litmus/casdep/casdep.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); -static Z: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - let a = X.load(Ordering::Relaxed); - let _b = Y.compare_exchange(a, 1, Ordering::Relaxed, Ordering::Relaxed); - Z.store(a, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(2, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/casdep/casdep.stderr b/tests/genmc/pass/litmus/casdep/casdep.stderr deleted file mode 100644 index edecd38278..0000000000 --- a/tests/genmc/pass/litmus/casdep/casdep.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 diff --git a/tests/genmc/pass/litmus/ccr/ccr.rs b/tests/genmc/pass/litmus/ccr/ccr.rs deleted file mode 100644 index 68ccf2b74e..0000000000 --- a/tests/genmc/pass/litmus/ccr/ccr.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - let expected = 0; - let _ = X.compare_exchange(expected, 42, Ordering::Relaxed, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - let expected = 0; - let _ = X.compare_exchange(expected, 17, Ordering::Relaxed, Ordering::Relaxed); - X.load(Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/ccr/ccr.stderr b/tests/genmc/pass/litmus/ccr/ccr.stderr deleted file mode 100644 index edecd38278..0000000000 --- a/tests/genmc/pass/litmus/ccr/ccr.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 diff --git a/tests/genmc/pass/litmus/cii/cii.rs b/tests/genmc/pass/litmus/cii/cii.rs deleted file mode 100644 index 0e25407d83..0000000000 --- a/tests/genmc/pass/litmus/cii/cii.rs +++ /dev/null @@ -1,36 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2, thread_3]) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - let expected = 1; - let _ = X.compare_exchange(expected, 2, Ordering::Relaxed, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/cii/cii.stderr b/tests/genmc/pass/litmus/cii/cii.stderr deleted file mode 100644 index e4151d346e..0000000000 --- a/tests/genmc/pass/litmus/cii/cii.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/cumul-release/cumul-release.rs b/tests/genmc/pass/litmus/cumul-release/cumul-release.rs deleted file mode 100644 index c414923e37..0000000000 --- a/tests/genmc/pass/litmus/cumul-release/cumul-release.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); -static Z: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - let r1 = Y.load(Ordering::Relaxed); - Z.store(r1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - let _r2 = Z.load(Ordering::Relaxed); - std::sync::atomic::fence(Ordering::AcqRel); - let _r3 = X.load(Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/cumul-release/cumul-release.stderr b/tests/genmc/pass/litmus/cumul-release/cumul-release.stderr deleted file mode 100644 index c2e069848f..0000000000 --- a/tests/genmc/pass/litmus/cumul-release/cumul-release.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 8 diff --git a/tests/genmc/pass/litmus/default/default.order123.stderr b/tests/genmc/pass/litmus/default/default.order123.stderr deleted file mode 100644 index 1ec3beefbf..0000000000 --- a/tests/genmc/pass/litmus/default/default.order123.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.order231.stderr b/tests/genmc/pass/litmus/default/default.order231.stderr deleted file mode 100644 index 1ec3beefbf..0000000000 --- a/tests/genmc/pass/litmus/default/default.order231.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.order312.stderr b/tests/genmc/pass/litmus/default/default.order312.stderr deleted file mode 100644 index 1ec3beefbf..0000000000 --- a/tests/genmc/pass/litmus/default/default.order312.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.order321.stderr b/tests/genmc/pass/litmus/default/default.order321.stderr deleted file mode 100644 index 1ec3beefbf..0000000000 --- a/tests/genmc/pass/litmus/default/default.order321.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 12 diff --git a/tests/genmc/pass/litmus/default/default.rs b/tests/genmc/pass/litmus/default/default.rs deleted file mode 100644 index e45fd9b509..0000000000 --- a/tests/genmc/pass/litmus/default/default.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc -//@revisions: order123 order321 order312 order231 - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = if cfg!(order123) { - [thread_1, thread_2, thread_3] - } else if cfg!(order321) { - [thread_3, thread_2, thread_1] - } else if cfg!(order312) { - [thread_3, thread_1, thread_2] - } else if cfg!(order231) { - [thread_2, thread_3, thread_1] - } else { - unimplemented!(); - }; - - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.load(Ordering::Acquire); - X.load(Ordering::Acquire); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.store(2, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/detour/detour.rs b/tests/genmc/pass/litmus/detour/detour.rs deleted file mode 100644 index eee0dadcd8..0000000000 --- a/tests/genmc/pass/litmus/detour/detour.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicI64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicI64 = AtomicI64::new(0); -static Y: AtomicI64 = AtomicI64::new(0); -static Z: AtomicI64 = AtomicI64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - let a = Z.load(Ordering::Relaxed); - X.store(a.wrapping_sub(1), Ordering::Relaxed); - let b = X.load(Ordering::Relaxed); - Y.store(b, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - let c = Y.load(Ordering::Relaxed); - Z.store(c, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/detour/detour.stderr b/tests/genmc/pass/litmus/detour/detour.stderr deleted file mode 100644 index 7e0204914a..0000000000 --- a/tests/genmc/pass/litmus/detour/detour.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 9 diff --git a/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs b/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs deleted file mode 100644 index 19547d09b7..0000000000 --- a/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.rs +++ /dev/null @@ -1,45 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::ptr::null_mut; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3, thread_4]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(2, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.store(3, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - let _r1 = X.load(Ordering::Relaxed); - let _r2 = X.load(Ordering::Relaxed); - let _r3 = X.load(Ordering::Relaxed); - let _r4 = X.load(Ordering::Relaxed); - null_mut() -} diff --git a/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr b/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr deleted file mode 100644 index 528ebdfd2b..0000000000 --- a/tests/genmc/pass/litmus/fr_w_w_w_reads/fr_w_w_w_reads.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 210 diff --git a/tests/genmc/pass/litmus/inc2w/inc2w.rs b/tests/genmc/pass/litmus/inc2w/inc2w.rs deleted file mode 100644 index 03552cac22..0000000000 --- a/tests/genmc/pass/litmus/inc2w/inc2w.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::ptr::null_mut; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.fetch_add(1, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.store(4, Ordering::Release); - null_mut() -} - -pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - X.fetch_add(2, Ordering::Relaxed); - null_mut() -} diff --git a/tests/genmc/pass/litmus/inc2w/inc2w.stderr b/tests/genmc/pass/litmus/inc2w/inc2w.stderr deleted file mode 100644 index e4151d346e..0000000000 --- a/tests/genmc/pass/litmus/inc2w/inc2w.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 6 diff --git a/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs b/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs deleted file mode 100644 index 17213612ae..0000000000 --- a/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.rs +++ /dev/null @@ -1,63 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::ptr::null_mut; -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicU64 = AtomicU64::new(0); - -static mut A: u64 = 0; -static mut B: u64 = 0; -static mut C: u64 = 0; -static mut D: u64 = 0; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2, thread_3, thread_4, thread_5]; - let ids = unsafe { create_pthreads_no_params(thread_order) }; - unsafe { join_pthreads(ids) }; - - if unsafe { A == 42 && B == 2 && C == 1 && D == 42 } { - std::process::abort(); - } - - 0 -} - -pub extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.fetch_add(1, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.fetch_add(1, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - unsafe { - A = X.load(Ordering::Relaxed); - B = X.load(Ordering::Relaxed); - } - null_mut() -} - -pub extern "C" fn thread_4(_value: *mut c_void) -> *mut c_void { - X.store(42, Ordering::Relaxed); - null_mut() -} - -pub extern "C" fn thread_5(_value: *mut c_void) -> *mut c_void { - unsafe { - C = X.load(Ordering::Relaxed); - D = X.load(Ordering::Relaxed); - } - null_mut() -} diff --git a/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr b/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr deleted file mode 100644 index ad9e4b3a6e..0000000000 --- a/tests/genmc/pass/litmus/inc_inc_RR_W_RR/inc_inc_RR_W_RR.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 600 diff --git a/tests/genmc/pass/litmus/riwi/riwi.rs b/tests/genmc/pass/litmus/riwi/riwi.rs deleted file mode 100644 index 1c210e7cea..0000000000 --- a/tests/genmc/pass/litmus/riwi/riwi.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_1, thread_2]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - Y.load(Ordering::Relaxed); - X.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - X.fetch_add(1, Ordering::Relaxed); - Y.store(1, Ordering::Release); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/riwi/riwi.stderr b/tests/genmc/pass/litmus/riwi/riwi.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/litmus/riwi/riwi.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs b/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs deleted file mode 100644 index 83468eddc0..0000000000 --- a/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.rs +++ /dev/null @@ -1,43 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static LOCK: AtomicU64 = AtomicU64::new(0); - -use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let thread_order = [thread_ra, thread_r, thread_rr, thread_rs]; - let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - 0 -} - -extern "C" fn thread_ra(_value: *mut c_void) -> *mut c_void { - LOCK.fetch_add(1, Ordering::Acquire); - LOCK.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_r(_value: *mut c_void) -> *mut c_void { - LOCK.fetch_add(1, Ordering::Relaxed); - LOCK.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} - -extern "C" fn thread_rr(_value: *mut c_void) -> *mut c_void { - LOCK.fetch_add(1, Ordering::Release); - std::ptr::null_mut() -} - -extern "C" fn thread_rs(_value: *mut c_void) -> *mut c_void { - LOCK.fetch_add(1, Ordering::Relaxed); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr b/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr deleted file mode 100644 index 5b01ae0789..0000000000 --- a/tests/genmc/pass/litmus/viktor-relseq/viktor-relseq.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 180 diff --git a/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs b/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs deleted file mode 100644 index 5c513ef561..0000000000 --- a/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.rs +++ /dev/null @@ -1,52 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -// #[path = "../../../../utils-dep/mod.rs"] -// mod utils_dep; - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -// use crate::utils_dep::*; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - // let thread_order = [thread_1, thread_2]; - // let _ids = unsafe { create_pthreads_no_params(thread_order) }; - - let spawn = |func| { - use libc::{pthread_attr_t, pthread_t}; - - let mut thread_id: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - let ret = unsafe { libc::pthread_create(&raw mut thread_id, attr, func, value) }; - if 0 != ret { - std::process::abort(); - } - thread_id - }; - - let _t1 = spawn(thread_1); - let _t2 = spawn(thread_2); - - 0 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - X.store(1, Ordering::SeqCst); - Y.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - Y.store(1, Ordering::Release); - X.store(2, Ordering::SeqCst); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr b/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr deleted file mode 100644 index 61dc3f60ba..0000000000 --- a/tests/genmc/pass/simple/2+2W+3sc+rel1/2_2w_3sc_rel1.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 4 diff --git a/tests/genmc/pass/simple/2w2w_seqcst.rs b/tests/genmc/pass/simple/2w2w_seqcst.rs deleted file mode 100644 index f8161e90f0..0000000000 --- a/tests/genmc/pass/simple/2w2w_seqcst.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -// TODO GENMC: this test currently takes 3 iterations, it this correct? - -#![no_main] - -use std::ffi::c_void; -use std::sync::atomic::{AtomicU64, Ordering}; - -use libc::{self, pthread_attr_t, pthread_t}; - -static X: AtomicU64 = AtomicU64::new(0); -static Y: AtomicU64 = AtomicU64::new(0); - -const LOAD_ORD: Ordering = Ordering::SeqCst; -const STORE_ORD: Ordering = Ordering::SeqCst; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let mut thread_id: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - let ret_create = unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }; - assert!(ret_create == 0); - - X.store(1, STORE_ORD); - Y.store(2, STORE_ORD); - - let ret_join = unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }; - assert!(ret_join == 0); - - let x = X.load(LOAD_ORD); - let y = Y.load(LOAD_ORD); - if x == 1 && y == 1 { - unsafe { std::hint::unreachable_unchecked() }; - } - 0 -} - -extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { - Y.store(1, STORE_ORD); - X.store(2, STORE_ORD); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/simple/2w2w_seqcst.stderr b/tests/genmc/pass/simple/2w2w_seqcst.stderr deleted file mode 100644 index f2f3f904fb..0000000000 --- a/tests/genmc/pass/simple/2w2w_seqcst.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 3 diff --git a/tests/genmc/pass/simple/atomic_ptr.rs b/tests/genmc/pass/simple/atomic_ptr.rs deleted file mode 100644 index 03fbd3e8b7..0000000000 --- a/tests/genmc/pass/simple/atomic_ptr.rs +++ /dev/null @@ -1,83 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::sync::atomic::*; - -static mut X: u64 = 0; -static mut Y: u64 = 0; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - unsafe { - let atomic_ptr: AtomicPtr = AtomicPtr::new(&raw mut X); - - let x_ptr = atomic_ptr.load(Ordering::SeqCst); - *x_ptr = 10; - if X != 10 { - std::process::abort(); - } - atomic_ptr.store(&raw mut Y, Ordering::SeqCst); - Y = 42; - let y_ptr = atomic_ptr.load(Ordering::SeqCst); - if *y_ptr != 42 { - std::process::abort(); - } - *y_ptr = 1234; - if Y != 1234 { - std::process::abort(); - } else if X != 10 { - std::process::abort(); - } - let y_ptr_ = atomic_ptr.swap(&raw mut X, Ordering::SeqCst); - if y_ptr_ != y_ptr { - std::process::abort(); - } - // To make sure also the provenance info is correctly restored, we need to use the pointers: - if *y_ptr_ != *y_ptr { - std::process::abort(); - } - *y_ptr_ = *y_ptr; - - match atomic_ptr.compare_exchange( - y_ptr, // wrong, it should be `x_ptr`, so this should never succeed - std::ptr::dangling_mut(), - Ordering::SeqCst, - Ordering::SeqCst, - ) { - Ok(_ptr) => std::process::abort(), - Err(ptr) => - if ptr != x_ptr { - std::process::abort(); - } else if *ptr != *x_ptr { - std::process::abort(); - } else { - *ptr = *ptr; - }, - } - - let mut array: [u64; 10] = [0xAAAA; 10]; - match atomic_ptr.compare_exchange( - x_ptr, - &raw mut array[2], - Ordering::SeqCst, - Ordering::SeqCst, - ) { - Ok(ptr) => - if ptr != x_ptr { - std::process::abort(); - }, - Err(_ptr) => std::process::abort(), - } - let ptr = atomic_ptr.load(Ordering::SeqCst); - *ptr = 0xB; - if array[2] != 0xB { - std::process::abort(); - } - array[2] = 0xC; - if *ptr != 0xC { - std::process::abort(); - } - } - 0 -} diff --git a/tests/genmc/pass/simple/atomic_ptr.stderr b/tests/genmc/pass/simple/atomic_ptr.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/simple/atomic_ptr.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/atomic_simple.rs b/tests/genmc/pass/simple/atomic_simple.rs deleted file mode 100644 index c9fdb89850..0000000000 --- a/tests/genmc/pass/simple/atomic_simple.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::sync::atomic::*; - -static FLAG: AtomicUsize = AtomicUsize::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - FLAG.store(42, Ordering::SeqCst); - let val = FLAG.load(Ordering::SeqCst); - if val != 42 { - std::process::abort(); - } - 0 -} diff --git a/tests/genmc/pass/simple/atomic_simple.stderr b/tests/genmc/pass/simple/atomic_simple.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/simple/atomic_simple.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/cas_simple.rs b/tests/genmc/pass/simple/cas_simple.rs deleted file mode 100644 index cd42084a54..0000000000 --- a/tests/genmc/pass/simple/cas_simple.rs +++ /dev/null @@ -1,47 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::sync::atomic::*; - -static VALUE: AtomicUsize = AtomicUsize::new(0); - -const SUCCESS_ORD: Ordering = Ordering::SeqCst; -const FAILURE_ORD: Ordering = Ordering::SeqCst; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - VALUE.store(1, SUCCESS_ORD); - - let current = 1; - let new_value = 2; - // Expect success: - match VALUE.compare_exchange(current, new_value, SUCCESS_ORD, FAILURE_ORD) { - Ok(old_value) => - if old_value != current { - std::process::abort(); - }, - Err(_value) => std::process::abort(), - } - - if new_value != VALUE.load(SUCCESS_ORD) { - std::process::abort() - } - - let dummy_value = 42; - let wrong_value = 1234; - - // Expect failure: - match VALUE.compare_exchange(wrong_value, dummy_value, SUCCESS_ORD, FAILURE_ORD) { - Ok(_old_value) => std::process::abort(), - Err(old_value) => - if old_value != new_value { - std::process::abort(); - }, - } - - if new_value != VALUE.load(SUCCESS_ORD) { - std::process::abort() - } - 0 -} diff --git a/tests/genmc/pass/simple/cas_simple.stderr b/tests/genmc/pass/simple/cas_simple.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/simple/cas_simple.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_main.rs b/tests/genmc/pass/simple/simple_main.rs deleted file mode 100644 index ac3c81a91b..0000000000 --- a/tests/genmc/pass/simple/simple_main.rs +++ /dev/null @@ -1,3 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -fn main() {} diff --git a/tests/genmc/pass/simple/simple_main.stderr b/tests/genmc/pass/simple/simple_main.stderr deleted file mode 100644 index 2184c16ce9..0000000000 --- a/tests/genmc/pass/simple/simple_main.stderr +++ /dev/null @@ -1,7 +0,0 @@ -warning: GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)! - -warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Relaxed' is treated like 'Acquire', which means that Miri might miss bugs related to this memory access (possible unsoundness)! - - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_main_spawn_threads.rs b/tests/genmc/pass/simple/simple_main_spawn_threads.rs deleted file mode 100644 index ec1af0dde8..0000000000 --- a/tests/genmc/pass/simple/simple_main_spawn_threads.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -const N: usize = 1; - -fn main() { - let handles: Vec<_> = (0..N).map(|_| std::thread::spawn(thread_func)).collect(); - handles.into_iter().for_each(|handle| handle.join().unwrap()); -} - -fn thread_func() {} diff --git a/tests/genmc/pass/simple/simple_main_spawn_threads.stderr b/tests/genmc/pass/simple/simple_main_spawn_threads.stderr deleted file mode 100644 index c6bd55a4f8..0000000000 --- a/tests/genmc/pass/simple/simple_main_spawn_threads.stderr +++ /dev/null @@ -1,9 +0,0 @@ -warning: GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)! - -warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Relaxed' is treated like 'Acquire', which means that Miri might miss bugs related to this memory access (possible unsoundness)! - -warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Acquire' is treated like 'Relaxed', which means that Miri might incorrectly detect errors related to this memory access (possible false positives). - - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs b/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs deleted file mode 100644 index 12d90869c0..0000000000 --- a/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::ffi::c_void; - -use libc::{self, pthread_attr_t, pthread_t}; - -const N: usize = 1; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let mut handles: Vec = vec![0; N]; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - handles.iter_mut().for_each(|thread_id| { - if 0 != unsafe { libc::pthread_create(thread_id, attr, thread_func, value) } { - std::process::abort(); - } - }); - - handles.into_iter().for_each(|thread_id| { - if 0 != unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) } { - std::process::abort(); - } - }); - - 0 -} - -extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr b/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/simple/simple_miri_main_spawn_pthreads.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs b/tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs deleted file mode 100644 index 69a0d00f26..0000000000 --- a/tests/genmc/pass/simple/simple_miri_main_spawn_threads.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -const N: usize = 1; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let handles: Vec<_> = (0..N).map(|_| std::thread::spawn(thread_func)).collect(); - handles.into_iter().for_each(|handle| handle.join().unwrap()); - - 0 -} - -fn thread_func() {} diff --git a/tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr b/tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr deleted file mode 100644 index 8ac3e9f5cf..0000000000 --- a/tests/genmc/pass/simple/simple_miri_main_spawn_threads.stderr +++ /dev/null @@ -1,9 +0,0 @@ -warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Relaxed' is treated like 'Acquire', which means that Miri might miss bugs related to this memory access (possible unsoundness)! - -warning: GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)! - -warning: GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering 'Acquire' is treated like 'Relaxed', which means that Miri might incorrectly detect errors related to this memory access (possible false positives). - - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/stack_alloc_atomic.rs b/tests/genmc/pass/simple/stack_alloc_atomic.rs deleted file mode 100644 index fa595845f9..0000000000 --- a/tests/genmc/pass/simple/stack_alloc_atomic.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::sync::atomic::*; - -const ORD: Ordering = Ordering::SeqCst; - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let x = AtomicU64::new(1234); - let a = x.load(ORD); - if a != 1234 { - std::process::abort(); - } - - 0 -} diff --git a/tests/genmc/pass/simple/stack_alloc_atomic.stderr b/tests/genmc/pass/simple/stack_alloc_atomic.stderr deleted file mode 100644 index 2382cc5a78..0000000000 --- a/tests/genmc/pass/simple/stack_alloc_atomic.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 1 diff --git a/tests/genmc/pass/simple/thread_locals.rs b/tests/genmc/pass/simple/thread_locals.rs deleted file mode 100644 index b37ced017e..0000000000 --- a/tests/genmc/pass/simple/thread_locals.rs +++ /dev/null @@ -1,54 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-genmc - -#![no_main] - -#[path = "../../../utils-dep/mod.rs"] -mod utils_dep; - -use std::cell::Cell; -use std::ffi::c_void; -use std::sync::atomic::{AtomicPtr, Ordering}; - -use crate::utils_dep::*; - -static X: AtomicPtr = AtomicPtr::new(std::ptr::null_mut()); - -thread_local! { - static R: Cell<*mut u64> = Cell::new(std::ptr::null_mut()); -} - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let _ids = unsafe { create_pthreads_no_params([thread_1, thread_2, thread_3]) }; - - 0 -} - -pub unsafe fn malloc() -> *mut u64 { - Box::into_raw(Box::::new_uninit()) as *mut u64 -} - -extern "C" fn thread_1(_value: *mut c_void) -> *mut c_void { - unsafe { - R.set(malloc()); - let r_ptr = R.get(); - let _ = X.compare_exchange(std::ptr::null_mut(), r_ptr, Ordering::SeqCst, Ordering::SeqCst); - std::ptr::null_mut() - } -} - -extern "C" fn thread_2(_value: *mut c_void) -> *mut c_void { - unsafe { - R.set(malloc()); - std::ptr::null_mut() - } -} - -extern "C" fn thread_3(_value: *mut c_void) -> *mut c_void { - unsafe { - R.set(malloc()); - let r_ptr = R.get(); - let _ = X.compare_exchange(std::ptr::null_mut(), r_ptr, Ordering::SeqCst, Ordering::SeqCst); - std::ptr::null_mut() - } -} diff --git a/tests/genmc/pass/simple/thread_locals.stderr b/tests/genmc/pass/simple/thread_locals.stderr deleted file mode 100644 index edecd38278..0000000000 --- a/tests/genmc/pass/simple/thread_locals.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 diff --git a/tests/genmc/pass/simple/thread_simple.rs b/tests/genmc/pass/simple/thread_simple.rs deleted file mode 100644 index 74da7f98ad..0000000000 --- a/tests/genmc/pass/simple/thread_simple.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@compile-flags: -Zmiri-genmc - -#![no_main] - -use std::ffi::c_void; -use std::sync::atomic::AtomicU64; -use std::sync::atomic::Ordering::SeqCst; - -use libc::{self, pthread_attr_t, pthread_t}; - -static FLAG: AtomicU64 = AtomicU64::new(0); - -#[unsafe(no_mangle)] -fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - let mut thread_id: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - assert!(0 == unsafe { libc::pthread_create(&raw mut thread_id, attr, thread_func, value) }); - - FLAG.store(1, SeqCst); - - assert!(0 == unsafe { libc::pthread_join(thread_id, std::ptr::null_mut()) }); - - let flag = FLAG.load(SeqCst); - assert!(flag == 1 || flag == 2); - return 0; -} - -extern "C" fn thread_func(_value: *mut c_void) -> *mut c_void { - FLAG.store(2, SeqCst); - std::ptr::null_mut() -} diff --git a/tests/genmc/pass/simple/thread_simple.stderr b/tests/genmc/pass/simple/thread_simple.stderr deleted file mode 100644 index edecd38278..0000000000 --- a/tests/genmc/pass/simple/thread_simple.stderr +++ /dev/null @@ -1,3 +0,0 @@ - -(GenMC) Verification complete. No errors were detected. -Number of complete executions explored: 2 diff --git a/tests/utils-dep/genmc.rs b/tests/utils-dep/genmc.rs deleted file mode 100644 index f6cdab63a7..0000000000 --- a/tests/utils-dep/genmc.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::ffi::c_void; - -use libc::{self, pthread_attr_t, pthread_t}; - -pub unsafe fn create_pthreads_no_params( - functions: [extern "C" fn(*mut c_void) -> *mut c_void; N], -) -> [pthread_t; N] { - functions.map(|func| { - let mut thread_id: pthread_t = 0; - - let attr: *const pthread_attr_t = std::ptr::null(); - let value: *mut c_void = std::ptr::null_mut(); - - if 0 != unsafe { libc::pthread_create(&raw mut thread_id, attr, func, value) } { - std::process::abort(); - } - thread_id - }) -} - -pub unsafe fn join_pthreads(thread_ids: [pthread_t; N]) { - let _ = thread_ids.map(|id| { - if 0 != unsafe { libc::pthread_join(id, std::ptr::null_mut()) } { - std::process::abort(); - } - }); -} diff --git a/tests/utils-dep/miri_extern.rs b/tests/utils-dep/miri_extern.rs deleted file mode 100644 index dbd4cdb48d..0000000000 --- a/tests/utils-dep/miri_extern.rs +++ /dev/null @@ -1,2 +0,0 @@ -// TODO GENMC: is this ok or is there a better solution? -include!("../utils/miri_extern.rs"); diff --git a/tests/utils-dep/mod.rs b/tests/utils-dep/mod.rs deleted file mode 100644 index ab35b8e3c4..0000000000 --- a/tests/utils-dep/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![allow(dead_code)] -#![allow(unused_imports)] - -pub mod genmc; -mod miri_extern; - -pub use self::genmc::*; -pub use self::miri_extern::*; diff --git a/tests/utils/miri_extern.rs b/tests/utils/miri_extern.rs index 4ce7d27539..d6c43b1882 100644 --- a/tests/utils/miri_extern.rs +++ b/tests/utils/miri_extern.rs @@ -147,7 +147,4 @@ extern "Rust" { /// "symbolic" alignment checks. Will fail if the pointer is not actually aligned or `align` is /// not a power of two. Has no effect when alignment checks are concrete (which is the default). pub fn miri_promise_symbolic_alignment(ptr: *const (), align: usize); - - /// Blocks the current execution if the argument is false - pub fn miri_genmc_verifier_assume(condition: bool); } From 325a5f48d6f57f52c0b7596ebf6e5e6950b59b1e Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 11:38:19 +0200 Subject: [PATCH 03/64] Miri-GenMC build PR: Reduce code changes to minimum needed to test build. --- Cargo.lock | 1 - Cargo.toml | 5 +- genmc-sys/Cargo.lock | 788 ------------ genmc-sys/src/lib.rs | 282 +---- genmc-sys/src_cpp/MiriInterface.cpp | 506 +------- genmc-sys/src_cpp/MiriInterface.hpp | 222 +--- src/alloc_addresses/mod.rs | 26 +- src/bin/miri.rs | 36 +- src/concurrency/data_race.rs | 73 +- src/concurrency/genmc/config.rs | 51 +- src/concurrency/genmc/cxx_extra.rs | 48 - src/concurrency/genmc/dummy.rs | 84 +- src/concurrency/genmc/global_allocations.rs | 145 --- src/concurrency/genmc/helper.rs | 230 ---- src/concurrency/genmc/mapping.rs | 83 -- src/concurrency/genmc/miri_genmc.rs | 73 -- src/concurrency/genmc/mod.rs | 1135 ++---------------- src/concurrency/genmc/thread_info_manager.rs | 95 -- src/concurrency/genmc/warnings.rs | 66 - src/concurrency/mod.rs | 4 +- src/concurrency/thread.rs | 89 +- src/concurrency/weak_memory.rs | 3 - src/diagnostics.rs | 13 +- src/eval.rs | 3 +- src/lib.rs | 2 +- src/machine.rs | 29 +- src/shims/foreign_items.rs | 16 - tests/genmc/pass/test_cxx_build.rs | 8 + tests/genmc/pass/test_cxx_build.stderr | 4 + 29 files changed, 235 insertions(+), 3885 deletions(-) delete mode 100644 genmc-sys/Cargo.lock delete mode 100644 src/concurrency/genmc/cxx_extra.rs delete mode 100644 src/concurrency/genmc/global_allocations.rs delete mode 100644 src/concurrency/genmc/helper.rs delete mode 100644 src/concurrency/genmc/mapping.rs delete mode 100644 src/concurrency/genmc/miri_genmc.rs delete mode 100644 src/concurrency/genmc/thread_info_manager.rs delete mode 100644 src/concurrency/genmc/warnings.rs create mode 100644 tests/genmc/pass/test_cxx_build.rs create mode 100644 tests/genmc/pass/test_cxx_build.stderr diff --git a/Cargo.lock b/Cargo.lock index 82287fee05..04187e5922 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -966,7 +966,6 @@ dependencies = [ "chrono", "chrono-tz", "colored 3.0.0", - "cxx", "directories", "genmc-sys", "getrandom 0.3.3", diff --git a/Cargo.toml b/Cargo.toml index e35619b3ce..751559b6fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ chrono-tz = "0.10" directories = "6" bitflags = "2.6" serde_json = { version = "1.0", optional = true } -cxx = { version = "1.0.143", features = ["c++20"], optional = true } +# cxx = { version = "1.0.160", features = ["c++20"], optional = true } genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } # Copied from `compiler/rustc/Cargo.toml`. @@ -69,8 +69,9 @@ harness = false [features] # TODO GENMC (DEBUGGING): `genmc` feature should be turned off in upstream repo for now default = ["stack-cache", "genmc"] +genmc = ["dep:genmc-sys"] # default = ["stack-cache", "native-lib"] -genmc = ["dep:cxx", "dep:genmc-sys"] +# genmc = ["dep:cxx", "dep:genmc-sys"] stack-cache = [] stack-cache-consistency-check = ["stack-cache"] tracing = ["serde_json"] diff --git a/genmc-sys/Cargo.lock b/genmc-sys/Cargo.lock deleted file mode 100644 index 5efeb8f27a..0000000000 --- a/genmc-sys/Cargo.lock +++ /dev/null @@ -1,788 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anstyle" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "cc" -version = "1.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "clap" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" -dependencies = [ - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_lex" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "codespan-reporting" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" -dependencies = [ - "serde", - "termcolor", - "unicode-width", -] - -[[package]] -name = "cxx" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1149bab7a5580cb267215751389597c021bfad13c0bb00c54e19559333764c" -dependencies = [ - "cc", - "cxxbridge-cmd", - "cxxbridge-flags", - "cxxbridge-macro", - "foldhash", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeeaf1aefae8e0f5141920a7ecbc64a22ab038d4b4ac59f2d19e0effafd5b53" -dependencies = [ - "cc", - "codespan-reporting", - "indexmap", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-cmd" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36ac1f9a72064b1f41fd7b49a4c1b3bf33b9ccb1274874dda6d264f57c55964" -dependencies = [ - "clap", - "codespan-reporting", - "indexmap", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170c6ff5d009663866857a91ebee55b98ea4d4b34e7d7aba6dc4a4c95cc7b748" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4984a142211026786011a7e79fa22faa1eca1e9cbf0e60bffecfd57fd3db88f1" -dependencies = [ - "indexmap", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "genmc-sys" -version = "0.11.0" -dependencies = [ - "cmake", - "cxx", - "cxx-build", - "git2", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi", -] - -[[package]] -name = "git2" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" -dependencies = [ - "bitflags", - "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", -] - -[[package]] -name = "hashbrown" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" - -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom", - "libc", -] - -[[package]] -name = "libc" -version = "0.2.174" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" - -[[package]] -name = "libgit2-sys" -version = "0.18.2+1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" -dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - -[[package]] -name = "libssh2-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" -dependencies = [ - "cc", -] - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "scratch" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/genmc-sys/src/lib.rs b/genmc-sys/src/lib.rs index a4dc5c2aa2..ab46d729ea 100644 --- a/genmc-sys/src/lib.rs +++ b/genmc-sys/src/lib.rs @@ -1,35 +1,11 @@ pub use self::ffi::*; -/// Defined in "genmc/src/Support/SAddr.hpp" -/// FIXME: currently we use `getGlobalAllocStaticMask()` to ensure the constant is consistent between Miri and GenMC, -/// but if https://github.com/dtolnay/cxx/issues/1051 is fixed we could share the constant directly. -pub const GENMC_GLOBAL_ADDRESSES_MASK: u64 = 1 << 63; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct GenmcThreadId(pub i32); - -pub const GENMC_MAIN_THREAD_ID: GenmcThreadId = GenmcThreadId(0); - -impl GenmcScalar { - pub const UNINIT: Self = Self { value: 0, extra: 0, is_init: false }; - pub const DUMMY: Self = Self::from_u64(0xDEADBEEF); - - pub const MUTEX_LOCKED_STATE: Self = Self::from_u64(1); - pub const MUTEX_UNLOCKED_STATE: Self = Self::from_u64(0); - - pub const fn from_u64(value: u64) -> Self { - Self { value, extra: 0, is_init: true } - } -} - impl Default for GenmcParams { fn default() -> Self { Self { print_random_schedule_seed: false, - quiet: true, - log_level_trace: false, - do_symmetry_reduction: false, // TODO GENMC (PERFORMANCE): maybe make this default `true` - estimation_max: 1000, + do_symmetry_reduction: false, + // FIXME(GenMC): Add defaults for remaining parameters } } } @@ -40,265 +16,15 @@ mod ffi { /// (The fields of this struct are visible to both Rust and C++) #[derive(Clone, Debug)] struct GenmcParams { - // pub genmc_seed: u64; // OR: Option pub print_random_schedule_seed: bool, - pub quiet: bool, // TODO GENMC: maybe make log-level more fine grained - pub log_level_trace: bool, pub do_symmetry_reduction: bool, - pub estimation_max: u32, - } - - #[derive(Debug)] - enum ActionKind { - /// Any Mir terminator that's atomic and has load semantics. - Load, - /// Anything that's not a `Load`. - NonLoad, - } - - #[derive(Debug)] - enum MemOrdering { - NotAtomic = 0, - Relaxed = 1, - // In case we support consume - Acquire = 3, - Release = 4, - AcquireRelease = 5, - SequentiallyConsistent = 6, - } - - #[derive(Debug)] - enum RMWBinOp { - Xchg = 0, - Add = 1, - Sub = 2, - And = 3, - Nand = 4, - Or = 5, - Xor = 6, - Max = 7, - Min = 8, - UMax = 9, - UMin = 10, - } - - // TODO GENMC: do these have to be shared with the Rust side? - #[derive(Debug)] - enum StoreEventType { - Normal, - ReadModifyWrite, - CompareExchange, - MutexUnlockWrite, - } - - #[derive(Debug, Clone, Copy)] - struct GenmcScalar { - value: u64, - extra: u64, - is_init: bool, - } - - /**** \/ Result & Error types \/ ****/ - - #[must_use] - #[derive(Debug)] - struct ReadModifyWriteResult { - old_value: GenmcScalar, - new_value: GenmcScalar, - isCoMaxWrite: bool, - error: UniquePtr, // TODO GENMC: pass more error info here - } - - #[must_use] - #[derive(Debug)] - struct MutexLockResult { - is_lock_acquired: bool, - error: UniquePtr, // TODO GENMC: pass more error info here - } - - #[must_use] - #[derive(Debug)] - struct CompareExchangeResult { - old_value: GenmcScalar, // TODO GENMC: handle bigger values - is_success: bool, - isCoMaxWrite: bool, - error: UniquePtr, // TODO GENMC: pass more error info here + // FIXME(GenMC): Add remaining parameters. } - - #[must_use] - #[derive(Debug)] - struct LoadResult { - is_read_opt: bool, - read_value: GenmcScalar, // TODO GENMC: handle bigger values - error: UniquePtr, // TODO GENMC: pass more error info here - } - - #[must_use] - #[derive(Debug)] - struct StoreResult { - error: UniquePtr, // TODO GENMC: pass more error info here - isCoMaxWrite: bool, - } - - #[must_use] - #[derive(Debug)] - enum VerificationError { - VE_NonErrorBegin, - VE_OK, - VE_WWRace, - VE_UnfreedMemory, - VE_NonErrorLast, - VE_Safety, - VE_Recovery, - VE_Liveness, - VE_RaceNotAtomic, - VE_RaceFreeMalloc, - VE_FreeNonMalloc, - VE_DoubleFree, - VE_Allocation, - - VE_InvalidAccessBegin, - VE_UninitializedMem, - VE_AccessNonMalloc, - VE_AccessFreed, - VE_InvalidAccessEnd, - - VE_InvalidCreate, - VE_InvalidJoin, - VE_InvalidUnlock, - VE_InvalidBInit, - VE_InvalidRecoveryCall, - VE_InvalidTruncate, - VE_Annotation, - VE_MixedSize, - VE_LinearizabilityError, - VE_SystemError, - } - - /**** /\ Result & Error types /\ ****/ - unsafe extern "C++" { include!("MiriInterface.hpp"); - type MemOrdering; - type RMWBinOp; - type StoreEventType; - - // Types for Scheduling queries: - type ActionKind; - - // Result / Error types: - type LoadResult; - type StoreResult; - type ReadModifyWriteResult; - type CompareExchangeResult; - type MutexLockResult; - type VerificationError; - - type GenmcScalar; - - // type OperatingMode; // Estimation(budget) or Verification - type MiriGenMCShim; - fn createGenmcHandle(config: &GenmcParams, do_estimation: bool) - -> UniquePtr; - fn getGlobalAllocStaticMask() -> u64; - - fn handleExecutionStart(self: Pin<&mut MiriGenMCShim>); - fn handleExecutionEnd(self: Pin<&mut MiriGenMCShim>) -> UniquePtr; - - fn handleLoad( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - memory_ordering: MemOrdering, - old_value: GenmcScalar, - ) -> LoadResult; - fn handleReadModifyWrite( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - load_ordering: MemOrdering, - store_ordering: MemOrdering, - rmw_op: RMWBinOp, - rhs_value: GenmcScalar, - old_value: GenmcScalar, - ) -> ReadModifyWriteResult; - fn handleCompareExchange( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - expected_value: GenmcScalar, - new_value: GenmcScalar, - old_value: GenmcScalar, - success_load_ordering: MemOrdering, - success_store_ordering: MemOrdering, - fail_load_ordering: MemOrdering, - can_fail_spuriously: bool, - ) -> CompareExchangeResult; - fn handleStore( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - value: GenmcScalar, - old_value: GenmcScalar, - memory_ordering: MemOrdering, - store_event_type: StoreEventType, - ) -> StoreResult; - fn handleFence(self: Pin<&mut MiriGenMCShim>, thread_id: i32, memory_ordering: MemOrdering); - - fn handleMalloc( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - size: u64, - alignment: u64, - ) -> u64; - fn handleFree(self: Pin<&mut MiriGenMCShim>, thread_id: i32, address: u64, size: u64); - - fn handleThreadCreate(self: Pin<&mut MiriGenMCShim>, thread_id: i32, parent_id: i32); - fn handleThreadJoin(self: Pin<&mut MiriGenMCShim>, thread_id: i32, child_id: i32); - fn handleThreadFinish(self: Pin<&mut MiriGenMCShim>, thread_id: i32, ret_val: u64); - - /**** Blocking instructions ****/ - fn handleUserBlock(self: Pin<&mut MiriGenMCShim>, thread_id: i32); - - /**** Mutex handling ****/ - fn handleMutexLock( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - ) -> MutexLockResult; - fn handleMutexTryLock( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - ) -> MutexLockResult; - fn handleMutexUnlock( - self: Pin<&mut MiriGenMCShim>, - thread_id: i32, - address: u64, - size: u64, - ) -> StoreResult; - - /**** Scheduling ****/ - fn scheduleNext( - self: Pin<&mut MiriGenMCShim>, - curr_thread_id: i32, - curr_thread_next_instr_kind: ActionKind, - ) -> i64; - - // TODO GENMC: Replace once VerificationResult is accessible (or at least rename the function). - fn getStuckExecutionCount(self: &MiriGenMCShim) -> u64; - fn isExplorationDone(self: Pin<&mut MiriGenMCShim>) -> bool; - - fn printGraph(self: Pin<&mut MiriGenMCShim>); - fn printEstimationResults(self: &MiriGenMCShim, elapsed_time_sec: f64); + fn createGenmcHandle(config: &GenmcParams) -> UniquePtr; } } diff --git a/genmc-sys/src_cpp/MiriInterface.cpp b/genmc-sys/src_cpp/MiriInterface.cpp index c014def853..3e6921eb2a 100644 --- a/genmc-sys/src_cpp/MiriInterface.cpp +++ b/genmc-sys/src_cpp/MiriInterface.cpp @@ -2,103 +2,41 @@ #include "genmc-sys/src/lib.rs.h" -#include "ExecutionGraph/EventLabel.hpp" -#include "Support/ASize.hpp" -#include "Support/Error.hpp" -#include "Support/Logger.hpp" -#include "Support/MemAccess.hpp" -#include "Support/MemOrdering.hpp" -#include "Support/MemoryModel.hpp" -#include "Support/RMWOps.hpp" -#include "Support/SAddr.hpp" -#include "Support/SVal.hpp" -#include "Support/ThreadInfo.hpp" -#include "Support/Verbosity.hpp" -#include "Verification/DriverEnumAPI.hpp" -#include "Verification/GenMCDriver.hpp" - -#include -#include -#include -#include - -using AnnotID = ModuleID_ID; -using AnnotT = SExpr; - -// Return -1 when no thread can/should be scheduled, or the thread id of the next thread -// NOTE: this is safe because ThreadId is 32 bit, and we return a 64 bit integer -// TODO GENMC: could directly return std::optional if CXX ever supports this -auto MiriGenMCShim::scheduleNext(const int curr_thread_id, - const ActionKind curr_thread_next_instr_kind) -> int64_t -{ - // The current thread is the only one where the `kind` could have changed since we last made - // a scheduling decision. - globalInstructions[curr_thread_id].kind = curr_thread_next_instr_kind; - - auto result = GenMCDriver::scheduleNext(globalInstructions); - if (result.has_value()) { - return static_cast(result.value()); - } - return -1; -} - -/**** Functions available to Miri ****/ - // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto MiriGenMCShim::createHandle(const GenmcParams &config, bool estimation_mode) +auto MiriGenMCShim::createHandle(const GenmcParams &config) -> std::unique_ptr { auto vConf = std::make_shared(); - // TODO GENMC: Can we get some default values somehow? - // Config::saveConfigOptions(*vConf); - - // NOTE: Miri already initialization checks, so we can disable them in GenMC - vConf->skipNonAtomicInitializedCheck = true; // Miri needs all threads to be replayed, even fully completed ones. vConf->replayCompletedThreads = true; - // TODO GENMC: make sure this doesn't affect any tests, and maybe make it changeable from - // Miri: - constexpr unsigned int DEFAULT_WARN_ON_GRAPH_SIZE = 16 * 1024; - vConf->warnOnGraphSize = DEFAULT_WARN_ON_GRAPH_SIZE; + // We only support the RC11 memory model for Rust. vConf->model = ModelType::RC11; - vConf->randomScheduleSeed = - "42"; // TODO GENMC: only for random exploration/scheduling mode in GenMC + vConf->printRandomScheduleSeed = config.print_random_schedule_seed; - if (config.quiet) { - // logLevel = VerbosityLevel::Quiet; - // TODO GENMC: error might be better (or new level for `BUG`) - // logLevel = VerbosityLevel::Quiet; - logLevel = VerbosityLevel::Error; - } else if (config.log_level_trace) { - logLevel = VerbosityLevel::Trace; - } else { - logLevel = VerbosityLevel::Tip; - } - // TODO GENMC (EXTRA): check if we can enable IPR: + // FIXME(GenMC): disable any options we don't support currently: vConf->ipr = false; - // TODO GENMC (EXTRA): check if we can enable BAM: vConf->disableBAM = true; - // TODO GENMC (EXTRA): check if we can enable Symmetry Reduction: - vConf->symmetryReduction = config.do_symmetry_reduction; - - // TODO GENMC (EXTRA): check if we can do instruction caching (probably not) vConf->instructionCaching = false; - // TODO GENMC: Should there be a way to change this option from Miri? + ERROR_ON(config.do_symmetry_reduction, "Symmetry reduction is currently unsupported in GenMC mode."); + vConf->symmetryReduction = config.do_symmetry_reduction; + + // FIXME(GenMC): Should there be a way to change this option from Miri? vConf->schedulePolicy = SchedulePolicy::WF; - vConf->estimate = estimation_mode; - vConf->estimationMax = config.estimation_max; + // FIXME(GenMC): implement estimation mode: + vConf->estimate = false; + vConf->estimationMax = 1000; const auto mode = vConf->estimate ? GenMCDriver::Mode(GenMCDriver::EstimationMode{}) - : GenMCDriver::Mode(GenMCDriver::VerificationMode{}); + : GenMCDriver::Mode(GenMCDriver::VerificationMode{}); - // With `disableRaceDetection = true`, the scheduler would be incorrectly replaying - // executions with Miri, since we can only schedule at Mir terminators, and each Mir - // terminator can generate multiple events in the ExecutionGraph. - // Users running Miri-GenMC most likely want to always have race detection enabled anyway. + // Running Miri-GenMC without race detection is not supported. + // Disabling this option also changes the behavior of the replay scheduler to only schedule at atomic operations, which is required with Miri. + // This happens because Miri can generate multiple GenMC events for a single MIR terminator. Without this option, + // the scheduler might incorrectly schedule an atomic MIR terminator because the first event it creates is a non-atomic (e.g., `StorageLive`). vConf->disableRaceDetection = false; // Miri can already check for unfreed memory. Also, GenMC cannot distinguish between memory @@ -108,417 +46,5 @@ auto MiriGenMCShim::createHandle(const GenmcParams &config, bool estimation_mode checkVerificationConfigOptions(*vConf); auto driver = std::make_unique(std::move(vConf), mode); - - auto *driverPtr = driver.get(); - auto initValGetter = [driverPtr](const AAccess &access) { - const auto addr = access.getAddr(); - if (!driverPtr->initVals_.contains(addr)) { - MIRI_LOG() << "WARNING: TODO GENMC: requested initial value for address " - << addr << ", but there is none.\n"; - return SVal(0xCC00CC00); - // BUG_ON(!driverPtr->initVals_.contains(addr)); - } - auto result = driverPtr->initVals_[addr]; - if (!result.is_init) { - MIRI_LOG() << "WARNING: TODO GENMC: requested initial value for address " - << addr << ", but the memory is uninitialized.\n"; - return SVal(0xFF00FF00); - } - MIRI_LOG() << "MiriGenMCShim: requested initial value for address " << addr - << " == " << addr.get() << ", returning: " << result << "\n"; - return result.toSVal(); - }; - driver->getExec().getGraph().setInitValGetter(initValGetter); - return driver; } - -// This needs to be available to Miri, but clang-tidy wants it static -// NOLINTNEXTLINE(misc-use-internal-linkage) -auto createGenmcHandle(const GenmcParams &config, bool estimation_mode) - -> std::unique_ptr -{ - return MiriGenMCShim::createHandle(config, estimation_mode); -} - -/**** Execution start/end handling ****/ - -void MiriGenMCShim::handleExecutionStart() -{ - // TODO GENMC: reset completely or just set to init event for each thread? - globalInstructions.clear(); - globalInstructions.push_back(Action(ActionKind::Load, Event::getInit())); - // for (auto &action : globalInstructions) { - // action.event.index = 0; - // action.kind = ActionKind::Load; - // } - GenMCDriver::handleExecutionStart(); -} - -auto MiriGenMCShim::handleExecutionEnd() -> std::unique_ptr -{ - return GenMCDriver::handleExecutionEnd(globalInstructions); -} - -/**** Thread management ****/ - -void MiriGenMCShim::handleThreadCreate(ThreadId thread_id, ThreadId parent_id) -{ - // NOTE: The threadCreate event happens in the parent: - auto pos = incPos(parent_id); - - const unsigned funId = 0; // TODO GENMC - const SVal arg = SVal(0); // TODO GENMC - const ThreadInfo childInfo = ThreadInfo{thread_id, parent_id, funId, arg}; - - // NOTE: Default GenMC ordering used here - auto tcLab = std::make_unique(pos, childInfo); - auto createLab = GenMCDriver::handleThreadCreate(std::move(tcLab)); - auto genmcTid = createLab->getChildId(); - - BUG_ON(genmcTid != thread_id); - BUG_ON(genmcTid == -1); // TODO GENMC (ERROR HANDLING): proper error handling - BUG_ON(genmcTid > globalInstructions.size()); - - // TODO GENMC: should both these be possible? - if (genmcTid >= globalInstructions.size()) - globalInstructions.push_back(Action(ActionKind::Load, Event(genmcTid, 0))); - else - globalInstructions[genmcTid] = Action(ActionKind::Load, Event(genmcTid, 0)); -} - -void MiriGenMCShim::handleThreadJoin(ThreadId thread_id, ThreadId child_id) -{ - auto parentTid = thread_id; - auto childTid = child_id; - - // NOTE: The thread join event happens in the parent: - auto pos = incPos(parentTid); - - // NOTE: Default GenMC ordering used here - auto lab = std::make_unique(pos, childTid); - auto res = GenMCDriver::handleThreadJoin(std::move(lab)); - // TODO GENMC: use return value if needed - if (res.has_value()) { - MIRI_LOG() << "TODO GENMC: GenMC::handleThreadJoin: returned value: " - << res.getValue() << "\n"; - } else { - MIRI_LOG() << "MiriGenMCShim::handleThreadJoin got no value."; - decPos(parentTid); - } -} - -void MiriGenMCShim::handleThreadFinish(ThreadId thread_id, uint64_t ret_val) -{ - MIRI_LOG() << "GenMC: handleThreadFinish: thread id: " << thread_id << "\n"; - - auto pos = incPos(thread_id); - auto retVal = SVal(ret_val); - - // NOTE: Default GenMC ordering used here - auto eLab = std::make_unique(pos, retVal); - - GenMCDriver::handleThreadFinish(std::move(eLab)); -} - -/**** Blocking instructions ****/ - -void MiriGenMCShim::handleUserBlock(ThreadId thread_id) -{ - - auto pos = incPos(thread_id); - auto bLab = UserBlockLabel::create(/* EventLabelKind::UserBlock, */ pos); - GenMCDriver::handleBlock(std::move(bLab)); - // TODO GENMC: could this ever fail? -} - -/**** Memory access handling ****/ - -[[nodiscard]] auto MiriGenMCShim::handleLoad(ThreadId thread_id, uint64_t address, uint64_t size, - MemOrdering ord, GenmcScalar old_val) -> LoadResult -{ - MIRI_LOG() << "Received Load from Miri at address: " << address << ", size " << size - << " with ordering " << ord << "\n"; - - auto pos = incPos(thread_id); - - auto loc = SAddr(address); - auto aSize = ASize(size); - auto type = AType::Unsigned; // TODO GENMC: get correct type from Miri - - auto newLab = std::make_unique(pos, ord, loc, aSize, type); - - auto oldValSetter = [this, old_val](SAddr loc) { this->handleOldVal(loc, old_val); }; - auto result = GenMCDriver::handleLoad(std::move(newLab), oldValSetter); - return result; -} - -[[nodiscard]] auto MiriGenMCShim::handleReadModifyWrite(ThreadId thread_id, uint64_t address, - uint64_t size, MemOrdering loadOrd, - MemOrdering store_ordering, RMWBinOp rmw_op, - GenmcScalar rhs_value, GenmcScalar old_val) - -> ReadModifyWriteResult -{ - MIRI_LOG() << "Received Read-Modify-Write from Miri at address: " << address << ", size " - << size << " with orderings (" << loadOrd << ", " << store_ordering - << "), rmw op: " << static_cast(rmw_op) << "\n"; - - auto pos = incPos(thread_id); - - auto loc = SAddr(address); - auto aSize = ASize(size); - auto type = AType::Unsigned; - - auto rhsVal = rhs_value.toSVal(); - auto newLab = - std::make_unique(pos, loadOrd, loc, aSize, type, rmw_op, rhsVal); - - auto oldValSetter = [this, old_val](SAddr loc) { this->handleOldVal(loc, old_val); }; - auto result = GenMCDriver::handleLoad(std::move(newLab), oldValSetter); - if (const auto *error = result.error.get()) { - return ReadModifyWriteResult::fromError(*error); - } - - auto oldVal = result.scalar.toSVal(); // TODO GENMC: u128 handling - auto newVal = executeRMWBinOp(oldVal, rhsVal, size, rmw_op); - - auto store_result = handleStore(thread_id, address, size, GenmcScalar(newVal), old_val, - store_ordering, StoreEventType::ReadModifyWrite); - - if (store_result.is_error()) - return ReadModifyWriteResult::fromError(*store_result.error.get()); - return ReadModifyWriteResult(oldVal, newVal, store_result.isCoMaxWrite); -} - -[[nodiscard]] auto MiriGenMCShim::handleCompareExchange( - ThreadId thread_id, uint64_t address, uint64_t size, GenmcScalar expected_value, - GenmcScalar new_value, GenmcScalar old_val, MemOrdering success_load_ordering, - MemOrdering success_store_ordering, MemOrdering fail_load_ordering, - bool can_fail_spuriously) -> CompareExchangeResult -{ - - MIRI_LOG() << "Received Compare-Exchange from Miri (value: " << expected_value << " --> " - << new_value << ", old value: " << old_val << ") at address: " << address - << ", size " << size << " with success orderings (" << success_load_ordering - << ", " << success_store_ordering - << "), fail load ordering: " << fail_load_ordering - << ", is weak (can fail spuriously): " << can_fail_spuriously << "\n"; - - auto pos = incPos(thread_id); - - auto loc = SAddr(address); - auto aSize = ASize(size); - auto type = AType::Unsigned; - - auto expectedVal = expected_value.toSVal(); - auto newVal = new_value.toSVal(); - - // FIXME(GenMC): properly handle failure memory ordering. - - auto newLab = std::make_unique(pos, success_load_ordering, loc, aSize, type, - expectedVal, newVal); - - auto oldValSetter = [this, old_val](SAddr loc) { this->handleOldVal(loc, old_val); }; - auto result = GenMCDriver::handleLoad(std::move(newLab), oldValSetter); - if (const auto *error = result.error.get()) { - return CompareExchangeResult::fromError(*error); - } - - auto oldVal = result.scalar.toSVal(); - if (oldVal != expectedVal) - return CompareExchangeResult::failure(oldVal); - - auto store_result = handleStore(thread_id, address, size, GenmcScalar(newVal), old_val, - success_store_ordering, StoreEventType::CompareExchange); - - if (store_result.is_error()) - return CompareExchangeResult::fromError(*store_result.error); - return CompareExchangeResult::success(oldVal, store_result.isCoMaxWrite); -} - -[[nodiscard]] auto MiriGenMCShim::handleStore(ThreadId thread_id, uint64_t address, uint64_t size, - GenmcScalar value, GenmcScalar old_val, - MemOrdering ord, StoreEventType store_event_type) - -> StoreResult -{ - MIRI_LOG() << "Received Store from Miri at address " << address << ", size " << size - << " with ordering " << ord << ", is part of rmw: (" - << static_cast(store_event_type) << ")\n"; - - auto pos = incPos(thread_id); - - auto loc = SAddr(address); // TODO GENMC: called addr for write, loc for read? - auto aSize = ASize(size); - auto type = AType::Unsigned; // TODO GENMC: get from Miri - - // TODO GENMC: u128 support - auto val = value.toSVal(); - - std::unique_ptr wLab; - switch (store_event_type) { - case StoreEventType::Normal: - wLab = std::make_unique(pos, ord, loc, aSize, type, val); - break; - case StoreEventType::ReadModifyWrite: - wLab = std::make_unique(pos, ord, loc, aSize, type, val); - break; - case StoreEventType::CompareExchange: - wLab = std::make_unique(pos, ord, loc, aSize, type, val); - break; - case StoreEventType::MutexUnlockWrite: - wLab = UnlockWriteLabel::create(pos, ord, loc, aSize, AType::Signed, val); - break; - default: - ERROR("Unsupported Store Event Type"); - } - - auto oldValSetter = [this, old_val](SAddr loc) { - this->handleOldVal(loc, - old_val); // TODO GENMC(HACK): is this the correct way to do it? - }; - - return GenMCDriver::handleStore(std::move(wLab), oldValSetter); -} - -void MiriGenMCShim::handleFence(ThreadId thread_id, MemOrdering ord) -{ - MIRI_LOG() << "Received fence operation from Miri with ordering " << ord << "\n"; - - auto pos = incPos(thread_id); - - auto fLab = std::make_unique(pos, ord); - GenMCDriver::handleFence(std::move(fLab)); -} - -/**** Memory (de)allocation ****/ - -auto MiriGenMCShim::handleMalloc(ThreadId thread_id, uint64_t size, uint64_t alignment) -> uintptr_t -{ - BUG_ON(size == 0); - auto pos = incPos(thread_id); - - MIRI_LOG() << "handleMalloc: thread " << thread_id << ", new MallocLabel at position {" - << pos.thread << ", " << pos.index << "}\n"; - - auto sd = StorageDuration::SD_Heap; // TODO GENMC: get from Miri - auto stype = StorageType::ST_Durable; // TODO GENMC - auto spc = AddressSpace::AS_User; // TODO GENMC - - auto deps = EventDeps(); // TODO GENMC: without this, constructor is ambiguous - - // TODO GENMC (types): size_t vs unsigned int - auto aLab = std::make_unique(pos, size, alignment, sd, stype, spc, deps); - - SAddr retVal = GenMCDriver::handleMalloc(std::move(aLab)); - - BUG_ON(retVal.get() == 0); - - auto address = retVal.get(); - return address; -} - -void MiriGenMCShim::handleFree(ThreadId thread_id, uint64_t address, uint64_t size) -{ - MIRI_LOG() << "GENMC: handleFree called (address: " << address << ", size: " << size - << ")\n"; - BUG_ON(size == 0); - - auto addr = SAddr(address); - auto alloc_size = SAddr(size); - BUG_ON(addr.get() == 0); - - auto pos = incPos(thread_id); - - auto dLab = std::make_unique(pos, addr, size); - GenMCDriver::handleFree(std::move(dLab)); -} - -/**** Mutex handling ****/ - -auto MiriGenMCShim::handleMutexLock(ThreadId thread_id, uint64_t address, uint64_t size) - -> MutexLockResult -{ - // TODO GENMC: this needs to be identical even in multithreading - unsigned int annot_id; - if (annotation_id.contains(address)) { - annot_id = annotation_id.at(address); - } else { - annot_id = annotation_id_counter++; - annotation_id.insert(std::make_pair(address, annot_id)); - } - auto annot = std::move(Annotation( - AssumeType::Spinloop, - Annotation::ExprVP(NeExpr::create( - RegisterExpr::create(size * CHAR_BIT, annot_id), - ConcreteExpr::create(size * CHAR_BIT, SVal(1))) - .release()))); - - auto &currPos = globalInstructions[thread_id].event; - // auto rLab = LockCasReadLabel::create(++currPos, address, size); - auto rLab = LockCasReadLabel::create(++currPos, address, size, annot); - - // Mutex starts out unlocked, so we always say the previous value is "unlocked". - auto oldValSetter = [this](SAddr loc) { this->handleOldVal(loc, SVal(0)); }; - LoadResult loadResult = GenMCDriver::handleLoad(std::move(rLab), oldValSetter); - if (loadResult.is_error()) { - --currPos; - return MutexLockResult::fromError(*loadResult.error); - } else if (loadResult.is_read_opt) { - --currPos; - // TODO GENMC: is_read_opt == Mutex is acquired - // None --> Someone else has lock, this thread will be rescheduled later (currently - // block) 0 --> Got the lock 1 --> Someone else has lock, this thread will - // not be rescheduled later (block on Miri side) - return MutexLockResult(false); - } - // TODO GENMC(QUESTION): is the `isBlocked` even needed? - // if (!loadResult.has_value() || getCurThr().isBlocked()) - // return; - - const bool is_lock_acquired = loadResult.getValue() == SVal(0); - if (is_lock_acquired) { - auto wLab = LockCasWriteLabel::create(++currPos, address, size); - StoreResult storeResult = GenMCDriver::handleStore(std::move(wLab), oldValSetter); - if (storeResult.is_error()) - return MutexLockResult::fromError(*storeResult.error); - - } else { - auto bLab = LockNotAcqBlockLabel::create(++currPos); - GenMCDriver::handleBlock(std::move(bLab)); - } - - return MutexLockResult(is_lock_acquired); -} - -auto MiriGenMCShim::handleMutexTryLock(ThreadId thread_id, uint64_t address, uint64_t size) - -> MutexLockResult -{ - auto &currPos = globalInstructions[thread_id].event; - auto rLab = TrylockCasReadLabel::create(++currPos, address, size); - // Mutex starts out unlocked, so we always say the previous value is "unlocked". - auto oldValSetter = [this](SAddr loc) { this->handleOldVal(loc, SVal(0)); }; - LoadResult loadResult = GenMCDriver::handleLoad(std::move(rLab), oldValSetter); - if (!loadResult.has_value()) { - --currPos; - // TODO GENMC: maybe use std move and make it take a unique_ptr ? - return MutexLockResult::fromError(*loadResult.error); - } - - const bool is_lock_acquired = loadResult.getValue() == SVal(0); - if (!is_lock_acquired) - return MutexLockResult(false); /* Lock already held. */ - - auto wLab = TrylockCasWriteLabel::create(++currPos, address, size); - StoreResult storeResult = GenMCDriver::handleStore(std::move(wLab), oldValSetter); - if (storeResult.is_error()) - return MutexLockResult::fromError(*storeResult.error); - - return MutexLockResult(true); -} - -auto MiriGenMCShim::handleMutexUnlock(ThreadId thread_id, uint64_t address, uint64_t size) - -> StoreResult -{ - return handleStore(thread_id, address, size, SVal(0), SVal(0xDEADBEEF), - MemOrdering::Release, StoreEventType::MutexUnlockWrite); -} diff --git a/genmc-sys/src_cpp/MiriInterface.hpp b/genmc-sys/src_cpp/MiriInterface.hpp index 8c29fc1477..9d07182ac3 100644 --- a/genmc-sys/src_cpp/MiriInterface.hpp +++ b/genmc-sys/src_cpp/MiriInterface.hpp @@ -1,232 +1,42 @@ -#ifndef GENMC_GENMC_MIRI_INTERFACE_HPP -#define GENMC_GENMC_MIRI_INTERFACE_HPP +#ifndef GENMC_MIRI_INTERFACE_HPP +#define GENMC_MIRI_INTERFACE_HPP #include "rust/cxx.h" -#include "ExecutionGraph/EventLabel.hpp" -#include "Support/MemOrdering.hpp" -#include "Support/RMWOps.hpp" #include "Verification/GenMCDriver.hpp" #include "Verification/VerificationConfig.hpp" -#include -#include -#include +#include /**** Types available to Miri ****/ +// Config struct defined on the Rust side and translated to C++ by cxx.rs: struct GenmcParams; -using ThreadId = int; - -enum class StoreEventType : uint8_t { - Normal, - ReadModifyWrite, - CompareExchange, - MutexUnlockWrite, -}; - -struct MutexLockResult { - bool is_lock_acquired; - std::unique_ptr error; // TODO GENMC: pass more error info here - - MutexLockResult(bool is_lock_acquired) : is_lock_acquired(is_lock_acquired), error(nullptr) - {} - - static auto fromError(std::string msg) -> MutexLockResult - { - auto res = MutexLockResult(false); - res.error = std::make_unique(msg); - return res; - } -}; - -// TODO GENMC: fix naming conventions - -struct MiriGenMCShim : private GenMCDriver { +struct MiriGenMCShim : private GenMCDriver +{ public: MiriGenMCShim(std::shared_ptr vConf, Mode mode /* = VerificationMode{} */) : GenMCDriver(std::move(vConf), nullptr, mode) { - globalInstructions.reserve(8); - globalInstructions.push_back(Action(ActionKind::Load, Event::getInit())); + std::cerr << "C++: GenMC handle created!" << std::endl; } - virtual ~MiriGenMCShim() {} - - /**** Execution start/end handling ****/ - - void handleExecutionStart(); - std::unique_ptr handleExecutionEnd(); - - /**** Memory access handling ****/ - - /////////////////// - [[nodiscard]] LoadResult handleLoad(ThreadId thread_id, uint64_t address, uint64_t size, - MemOrdering ord, GenmcScalar old_val); - [[nodiscard]] ReadModifyWriteResult - handleReadModifyWrite(ThreadId thread_id, uint64_t address, uint64_t size, - MemOrdering loadOrd, MemOrdering store_ordering, RMWBinOp rmw_op, - GenmcScalar rhs_value, GenmcScalar old_val); - [[nodiscard]] CompareExchangeResult - handleCompareExchange(ThreadId thread_id, uint64_t address, uint64_t size, - GenmcScalar expected_value, GenmcScalar new_value, - GenmcScalar old_val, MemOrdering success_load_ordering, - MemOrdering success_store_ordering, MemOrdering fail_load_ordering, - bool can_fail_spuriously); - [[nodiscard]] StoreResult handleStore(ThreadId thread_id, uint64_t address, uint64_t size, - GenmcScalar value, GenmcScalar old_val, - MemOrdering ord, StoreEventType store_event_type); - - void handleFence(ThreadId thread_id, MemOrdering ord); - - /**** Memory (de)allocation ****/ - - uintptr_t handleMalloc(ThreadId thread_id, uint64_t size, uint64_t alignment); - void handleFree(ThreadId thread_id, uint64_t address, uint64_t size); - - /**** Thread management ****/ - - void handleThreadCreate(ThreadId thread_id, ThreadId parent_id); - void handleThreadJoin(ThreadId thread_id, ThreadId child_id); - void handleThreadFinish(ThreadId thread_id, uint64_t ret_val); - - /**** Blocking instructions ****/ - - void handleUserBlock(ThreadId thread_id); - - /**** Mutex handling ****/ - auto handleMutexLock(ThreadId thread_id, uint64_t address, uint64_t size) - -> MutexLockResult; - auto handleMutexTryLock(ThreadId thread_id, uint64_t address, uint64_t size) - -> MutexLockResult; - auto handleMutexUnlock(ThreadId thread_id, uint64_t address, uint64_t size) -> StoreResult; - - /**** Scheduling queries ****/ - - // TODO GENMC: implement - - auto scheduleNext(const int curr_thread_id, const ActionKind curr_thread_next_instr_kind) - -> int64_t; - - /**** TODO GENMC: Other stuff: ****/ - - auto getStuckExecutionCount() const -> uint64_t - { - return static_cast(getResult().exploredBlocked); - } - - bool isExplorationDone() { return GenMCDriver::done(); } - - /**** OTHER ****/ - - auto incPos(ThreadId tid) -> Event - { - ERROR_ON(tid >= globalInstructions.size(), "ThreadId out of bounds"); - return ++globalInstructions[tid].event; - } - auto decPos(ThreadId tid) -> Event + virtual ~MiriGenMCShim() { - ERROR_ON(tid >= globalInstructions.size(), "ThreadId out of bounds"); - return --globalInstructions[tid].event; + std::cerr << "C++: GenMC handle destroyed!" << std::endl; } - void printGraph() { GenMCDriver::debugPrintGraph(); } - - void printEstimationResults(const double elapsed_time_sec) const - { - // TODO GENMC(CLEANUP): should this happen on the Rust side? - const auto &res = getResult(); - const auto *vConf = getConf(); - - auto mean = std::llround(res.estimationMean); - auto sd = std::llround(std::sqrt(res.estimationVariance)); - auto meanTimeSecs = (long double)elapsed_time_sec / (res.explored + res.exploredBlocked); - // FIXME(io): restore the old precision after the print? - PRINT(VerbosityLevel::Error) - << "Finished estimation in " << std::setprecision(2) << elapsed_time_sec << " seconds.\n\n" - << "Total executions estimate: " << mean << " (+- " << sd << ")\n" - << "Time to completion estimate: " - << std::setprecision(2) << (meanTimeSecs * mean) << "s\n"; - GENMC_DEBUG(if (vConf->printEstimationStats) PRINT(VerbosityLevel::Error) - << "Estimation moot: " << res.exploredMoot << "\n" - << "Estimation blocked: " << res.exploredBlocked << "\n" - << "Estimation complete: " << res.explored << "\n";); - } - - static std::unique_ptr createHandle(const GenmcParams &config, - bool estimation_mode); - -private: - /** - * @brief Try to insert the initial value of a memory location. - * @param addr - * @param value - * */ - void handleOldVal(const SAddr addr, GenmcScalar value) - { - MIRI_LOG() << "handleOldVal: " << addr << ", " << value.value << ", " << value.extra - << ", " << value.is_init << "\n"; - // if (!value.is_init) { - // // // TODO GENMC(uninit value handling) - // // MIRI_LOG() << "WARNING: got uninitialized old value, ignoring ...\n"; - // // return; - // MIRI_LOG() << "WARNING: got uninitialized old value, converting to dummy " - // "value ...\n"; - // value.is_init = true; - // value.value = 0xAAFFAAFF; - // } - - // TODO GENMC(CLEANUP): Pass this as a parameter: - auto &g = getExec().getGraph(); - auto *coLab = g.co_max(addr); - MIRI_LOG() << "handleOldVal: coLab: " << *coLab << "\n"; - if (auto *wLab = llvm::dyn_cast(coLab)) { - MIRI_LOG() << "handleOldVal: got WriteLabel, atomic: " << wLab->isAtomic() - << "\n"; - if (!value.is_init) - MIRI_LOG() << "WARNING: TODO GENMC: handleOldVal tried to " - "overwrite value of NA " - "reads-from label, but old value is `uninit`\n"; - else if (wLab->isNotAtomic()) - wLab->setVal(value.toSVal()); - } else if (const auto *wLab = llvm::dyn_cast(coLab)) { - if (value.is_init) { - auto result = initVals_.insert(std::make_pair(addr, value)); - MIRI_LOG() << "handleOldVal: got InitLabel, insertion result: " - << result.first->second << ", " << result.second << "\n"; - BUG_ON(result.second && - (*result.first).second != - value); /* Attempt to replace initial value */ - } else { - // LOG(VerbosityLevel::Error) << - MIRI_LOG() << "WARNING: TODO GENMC: handleOldVal tried set initial " - "value, but old " - "value is `uninit`\n"; - } - } else { - BUG(); /* Invalid label */ - } - // either initLabel ==> update initValGetter - // or WriteLabel ==> Update its value in place (only if non-atomic) - } - - // TODO GENMC(mixed-size accesses): - std::unordered_map initVals_{}; - - std::vector globalInstructions; - - std::unordered_map annotation_id{}; - unsigned int annotation_id_counter = 0; + static std::unique_ptr createHandle(const GenmcParams &config); }; /**** Functions available to Miri ****/ -// NOTE: CXX doesn't seem to support exposing static methods to Rust, so we expose this -// function instead -std::unique_ptr createGenmcHandle(const GenmcParams &config, bool estimation_mode); - -constexpr auto getGlobalAllocStaticMask() -> uint64_t { return SAddr::staticMask; } +// NOTE: CXX doesn't support exposing static methods to Rust currently, so we expose this function instead. +static inline auto createGenmcHandle(const GenmcParams &config) -> std::unique_ptr +{ + return MiriGenMCShim::createHandle(config); +} -#endif /* GENMC_GENMC_MIRI_INTERFACE_HPP */ +#endif /* GENMC_MIRI_INTERFACE_HPP */ diff --git a/src/alloc_addresses/mod.rs b/src/alloc_addresses/mod.rs index 2beb309078..3cc38fa087 100644 --- a/src/alloc_addresses/mod.rs +++ b/src/alloc_addresses/mod.rs @@ -33,7 +33,6 @@ pub struct GlobalStateInner { /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset /// from the base address, and we need to find the `AllocId` it belongs to. This is not the /// *full* inverse of `base_addr`; dead allocations have been removed. - /// TODO GENMC: keep dead allocations in GenMC mode? int_to_ptr_map: Vec<(u64, AllocId)>, /// The base address for each allocation. We cannot put that into /// `AllocExtra` because function pointers also have a base address, and @@ -99,8 +98,7 @@ impl GlobalStateInner { /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple /// of `align` that is larger or equal to `addr` -/// FIXME(GenMC): is it ok to make this public? -pub(crate) fn align_addr(addr: u64, align: u64) -> u64 { +fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, rem => addr.strict_add(align) - rem, @@ -121,7 +119,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miri's address assignment leaks state across thread boundaries, which is incompatible // with GenMC execution. So we instead let GenMC assign addresses to allocations. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - return genmc_ctx.handle_alloc(this, alloc_id, info.size, info.align, memory_kind); + let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?; + return interp_ok(addr); } let mut rng = this.machine.rng.borrow_mut(); @@ -263,10 +262,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only use this provenance if it has been exposed, or if the caller requested also non-exposed allocations if !only_exposed_allocations || global_state.exposed.contains(&alloc_id) { // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - // In GenMC mode, we keep all allocations, so this check doesn't apply there. - debug_assert!( - this.machine.data_race.as_genmc_ref().is_some() || this.is_alloc_live(alloc_id) - ); + debug_assert!(this.is_alloc_live(alloc_id)); Some(alloc_id) } else { None @@ -497,15 +493,11 @@ impl<'tcx> MiriMachine<'tcx> { let addr = *global_state.base_addr.get(&dead_id).unwrap(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr).unwrap(); - - // TODO GENMC(DOCUMENTATION): - if self.data_race.as_genmc_ref().is_none() { - let removed = global_state.int_to_ptr_map.remove(pos); - assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing - // We can also remove it from `exposed`, since this allocation can anyway not be returned by - // `alloc_id_from_addr` any more. - global_state.exposed.remove(&dead_id); - } + let removed = global_state.int_to_ptr_map.remove(pos); + assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing + // We can also remove it from `exposed`, since this allocation can anyway not be returned by + // `alloc_id_from_addr` any more. + global_state.exposed.remove(&dead_id); // Also remember this address for future reuse. let thread = self.threads.active_thread(); global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ccdd4eb2ab..a96915a6cc 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -39,7 +39,7 @@ use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use miri::{ BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType, - ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, miri_genmc, + ProvenanceMode, RetagFields, TreeBorrowsParams, ValidationMode, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -193,34 +193,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } if let Some(genmc_config) = &self.genmc_config { - let eval_entry_once = |genmc_ctx: Rc| { - miri::eval_entry(tcx, entry_def_id, entry_type, &config, Some(genmc_ctx)) - }; - - if genmc_config.do_estimation() - && miri_genmc::run_genmc_mode( - &config, - genmc_config, - eval_entry_once, - miri_genmc::Mode::Estimation, - ) - .is_some() - { - tcx.dcx().abort_if_errors(); - } + let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config)); - let return_code = miri_genmc::run_genmc_mode( - &config, - genmc_config, - eval_entry_once, - miri_genmc::Mode::Verification, - ) - .unwrap_or_else(|| { - tcx.dcx().abort_if_errors(); - rustc_driver::EXIT_FAILURE - }); - - exit(return_code); + todo!("GenMC mode not yet implemented"); }; if let Some(many_seeds) = self.many_seeds.take() { @@ -633,6 +608,7 @@ fn main() { // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. miri_config.borrow_tracker = None; } + miri_config.borrow_tracker = None; GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); @@ -769,9 +745,9 @@ fn main() { // Validate settings for data race detection and GenMC mode. assert_eq!(genmc_config.is_some(), miri_config.genmc_mode); - if miri_config.genmc_mode { + if genmc_config.is_some() { if !miri_config.data_race_detector { - fatal_error!("Cannot disable data race detection in GenMC mode"); + fatal_error!("Cannot disable data race detection in GenMC mode (currently)"); } else if !miri_config.weak_memory_emulation { fatal_error!("Cannot disable weak memory emulation in GenMC mode"); } diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c9112cda08..38d76f5cf7 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -71,7 +71,7 @@ pub enum AtomicRwOrd { } /// Valid atomic read orderings, subset of atomic::Ordering. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicReadOrd { Relaxed, Acquire, @@ -719,7 +719,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Only metadata on the location itself is used. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let old_val = this.run_for_validation_ref(|this| this.read_scalar(place)).discard_err(); + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let old_val = None; return genmc_ctx.atomic_load( this, place.ptr().addr(), @@ -751,21 +752,10 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err(); - // Inform GenMC about the atomic store. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - if genmc_ctx.atomic_store( - this, - dest.ptr().addr(), - dest.layout.size, - val, - old_val, - atomic, - )? { - // The store might be the latest store in coherence order (determined by GenMC). - // If it is, we need to update the value in Miri's memory: - this.allow_data_races_mut(|this| this.write_scalar(val, dest))?; - } + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + genmc_ctx.atomic_store(this, dest.ptr().addr(), dest.layout.size, val, atomic)?; return interp_ok(()); } this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; @@ -789,6 +779,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic rmw operation. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics let (old_val, new_val) = genmc_ctx.atomic_rmw_op( this, place.ptr().addr(), @@ -796,11 +787,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { atomic, (op, not), rhs.to_scalar(), - old.to_scalar(), )?; - if let Some(new_val) = new_val { - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; - } + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } @@ -830,19 +818,14 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic atomic exchange. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let (old_val, new_val) = genmc_ctx.atomic_exchange( + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, _is_success) = genmc_ctx.atomic_exchange( this, place.ptr().addr(), place.layout.size, new, atomic, - old, )?; - // The store might be the latest store in coherence order (determined by GenMC). - // If it is, we need to update the value in Miri's memory: - if let Some(new_val) = new_val { - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; - } return interp_ok(old_val); } @@ -868,6 +851,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic min/max operation. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics let (old_val, new_val) = genmc_ctx.atomic_min_max_op( this, place.ptr().addr(), @@ -876,13 +860,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { min, old.layout.backend_repr.is_signed(), rhs.to_scalar(), - old.to_scalar(), )?; - // The store might be the latest store in coherence order (determined by GenMC). - // If it is, we need to update the value in Miri's memory: - if let Some(new_val) = new_val { - this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; - } + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; return interp_ok(ImmTy::from_scalar(old_val, old.layout)); } @@ -924,7 +903,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; - // // FIXME(GenMC): this comment is wrong: // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -933,24 +911,20 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // Inform GenMC about the atomic atomic compare exchange. if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let (old_value, is_co_maximal_write, cmpxchg_success) = genmc_ctx - .atomic_compare_exchange( - this, - place.ptr().addr(), - place.layout.size, - this.read_scalar(expect_old)?, - new, - success, - fail, - can_fail_spuriously, - old.to_scalar(), - )?; - // The store might be the latest store in coherence order (determined by GenMC). - // If it is, we need to update the value in Miri's memory: - if is_co_maximal_write { + let (old, cmpxchg_success) = genmc_ctx.atomic_compare_exchange( + this, + place.ptr().addr(), + place.layout.size, + this.read_scalar(expect_old)?, + new, + success, + fail, + can_fail_spuriously, + )?; + if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, place))?; } - return interp_ok(Immediate::ScalarPair(old_value, Scalar::from_bool(cmpxchg_success))); + return interp_ok(Immediate::ScalarPair(old, Scalar::from_bool(cmpxchg_success))); } // `binary_op` will bail if either of them is not a scalar. @@ -1016,7 +990,6 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(clock, &this.machine.threads); } - // TODO GENMC: does GenMC need to be informed about this? } } diff --git a/src/concurrency/genmc/config.rs b/src/concurrency/genmc/config.rs index aef41a0aa9..dbc546d32c 100644 --- a/src/concurrency/genmc/config.rs +++ b/src/concurrency/genmc/config.rs @@ -1,31 +1,22 @@ use super::GenmcParams; -// TODO GENMC: document this: +/// Configuration for GenMC mode. +/// The `params` field is shared with the C++ side. +/// The remaining options are kept on the Rust side. #[derive(Debug, Default, Clone)] pub struct GenmcConfig { pub(super) params: GenmcParams, - print_exec_graphs: bool, do_estimation: bool, + // FIXME: add remaining options. } impl GenmcConfig { - fn set_log_level_trace(&mut self) { - self.params.quiet = false; - self.params.log_level_trace = true; - } - - pub fn print_exec_graphs(&self) -> bool { - self.print_exec_graphs - } - - pub fn do_estimation(&self) -> bool { - self.do_estimation - } - /// Function for parsing command line options for GenMC mode. + /// /// All GenMC arguments start with the string "-Zmiri-genmc". + /// Passing any GenMC argument will enable GenMC mode. /// - /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed + /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed. pub fn parse_arg(genmc_config: &mut Option, trimmed_arg: &str) { if genmc_config.is_none() { *genmc_config = Some(Default::default()); @@ -33,32 +24,6 @@ impl GenmcConfig { if trimmed_arg.is_empty() { return; // this corresponds to "-Zmiri-genmc" } - let genmc_config = genmc_config.as_mut().unwrap(); - let trimmed_arg = trimmed_arg - .strip_prefix("-") - .unwrap_or_else(|| panic!("Invalid GenMC argument \"-Zmiri-genmc{trimmed_arg}\"")); - if trimmed_arg == "log-trace" { - // TODO GENMC: maybe expand to allow more control over log level? - genmc_config.set_log_level_trace(); - } else if trimmed_arg == "print-graphs" { - // TODO GENMC (DOCUMENTATION) - genmc_config.print_exec_graphs = true; - } else if trimmed_arg == "estimate" { - // TODO GENMC (DOCUMENTATION): naming, off/on by default? - genmc_config.do_estimation = true; - } else if let Some(estimation_max_str) = trimmed_arg.strip_prefix("estimation-max=") { - // TODO GENMC (DOCUMENTATION) - let estimation_max = estimation_max_str - .parse() - .expect("Zmiri-genmc-estimation-max expects a positive integer argument"); - assert!(estimation_max > 0); - genmc_config.params.estimation_max = estimation_max; - } else if trimmed_arg == "symmetry-reduction" { - // TODO GENMC (PERFORMANCE): maybe make this the default, have an option to turn it off instead - genmc_config.params.do_symmetry_reduction = true; - } else { - // TODO GENMC: how to properly handle this? - panic!("Invalid GenMC argument: \"-Zmiri-genmc-{trimmed_arg}\""); - } + // FIXME(GenMC): implement remaining parameters. } } diff --git a/src/concurrency/genmc/cxx_extra.rs b/src/concurrency/genmc/cxx_extra.rs deleted file mode 100644 index 55cfee57ea..0000000000 --- a/src/concurrency/genmc/cxx_extra.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![allow(unused)] // TODO GENMC - -use std::pin::Pin; - -use cxx::UniquePtr; -use cxx::memory::UniquePtrTarget; - -#[repr(transparent)] -pub struct NonNullUniquePtr { - /// SAFETY: `inner` is never `null` - inner: UniquePtr, -} - -impl NonNullUniquePtr { - pub fn new(input: UniquePtr) -> Option { - if input.is_null() { - None - } else { - // SAFETY: `input` is not `null` - Some(unsafe { Self::new_unchecked(input) }) - } - } - - /// SAFETY: caller must ensure that `input` is not `null` - pub unsafe fn new_unchecked(input: UniquePtr) -> Self { - Self { inner: input } - } - - pub fn into_inner(self) -> UniquePtr { - self.inner - } - - pub fn as_mut(&mut self) -> Pin<&mut T> { - let ptr = self.inner.as_mut_ptr(); - - // SAFETY: `inner` is not `null` (type invariant) - let mut_reference = unsafe { ptr.as_mut().unwrap_unchecked() }; - // SAFETY: TODO GENMC (should be the same reason as in CXX crate, but there is no safety comment there) - unsafe { Pin::new_unchecked(mut_reference) } - } -} - -impl AsRef for NonNullUniquePtr { - fn as_ref(&self) -> &T { - // SAFETY: `inner` is not `null` (type invariant) - unsafe { self.inner.as_ref().unwrap_unchecked() } - } -} diff --git a/src/concurrency/genmc/dummy.rs b/src/concurrency/genmc/dummy.rs index 4a09a278d7..3d0558fb68 100644 --- a/src/concurrency/genmc/dummy.rs +++ b/src/concurrency/genmc/dummy.rs @@ -1,10 +1,12 @@ +#![allow(unused)] + use rustc_abi::{Align, Size}; -use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult}; +use rustc_const_eval::interpret::{InterpCx, InterpResult}; use rustc_middle::mir; use crate::{ AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, - MiriMachine, OpTy, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, + MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, }; #[derive(Debug)] @@ -13,18 +15,12 @@ pub struct GenmcCtx {} #[derive(Debug, Default, Clone)] pub struct GenmcConfig {} -// TODO GENMC: add all exposed methods here too - impl GenmcCtx { pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self { unreachable!() } - - pub fn print_estimation_result(&self) { - unreachable!() - } - pub fn get_blocked_execution_count(&self) -> usize { + pub fn get_stuck_execution_count(&self) -> usize { unreachable!() } @@ -71,9 +67,8 @@ impl GenmcCtx { _address: Size, _size: Size, _value: Scalar, - _old_value: Option, _ordering: AtomicWriteOrd, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, ()> { unreachable!() } @@ -91,23 +86,21 @@ impl GenmcCtx { _address: Size, _size: Size, _ordering: AtomicRwOrd, - (_rmw_op, _not): (mir::BinOp, bool), + (rmw_op, not): (mir::BinOp, bool), _rhs_scalar: Scalar, - _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, Scalar)> { unreachable!() } pub(crate) fn atomic_min_max_op<'tcx>( &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _address: Size, - _size: Size, - _ordering: AtomicRwOrd, - _min: bool, - _is_signed: bool, - _rhs_scalar: Scalar, - _old_value: Scalar, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + min: bool, + is_signed: bool, + rhs_scalar: Scalar, ) -> InterpResult<'tcx, (Scalar, Scalar)> { unreachable!() } @@ -119,7 +112,6 @@ impl GenmcCtx { _size: Size, _rhs_scalar: Scalar, _ordering: AtomicRwOrd, - _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, bool)> { unreachable!() } @@ -134,7 +126,6 @@ impl GenmcCtx { _success: AtomicRwOrd, _fail: AtomicReadOrd, _can_fail_spuriously: bool, - _old_value: Scalar, ) -> InterpResult<'tcx, (Scalar, bool)> { unreachable!() } @@ -161,8 +152,7 @@ impl GenmcCtx { pub(crate) fn handle_alloc<'tcx>( &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - _alloc_id: AllocId, + _machine: &MiriMachine<'tcx>, _size: Size, _alignment: Align, _memory_kind: MemoryKind, @@ -173,7 +163,6 @@ impl GenmcCtx { pub(crate) fn handle_dealloc<'tcx>( &self, _machine: &MiriMachine<'tcx>, - _alloc_id: AllocId, _address: Size, _size: Size, _align: Align, @@ -187,8 +176,6 @@ impl GenmcCtx { pub(crate) fn handle_thread_create<'tcx>( &self, _threads: &ThreadManager<'tcx>, - _start_routine: crate::Pointer, - _func_arg: &crate::ImmTy<'tcx>, _new_thread_id: ThreadId, ) -> InterpResult<'tcx, ()> { unreachable!() @@ -202,19 +189,14 @@ impl GenmcCtx { unreachable!() } - pub(crate) fn handle_thread_stack_empty<'tcx>( - &self, - _threads: &ThreadManager<'tcx>, - _thread_id: ThreadId, - ) { - unreachable!() - } - - pub(crate) fn handle_main_thread_stack_empty<'tcx>(&self, _threads: &ThreadManager<'tcx>) { + pub(crate) fn handle_thread_stack_empty(&self, _thread_id: ThreadId) { unreachable!() } - pub(crate) fn handle_thread_finish<'tcx>(&self, _threads: &ThreadManager<'tcx>) { + pub(crate) fn handle_thread_finish<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + ) -> InterpResult<'tcx, ()> { unreachable!() } @@ -226,24 +208,14 @@ impl GenmcCtx { ) -> InterpResult<'tcx, ThreadId> { unreachable!() } -} - -/// Other functionality not directly related to event handling -impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn check_genmc_intercept_function( - &mut self, - _instance: rustc_middle::ty::Instance<'tcx>, - _args: &[rustc_const_eval::interpret::FnArg<'tcx, crate::Provenance>], - _dest: &crate::PlaceTy<'tcx>, - _ret: Option, - ) -> InterpResult<'tcx, bool> { - unreachable!() - } /**** Blocking instructions ****/ - fn handle_genmc_verifier_assume(&mut self, _condition: &OpTy<'tcx>) -> InterpResult<'tcx> { + pub(crate) fn handle_verifier_assume<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _condition: bool, + ) -> InterpResult<'tcx, ()> { unreachable!() } } @@ -261,11 +233,7 @@ impl GenmcConfig { ); } - pub fn print_exec_graphs(&self) -> bool { - unreachable!() - } - - pub fn do_estimation(&self) -> bool { + pub fn should_print_graph(&self, _rep: usize) -> bool { unreachable!() } } diff --git a/src/concurrency/genmc/global_allocations.rs b/src/concurrency/genmc/global_allocations.rs deleted file mode 100644 index e2fafba9cc..0000000000 --- a/src/concurrency/genmc/global_allocations.rs +++ /dev/null @@ -1,145 +0,0 @@ -use std::cmp::max; -use std::collections::hash_map::Entry; -use std::sync::RwLock; - -use genmc_sys::{GENMC_GLOBAL_ADDRESSES_MASK, getGlobalAllocStaticMask}; -use rand::rngs::StdRng; -use rand::{Rng, SeedableRng}; -use rustc_const_eval::interpret::{ - AllocId, AllocInfo, AllocKind, InterpResult, PointerArithmetic, interp_ok, -}; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::{err_exhaust, throw_exhaust}; -use tracing::info; - -use crate::alloc_addresses::align_addr; - -#[derive(Debug, Default)] -pub struct GlobalAllocationHandler { - inner: RwLock, -} - -/// This contains more or less a subset of the functionality of `struct GlobalStateInner` in `alloc_addresses`. -#[derive(Clone, Debug)] -struct GlobalStateInner { - /// This is used as a map between the address of each allocation and its `AllocId`. It is always - /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset - /// from the base address, and we need to find the `AllocId` it belongs to. This is not the - /// *full* inverse of `base_addr`; dead allocations have been removed. - #[allow(unused)] // FIXME(GenMC): do we need this? - int_to_ptr_map: Vec<(u64, AllocId)>, - /// The base address for each allocation. - /// This is the inverse of `int_to_ptr_map`. - base_addr: FxHashMap, - /// This is used as a memory address when a new pointer is casted to an integer. It - /// is always larger than any address that was previously made part of a block. - next_base_addr: u64, - /// To add some randomness to the allocations - /// FIXME(GenMC): maybe seed this from the rng in MiriMachine? - rng: StdRng, -} - -impl Default for GlobalStateInner { - fn default() -> Self { - Self::new() - } -} - -impl GlobalStateInner { - pub fn new() -> Self { - assert_eq!(GENMC_GLOBAL_ADDRESSES_MASK, getGlobalAllocStaticMask()); - assert_ne!(GENMC_GLOBAL_ADDRESSES_MASK, 0); - Self { - int_to_ptr_map: Vec::default(), - base_addr: FxHashMap::default(), - next_base_addr: GENMC_GLOBAL_ADDRESSES_MASK, - rng: StdRng::seed_from_u64(0), - } - } - - fn global_allocate_addr<'tcx>( - &mut self, - alloc_id: AllocId, - info: AllocInfo, - ) -> InterpResult<'tcx, u64> { - let entry = match self.base_addr.entry(alloc_id) { - Entry::Occupied(occupied_entry) => { - // Looks like some other thread allocated this for us - // between when we released the read lock and aquired the write lock, - // so we just return that value. - return interp_ok(*occupied_entry.get()); - } - Entry::Vacant(vacant_entry) => vacant_entry, - }; - - // This is either called immediately after allocation (and then cached), or when - // adjusting `tcx` pointers (which never get freed). So assert that we are looking - // at a live allocation. This also ensures that we never re-assign an address to an - // allocation that previously had an address, but then was freed and the address - // information was removed. - assert!(!matches!(info.kind, AllocKind::Dead)); - - // This allocation does not have a base address yet, pick or reuse one. - - // We are not in native lib mode, so we control the addresses ourselves. - - // We have to pick a fresh address. - // Leave some space to the previous allocation, to give it some chance to be less aligned. - // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. - let slack = self.rng.random_range(0..16); - // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = - self.next_base_addr.checked_add(slack).ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - let base_addr = align_addr(base_addr, info.align.bytes()); - - // Remember next base address. If this allocation is zero-sized, leave a gap of at - // least 1 to avoid two allocations having the same base address. (The logic in - // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers - // need to be distinguishable!) - self.next_base_addr = base_addr - .checked_add(max(info.size.bytes(), 1)) - .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - - assert_ne!(0, base_addr & GENMC_GLOBAL_ADDRESSES_MASK); - assert_ne!(0, self.next_base_addr & GENMC_GLOBAL_ADDRESSES_MASK); - // Cache the address for future use. - entry.insert(base_addr); - - interp_ok(base_addr) - } -} - -// FIXME(GenMC): "ExtPriv" or "PrivExt"? -impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn get_global_allocation_address( - &self, - global_allocation_handler: &GlobalAllocationHandler, - alloc_id: AllocId, - ) -> InterpResult<'tcx, u64> { - let this = self.eval_context_ref(); - let info = this.get_alloc_info(alloc_id); - - let global_state = global_allocation_handler.inner.read().unwrap(); - if let Some(base_addr) = global_state.base_addr.get(&alloc_id) { - info!( - "GenMC: address for global with alloc id {alloc_id:?} was cached: {base_addr} == {base_addr:#x}" - ); - return interp_ok(*base_addr); - } - - drop(global_state); - // We need to upgrade to a write lock. std::sync::RwLock doesn't support this, so we drop the guard and lock again - // Note that another thread might run in between and allocate the address, but we handle this case in the allocation function. - let mut global_state = global_allocation_handler.inner.write().unwrap(); - let base_addr = global_state.global_allocate_addr(alloc_id, info)?; - // Even if `Size` didn't overflow, we might still have filled up the address space. - if global_state.next_base_addr > this.target_usize_max() { - throw_exhaust!(AddressSpaceFull); - } - info!( - "GenMC: global with alloc id {alloc_id:?} got address: {base_addr} == {base_addr:#x}" - ); - interp_ok(base_addr) - } -} diff --git a/src/concurrency/genmc/helper.rs b/src/concurrency/genmc/helper.rs deleted file mode 100644 index e9d94be6cb..0000000000 --- a/src/concurrency/genmc/helper.rs +++ /dev/null @@ -1,230 +0,0 @@ -use rustc_abi::Size; -use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; -use rustc_middle::mir::{Terminator, TerminatorKind}; -use rustc_middle::ty::{self, ScalarInt, Ty}; -use tracing::info; - -use super::GenmcScalar; -use crate::alloc_addresses::EvalContextExt as _; -use crate::{ - BorTag, MiriInterpCx, MiriMachine, Pointer, Provenance, Scalar, ThreadId, throw_unsup_format, -}; - -const MEM_ACCESS_MAX_SIZE_BYTES: u64 = 8; - -pub fn split_access(address: Size, size: Size) -> impl Iterator { - // Handle possible misalignment: TODO GENMC: could always do largest power-of-two here - let size_bytes = size.bytes(); - - let start_address = address.bytes(); - let end_address = start_address + size_bytes; - // TODO GENMC: optimize this: - let start_missing = (MEM_ACCESS_MAX_SIZE_BYTES - (start_address % MEM_ACCESS_MAX_SIZE_BYTES)) - % MEM_ACCESS_MAX_SIZE_BYTES; - let end_missing = end_address % MEM_ACCESS_MAX_SIZE_BYTES; - - let start_address_aligned = start_address + start_missing; - let end_address_aligned = end_address - end_missing; - - info!( - "GenMC: splitting NA memory access into {MEM_ACCESS_MAX_SIZE_BYTES} byte chunks: {start_missing}B + {} * {MEM_ACCESS_MAX_SIZE_BYTES}B + {end_missing}B = {size:?}", - (end_address_aligned - start_address_aligned) / MEM_ACCESS_MAX_SIZE_BYTES - ); - debug_assert_eq!( - 0, - start_address_aligned % MEM_ACCESS_MAX_SIZE_BYTES, - "Incorrectly aligned start address: {start_address_aligned} % {MEM_ACCESS_MAX_SIZE_BYTES} != 0, {start_address} + {start_missing}" - ); - debug_assert_eq!( - 0, - end_address_aligned % MEM_ACCESS_MAX_SIZE_BYTES, - "Incorrectly aligned end address: {end_address_aligned} % {MEM_ACCESS_MAX_SIZE_BYTES} != 0, {end_address} - {end_missing}" - ); - debug_assert!( - start_missing < MEM_ACCESS_MAX_SIZE_BYTES && end_missing < MEM_ACCESS_MAX_SIZE_BYTES - ); - - let start_chunks = (start_address..start_address_aligned).map(|address| (address, 1)); - let aligned_chunks = (start_address_aligned..end_address_aligned) - .step_by(MEM_ACCESS_MAX_SIZE_BYTES.try_into().unwrap()) - .map(|address| (address, MEM_ACCESS_MAX_SIZE_BYTES)); - let end_chunks = (end_address_aligned..end_address).map(|address| (address, 1)); - - start_chunks.chain(aligned_chunks).chain(end_chunks) -} - -/// Convert an address (originally selected by GenMC) back into form that GenMC expects. -pub fn size_to_genmc(miri_address: Size) -> u64 { - miri_address.bytes() -} - -/// Like `scalar_to_genmc_scalar`, but returns an error if the scalar is not an integer -pub fn rhs_scalar_to_genmc_scalar<'tcx>( - ecx: &MiriInterpCx<'tcx>, - scalar: Scalar, -) -> InterpResult<'tcx, GenmcScalar> { - if matches!(scalar, Scalar::Ptr(..)) { - throw_unsup_format!("Right hand side of atomic operation cannot be a pointer"); - } - scalar_to_genmc_scalar(ecx, scalar) -} - -pub fn option_scalar_to_genmc_scalar<'tcx>( - ecx: &MiriInterpCx<'tcx>, - maybe_scalar: Option, -) -> InterpResult<'tcx, GenmcScalar> { - if let Some(scalar) = maybe_scalar { - scalar_to_genmc_scalar(ecx, scalar) - } else { - interp_ok(GenmcScalar::UNINIT) - } -} - -pub fn scalar_to_genmc_scalar<'tcx>( - ecx: &MiriInterpCx<'tcx>, - scalar: Scalar, -) -> InterpResult<'tcx, GenmcScalar> { - interp_ok(match scalar { - rustc_const_eval::interpret::Scalar::Int(scalar_int) => { - // TODO GENMC: u128 support - let value: u64 = scalar_int.to_uint(scalar_int.size()).try_into().unwrap(); // TODO GENMC: doesn't work for size != 8 - GenmcScalar { value, extra: 0, is_init: true } - } - rustc_const_eval::interpret::Scalar::Ptr(pointer, size) => { - let addr = Pointer::from(pointer).addr(); - if let Provenance::Wildcard = pointer.provenance { - throw_unsup_format!("Pointers with wildcard provenance not allowed in GenMC mode"); - } - let (alloc_id, _size, _prov_extra) = - rustc_const_eval::interpret::Machine::ptr_get_alloc(ecx, pointer, size.into()) - .unwrap(); - let base_addr = ecx.addr_from_alloc_id(alloc_id, None)?; - GenmcScalar { value: addr.bytes(), extra: base_addr, is_init: true } - } - }) -} - -pub fn genmc_scalar_to_scalar<'tcx>( - ecx: &MiriInterpCx<'tcx>, - scalar: GenmcScalar, - size: Size, -) -> InterpResult<'tcx, Scalar> { - // TODO GENMC: proper handling of large integers - // TODO GENMC: proper handling of pointers (currently assumes all integers) - - if scalar.extra != 0 { - // We have a pointer! - - let addr = Size::from_bytes(scalar.value); - let base_addr = scalar.extra; - - let alloc_size = 0; // TODO GENMC: what is the correct size here? Is 0 ok? - let only_exposed_allocations = false; - let Some(alloc_id) = - ecx.alloc_id_from_addr(base_addr, alloc_size, only_exposed_allocations) - else { - // TODO GENMC: what is the correct error in this case? - throw_unsup_format!( - "Cannot get allocation id of pointer received from GenMC (base address: 0x{base_addr:x}, pointer address: 0x{:x})", - addr.bytes() - ); - }; - - // TODO GENMC: is using `size: Size` ok here? Can we ever have `size != sizeof pointer`? - - // FIXME: Currently GenMC mode incompatible with aliasing model checking - let tag = BorTag::default(); - let provenance = crate::machine::Provenance::Concrete { alloc_id, tag }; - let offset = addr; - let ptr = rustc_middle::mir::interpret::Pointer::new(provenance, offset); - - let size = size.bytes().try_into().unwrap(); - return interp_ok(Scalar::Ptr(ptr, size)); - } - - // TODO GENMC (HACK): since we give dummy values to GenMC for NA accesses, we need to be able to convert it back: - let trunc_value = if size.bits() >= 64 { - scalar.value - } else { - let mask = (1u64 << size.bits()) - 1; - // let trunc_value = value & mask; - // eprintln!( - // "Masking {value} = 0x{value:x} to size {size:?}, with mask 0x{mask:x}, result: {trunc_value} = 0x{trunc_value:x}" - // ); - // trunc_value - scalar.value & mask - }; - - let Some(value_scalar_int) = ScalarInt::try_from_uint(trunc_value, size) else { - todo!( - "GenMC: cannot currently convert GenMC value {} (0x{:x}) (truncated {trunc_value} = 0x{trunc_value:x}), with size {size:?} into a Miri Scalar", - scalar.value, - scalar.value, - ); - }; - interp_ok(Scalar::Int(value_scalar_int)) -} - -pub fn is_terminator_atomic<'tcx>( - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - terminator: &Terminator<'tcx>, - thread_id: ThreadId, - // _cache: &mut FxHashMap, bool>, -) -> InterpResult<'tcx, bool> { - match &terminator.kind { - // All atomics are modeled as function calls to intrinsic functions. - // The one exception is thread joining, but those are also calls. - TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => { - let frame = ecx.machine.threads.get_thread_stack(thread_id).last().unwrap(); - let func_ty = func.ty(&frame.body().local_decls, *ecx.tcx); - info!("GenMC: terminator is a call with operand: {func:?}, ty of operand: {func_ty:?}"); - - is_function_atomic(ecx, func_ty) - - // match cache.entry(func_ty) { - // std::collections::hash_map::Entry::Occupied(occupied_entry) => { - // assert_eq!(is_function_atomic(ecx, func_ty)?, *occupied_entry.get()); - // interp_ok(*occupied_entry.get()) - // } - // std::collections::hash_map::Entry::Vacant(vacant_entry) => { - // let is_atomic = is_function_atomic(ecx, func_ty)?; - // vacant_entry.insert(is_atomic); - // interp_ok(is_atomic) - // } - // } - // } - } - _ => interp_ok(false), - } -} - -fn is_function_atomic<'tcx>( - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - func_ty: Ty<'tcx>, - // func: &Operand<'tcx>, -) -> InterpResult<'tcx, bool> { - let callee_def_id = match func_ty.kind() { - ty::FnDef(def_id, _args) => def_id, - _ => return interp_ok(true), // we don't know the callee, might be an intrinsic or pthread_join - }; - if ecx.tcx.is_foreign_item(*callee_def_id) { - // Some shims, like pthread_join, must be considered loads. So just consider them all loads, - // these calls are not *that* common. - return interp_ok(true); - } - - let Some(intrinsic_def) = ecx.tcx.intrinsic(callee_def_id) else { - // TODO GENMC: Make this work for other platforms? - let item_name = ecx.tcx.item_name(*callee_def_id); - info!("GenMC: function DefId: {callee_def_id:?}, item name: {item_name:?}"); - if matches!(item_name.as_str(), "pthread_join" | "WaitForSingleObject") { - info!("GenMC: found a 'join' terminator: '{}'", item_name.as_str(),); - return interp_ok(true); - } - return interp_ok(false); - }; - let intrinsice_name = intrinsic_def.name.as_str(); - info!("GenMC: intrinsic name: '{intrinsice_name}'"); - // TODO GENMC(ENHANCEMENT): make this more precise (only loads). How can we make this maintainable? - interp_ok(intrinsice_name.starts_with("atomic_")) -} diff --git a/src/concurrency/genmc/mapping.rs b/src/concurrency/genmc/mapping.rs deleted file mode 100644 index 5a64eebef9..0000000000 --- a/src/concurrency/genmc/mapping.rs +++ /dev/null @@ -1,83 +0,0 @@ -use genmc_sys::{MemOrdering, RMWBinOp}; - -use crate::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd}; - -impl AtomicReadOrd { - pub(super) fn convert(self) -> MemOrdering { - match self { - AtomicReadOrd::Relaxed => MemOrdering::Relaxed, - AtomicReadOrd::Acquire => MemOrdering::Acquire, - AtomicReadOrd::SeqCst => MemOrdering::SequentiallyConsistent, - } - } -} - -impl AtomicWriteOrd { - pub(super) fn convert(self) -> MemOrdering { - match self { - AtomicWriteOrd::Relaxed => MemOrdering::Relaxed, - AtomicWriteOrd::Release => MemOrdering::Release, - AtomicWriteOrd::SeqCst => MemOrdering::SequentiallyConsistent, - } - } -} - -impl AtomicFenceOrd { - pub(super) fn convert(self) -> MemOrdering { - match self { - AtomicFenceOrd::Acquire => MemOrdering::Acquire, - AtomicFenceOrd::Release => MemOrdering::Release, - AtomicFenceOrd::AcqRel => MemOrdering::AcquireRelease, - AtomicFenceOrd::SeqCst => MemOrdering::SequentiallyConsistent, - } - } -} - -impl AtomicRwOrd { - /// Split up an atomic read-write memory ordering into a separate read and write ordering. - pub(super) fn split_memory_orderings(self) -> (AtomicReadOrd, AtomicWriteOrd) { - match self { - AtomicRwOrd::Relaxed => (AtomicReadOrd::Relaxed, AtomicWriteOrd::Relaxed), - AtomicRwOrd::Acquire => (AtomicReadOrd::Acquire, AtomicWriteOrd::Relaxed), - AtomicRwOrd::Release => (AtomicReadOrd::Relaxed, AtomicWriteOrd::Release), - AtomicRwOrd::AcqRel => (AtomicReadOrd::Acquire, AtomicWriteOrd::Release), - AtomicRwOrd::SeqCst => (AtomicReadOrd::SeqCst, AtomicWriteOrd::SeqCst), - } - } - - /// Split up the atomic success ordering of a read-modify-write operation into GenMC's representation. - /// Note that both returned orderings are currently identical, because this is what GenMC expects. - pub(super) fn to_genmc_memory_orderings(self) -> (MemOrdering, MemOrdering) { - match self { - AtomicRwOrd::Relaxed => (MemOrdering::Relaxed, MemOrdering::Relaxed), - AtomicRwOrd::Acquire => (MemOrdering::Acquire, MemOrdering::Acquire), - AtomicRwOrd::Release => (MemOrdering::Release, MemOrdering::Release), - AtomicRwOrd::AcqRel => (MemOrdering::AcquireRelease, MemOrdering::AcquireRelease), - AtomicRwOrd::SeqCst => - (MemOrdering::SequentiallyConsistent, MemOrdering::SequentiallyConsistent), - } - } -} - -pub(super) fn min_max_to_genmc_rmw_op(min: bool, is_signed: bool) -> RMWBinOp { - match (min, is_signed) { - (true, true) => RMWBinOp::Min, // TODO GENMC: is there a use for FMin? (Min, UMin, FMin) - (false, true) => RMWBinOp::Max, - (true, false) => RMWBinOp::UMin, - (false, false) => RMWBinOp::UMax, - } -} - -pub(super) fn to_genmc_rmw_op(bin_op: rustc_middle::mir::BinOp, negate: bool) -> RMWBinOp { - match bin_op { - rustc_middle::mir::BinOp::Add => RMWBinOp::Add, - rustc_middle::mir::BinOp::Sub => RMWBinOp::Sub, - rustc_middle::mir::BinOp::BitOr if !negate => RMWBinOp::Or, - rustc_middle::mir::BinOp::BitXor if !negate => RMWBinOp::Xor, - rustc_middle::mir::BinOp::BitAnd if negate => RMWBinOp::Nand, - rustc_middle::mir::BinOp::BitAnd => RMWBinOp::And, - _ => { - panic!("unsupported atomic operation: bin_op: {bin_op:?}, negate: {negate}"); - } - } -} diff --git a/src/concurrency/genmc/miri_genmc.rs b/src/concurrency/genmc/miri_genmc.rs deleted file mode 100644 index 950b270c0b..0000000000 --- a/src/concurrency/genmc/miri_genmc.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::fmt::Display; -use std::rc::Rc; -use std::time::Instant; - -use crate::{GenmcConfig, GenmcCtx, MiriConfig}; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Mode { - Estimation, - Verification, -} - -impl Display for Mode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - Mode::Estimation => "Estimation", - Mode::Verification => "Verification", - }) - } -} - -pub fn run_genmc_mode( - config: &MiriConfig, - genmc_config: &GenmcConfig, - eval_entry: impl Fn(Rc) -> Option, - mode: Mode, -) -> Option { - let time_start = Instant::now(); - let genmc_ctx = Rc::new(GenmcCtx::new(config, genmc_config, mode)); - - for rep in 0u64.. { - tracing::info!("Miri-GenMC loop {}", rep + 1); - let result = eval_entry(genmc_ctx.clone()); - - if genmc_config.print_exec_graphs() { - genmc_ctx.print_genmc_graph(); - } - - // TODO GENMC (ERROR REPORTING): we currently do this here, so we can still print the GenMC graph above - let return_code = result?; - - let is_exploration_done = genmc_ctx.is_exploration_done(); - - tracing::info!( - "(GenMC Mode) Execution done (return code: {return_code}), is_exploration_done: {is_exploration_done}", - ); - - if is_exploration_done { - eprintln!(); - eprintln!("(GenMC) {mode} complete. No errors were detected.",); - - if mode == Mode::Estimation && return_code == 0 { - let elapsed_time = Instant::now().duration_since(time_start); - genmc_ctx.print_estimation_result(elapsed_time); - return Some(0); - } - - // TODO GENMC: proper message here, which info should be printed? - let blocked_execution_count = genmc_ctx.get_blocked_execution_count(); - // TODO GENMC: use VerificationResult instead: - let explored_execution_count = rep + 1 - blocked_execution_count; - eprintln!("Number of complete executions explored: {explored_execution_count}"); - if blocked_execution_count > 0 { - eprintln!("Number of blocked executions seen: {blocked_execution_count}"); - } - - // TODO GENMC: what is an appropriate return code? (since there are possibly many) - return Some(return_code); - } - } - tracing::error!("GenMC mode did not finish in 2^64 iterations!"); - None -} diff --git a/src/concurrency/genmc/mod.rs b/src/concurrency/genmc/mod.rs index ab727ec0ce..988c808e30 100644 --- a/src/concurrency/genmc/mod.rs +++ b/src/concurrency/genmc/mod.rs @@ -1,158 +1,74 @@ -use std::cell::{Cell, RefCell}; -use std::sync::Arc; -use std::time::Duration; +#![allow(unused)] // FIXME(GenMC): remove this -use genmc_sys::{ - ActionKind, GENMC_GLOBAL_ADDRESSES_MASK, GenmcScalar, GenmcThreadId, MemOrdering, - MiriGenMCShim, RMWBinOp, StoreEventType, createGenmcHandle, -}; +use std::cell::Cell; + +use genmc_sys::{GenmcParams, createGenmcHandle}; use rustc_abi::{Align, Size}; -use rustc_const_eval::interpret::{AllocId, InterpCx, InterpResult, interp_ok}; -use rustc_middle::{mir, throw_machine_stop, throw_ub_format, throw_unsup_format}; -use tracing::info; +use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; +use rustc_middle::mir; -use self::cxx_extra::NonNullUniquePtr; -use self::global_allocations::{EvalContextExtPriv as _, GlobalAllocationHandler}; -use self::helper::{ - genmc_scalar_to_scalar, option_scalar_to_genmc_scalar, rhs_scalar_to_genmc_scalar, - scalar_to_genmc_scalar, size_to_genmc, -}; -use self::mapping::{min_max_to_genmc_rmw_op, to_genmc_rmw_op}; -use self::thread_info_manager::ThreadInfoManager; -use crate::concurrency::genmc::helper::{is_terminator_atomic, split_access}; -use crate::concurrency::genmc::warnings::WarningsCache; -use crate::concurrency::thread::{EvalContextExt as _, ThreadState}; use crate::{ - callback, AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, BlockReason, MachineCallback, MemoryKind, MiriConfig, MiriInterpCx, MiriMachine, MiriMemoryKind, OpTy, Scalar, TerminationInfo, ThreadId, ThreadManager, UnblockKind, VisitProvenance, VisitWith + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, + MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, }; -pub mod miri_genmc; mod config; -mod cxx_extra; -mod global_allocations; -mod helper; -mod mapping; -mod thread_info_manager; -mod warnings; - -pub use genmc_sys::GenmcParams; pub use self::config::GenmcConfig; -const UNSUPPORTED_ATOMICS_SIZE_MSG: &str = - "GenMC mode currently does not support atomics larger than 8 bytes."; - +// FIXME(GenMC): add fields pub struct GenmcCtx { - handle: RefCell>, - - // TODO GENMC (PERFORMANCE): could use one RefCell for all internals instead of multiple - thread_infos: RefCell, - /// Some actions Miri does are allowed to cause data races. /// GenMC will not be informed about certain actions (e.g. non-atomic loads) when this flag is set. allow_data_races: Cell, - - main_thread_user_code_finished: Cell, - - /// Keep track of global allocations, to ensure they keep the same address across different executions, even if the order of allocations changes. - /// The `AllocId` for globals is stable across executions, so we can use it as an identifier. - global_allocations: Arc, - // TODO GENMC: maybe make this a (base, size), maybe BTreeMap/sorted vector for reverse lookups - // GenMC needs to have access to that - // TODO: look at code of "pub struct GlobalStateInner" - warnings_cache: RefCell, - - // terminator_cache: RefCell, bool>>, } -/// GenMC Context creation and administrative / query actions impl GenmcCtx { /// Create a new `GenmcCtx` from a given config. - pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig, mode: miri_genmc::Mode) -> Self { + pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self { assert!(miri_config.genmc_mode); - info!("GenMC: Creating new GenMC Context"); - let handle = createGenmcHandle(&genmc_config.params, mode == miri_genmc::Mode::Estimation); - let non_null_handle = NonNullUniquePtr::new(handle).expect("GenMC should not return null"); - let non_null_handle = RefCell::new(non_null_handle); + let handle = createGenmcHandle(&genmc_config.params); + assert!(!handle.is_null()); - Self { - handle: non_null_handle, - thread_infos: Default::default(), - allow_data_races: Cell::new(false), - main_thread_user_code_finished: Cell::new(false), - global_allocations: Default::default(), - warnings_cache: Default::default(), - // terminator_cache: Default::default(), - } - } + eprintln!("Miri: GenMC handle creation successful!"); + + drop(handle); + eprintln!("Miri: Dropping GenMC handle successful!"); - pub fn print_estimation_result(&self, elapsed_time: Duration) { - let elapsed_time_sec = elapsed_time.as_secs_f64(); - let mc = self.handle.borrow(); - mc.as_ref().printEstimationResults(elapsed_time_sec); + // FIXME(GenMC): implement + std::process::exit(0); } - pub fn get_blocked_execution_count(&self) -> u64 { - let mc = self.handle.borrow(); - mc.as_ref().getStuckExecutionCount() + pub fn get_stuck_execution_count(&self) -> usize { + todo!() } pub fn print_genmc_graph(&self) { - info!("GenMC: print the Execution graph"); - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.printGraph(); + todo!() } /// This function determines if we should continue exploring executions or if we are done. /// /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. pub fn is_exploration_done(&self) -> bool { - info!("GenMC: ask if execution exploration is done"); - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.isExplorationDone() + todo!() } -} - -/// GenMC event handling. These methods are used to inform GenMC about events happening in the program, and to handle scheduling decisions. -impl GenmcCtx { - /**** Memory access handling ****/ /// Inform GenMC that a new program execution has started. /// This function should be called at the start of every execution. pub(crate) fn handle_execution_start(&self) { - info!("GenMC: inform GenMC that new execution started"); - self.allow_data_races.replace(false); - self.main_thread_user_code_finished.set(false); - self.thread_infos.borrow_mut().reset(); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleExecutionStart(); + todo!() } /// Inform GenMC that the program's execution has ended. /// - /// This function must be called even when the execution is blocked - /// (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcBlockedExecution`). + /// This function must be called even when the execution got stuck (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). pub(crate) fn handle_execution_end<'tcx>( &self, - _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, ) -> Result<(), String> { - info!("GenMC: inform GenMC that execution ended!"); - let mut mc = self.handle.borrow_mut(); - - let pinned_mc = mc.as_mut(); - let result = pinned_mc.handleExecutionEnd(); - if let Some(msg) = result.as_ref() { - let msg = msg.to_string_lossy().to_string(); - info!("GenMC: execution ended with error \"{msg}\""); - Err(msg) // TODO GENMC: add more error info here, and possibly handle this without requiring to clone the CxxString - } else { - Ok(()) - } + todo!() } /**** Memory access handling ****/ @@ -167,29 +83,20 @@ impl GenmcCtx { /// # Panics /// If data race free is attempted to be set more than once (i.e., no nesting allowed). pub(super) fn set_ongoing_action_data_race_free(&self, enable: bool) { - info!("GenMC: set_ongoing_action_data_race_free ({enable})"); let old = self.allow_data_races.replace(enable); assert_ne!(old, enable, "cannot nest allow_data_races"); } - //* might fails if there's a race, load might also not read anything (returns None) */ pub(crate) fn atomic_load<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, address: Size, size: Size, ordering: AtomicReadOrd, - // The value that we would get, if we were to do a non-atomic load here. old_val: Option, ) -> InterpResult<'tcx, Scalar> { - info!("GenMC: atomic_load: old_val: {old_val:?}"); - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let ordering = ordering.convert(); - let genmc_old_value = option_scalar_to_genmc_scalar(ecx, old_val)?; - let read_value = - self.atomic_load_impl(&ecx.machine, address, size, ordering, genmc_old_value)?; - info!("GenMC: atomic_load: received value from GenMC: {read_value:?}"); - genmc_scalar_to_scalar(ecx, read_value, size) + assert!(!self.allow_data_races.get()); + todo!() } pub(crate) fn atomic_store<'tcx>( @@ -198,15 +105,10 @@ impl GenmcCtx { address: Size, size: Size, value: Scalar, - // The value that we would get, if we were to do a non-atomic load here. - old_value: Option, ordering: AtomicWriteOrd, - ) -> InterpResult<'tcx, bool> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let ordering = ordering.convert(); - let genmc_value = scalar_to_genmc_scalar(ecx, value)?; - let genmc_old_value = option_scalar_to_genmc_scalar(ecx, old_value)?; - self.atomic_store_impl(&ecx.machine, address, size, genmc_value, genmc_old_value, ordering) + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() } pub(crate) fn atomic_fence<'tcx>( @@ -214,26 +116,13 @@ impl GenmcCtx { machine: &MiriMachine<'tcx>, ordering: AtomicFenceOrd, ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - info!("GenMC: atomic_fence with ordering: {ordering:?}"); - - let ordering = ordering.convert(); - - let thread_infos = self.thread_infos.borrow(); - let curr_thread = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleFence(genmc_tid.0, ordering); - - // TODO GENMC: can this operation ever fail? - interp_ok(()) + assert!(!self.allow_data_races.get()); + todo!() } /// Inform GenMC about an atomic read-modify-write operation. /// - /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. + /// Returns `(old_val, new_val)`. pub(crate) fn atomic_rmw_op<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -242,32 +131,14 @@ impl GenmcCtx { ordering: AtomicRwOrd, (rmw_op, not): (mir::BinOp, bool), rhs_scalar: Scalar, - // The value that we would get, if we were to do a non-atomic load here. - old_value: Scalar, - ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let (load_ordering, store_ordering) = ordering.to_genmc_memory_orderings(); - let genmc_rmw_op = to_genmc_rmw_op(rmw_op, not); - tracing::info!( - "GenMC: atomic_rmw_op (op: {rmw_op:?}, not: {not}, genmc_rmw_op: {genmc_rmw_op:?}): rhs value: {rhs_scalar:?}, orderings ({load_ordering:?}, {store_ordering:?})" - ); - let genmc_rhs_scalar = rhs_scalar_to_genmc_scalar(ecx, rhs_scalar)?; - let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; - self.atomic_rmw_op_impl( - ecx, - address, - size, - load_ordering, - store_ordering, - genmc_rmw_op, - genmc_rhs_scalar, - genmc_old_value, - ) + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + assert!(!self.allow_data_races.get()); + todo!() } /// Inform GenMC about an atomic `min` or `max` operation. /// - /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. + /// Returns `(old_val, new_val)`. pub(crate) fn atomic_min_max_op<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -277,30 +148,11 @@ impl GenmcCtx { min: bool, is_signed: bool, rhs_scalar: Scalar, - // The value that we would get, if we were to do a non-atomic load here. - old_value: Scalar, - ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let (load_ordering, store_ordering) = ordering.to_genmc_memory_orderings(); - let genmc_rmw_op = min_max_to_genmc_rmw_op(min, is_signed); - tracing::info!( - "GenMC: atomic_min_max_op (min: {min}, signed: {is_signed}, genmc_rmw_op: {genmc_rmw_op:?}): rhs value: {rhs_scalar:?}, orderings ({load_ordering:?}, {store_ordering:?})" - ); - let genmc_rhs_scalar = rhs_scalar_to_genmc_scalar(ecx, rhs_scalar)?; - let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; - self.atomic_rmw_op_impl( - ecx, - address, - size, - load_ordering, - store_ordering, - genmc_rmw_op, - genmc_rhs_scalar, - genmc_old_value, - ) + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + assert!(!self.allow_data_races.get()); + todo!() } - /// Returns `(old_val, Option)`. `new_val` might not be the latest write in coherence order, which is indicated by `None`. pub(crate) fn atomic_exchange<'tcx>( &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, @@ -308,29 +160,9 @@ impl GenmcCtx { size: Size, rhs_scalar: Scalar, ordering: AtomicRwOrd, - // The value that we would get, if we were to do a non-atomic load here. - old_value: Scalar, - ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - // TODO GENMC: could maybe merge this with atomic_rmw? - - let (load_ordering, store_ordering) = ordering.to_genmc_memory_orderings(); - let genmc_rmw_op = RMWBinOp::Xchg; - tracing::info!( - "GenMC: atomic_exchange (op: {genmc_rmw_op:?}): new value: {rhs_scalar:?}, orderings ({load_ordering:?}, {store_ordering:?})" - ); - let genmc_rhs_scalar = scalar_to_genmc_scalar(ecx, rhs_scalar)?; - let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; - self.atomic_rmw_op_impl( - ecx, - address, - size, - load_ordering, - store_ordering, - genmc_rmw_op, - genmc_rhs_scalar, - genmc_old_value, - ) + ) -> InterpResult<'tcx, (Scalar, bool)> { + assert!(!self.allow_data_races.get()); + todo!() } pub(crate) fn atomic_compare_exchange<'tcx>( @@ -343,68 +175,9 @@ impl GenmcCtx { success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, - // The value that we would get, if we were to do a non-atomic load here. - old_value: Scalar, - ) -> InterpResult<'tcx, (Scalar, bool, bool)> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - - // FIXME(genmc): remove once GenMC supports failure memory ordering in `compare_exchange`. - self.warnings_cache.borrow_mut().warn_once_rmw_failure_ordering(&ecx.tcx, success, fail); - // FIXME(genmc): remove once GenMC implements spurious failures for `compare_exchange_weak`. - if can_fail_spuriously { - self.warnings_cache.borrow_mut().warn_once_compare_exchange_weak(&ecx.tcx); - } - - let machine = &ecx.machine; - let (success_load_ordering, success_store_ordering) = success.to_genmc_memory_orderings(); - let fail_load_ordering = fail.convert(); - - info!( - "GenMC: atomic_compare_exchange, address: {address:?}, size: {size:?} (expect: {expected_old_value:?}, new: {new_value:?}, old_value: {old_value:?}, {success:?}, {fail:?}), can fail spuriously: {can_fail_spuriously}" - ); - info!( - "GenMC: atomic_compare_exchange orderings: success: ({success_load_ordering:?}, {success_store_ordering:?}), failure load ordering: {fail_load_ordering:?}" - ); - - let thread_infos = self.thread_infos.borrow(); - let curr_thread = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; - - let genmc_address = size_to_genmc(address); - let genmc_size = size_to_genmc(size); - - let genmc_expected_value = scalar_to_genmc_scalar(ecx, expected_old_value)?; - let genmc_new_value = scalar_to_genmc_scalar(ecx, new_value)?; - let genmc_old_value = scalar_to_genmc_scalar(ecx, old_value)?; - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let cas_result = pinned_mc.handleCompareExchange( - genmc_tid.0, - genmc_address, - genmc_size, - genmc_expected_value, - genmc_new_value, - genmc_old_value, - success_load_ordering, - success_store_ordering, - fail_load_ordering, - can_fail_spuriously, - ); - - if let Some(error) = cas_result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: RMW operation returned an error: \"{msg}\""); - throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here - } - - let return_scalar = genmc_scalar_to_scalar(ecx, cas_result.old_value, size)?; - info!( - "GenMC: atomic_compare_exchange: result: {cas_result:?}, returning scalar: {return_scalar:?}" - ); - // The write can only be a co-maximal write if the CAS succeeded. - assert!(cas_result.is_success || !cas_result.isCoMaxWrite); - interp_ok((return_scalar, cas_result.isCoMaxWrite, cas_result.is_success)) + ) -> InterpResult<'tcx, (Scalar, bool)> { + assert!(!self.allow_data_races.get()); + todo!() } /// Inform GenMC about a non-atomic memory load @@ -416,59 +189,7 @@ impl GenmcCtx { address: Size, size: Size, ) -> InterpResult<'tcx, ()> { - if self.allow_data_races.get() { - // TODO GENMC: handle this properly - info!("GenMC: skipping `handle_load`"); - return interp_ok(()); - } - info!( - "GenMC: received memory_load (non-atomic): address: {:#x}, size: {}", - address.bytes(), - size.bytes() - ); - // GenMC doesn't like ZSTs, and they can't have any data races, so we skip them - if size.bytes() == 0 { - return interp_ok(()); - } - - // TODO GENMC: can this be improved? - if machine.threads.active_thread() == ThreadId::MAIN_THREAD - && self.main_thread_user_code_finished.get() - { - info!("GenMC: skipping `memory_load` for finished main thread"); - return interp_ok(()); - } - - // let _read_value = - // self.atomic_load_impl(machine, address, size, MemOrdering::NotAtomic)?; - - // // TODO GENMC (HACK): to handle large non-atomics, we ignore the value by GenMC for now - // interp_ok(Scalar::from_u64(0xDEADBEEF)) - - if size.bytes() <= 8 { - // NOTE: Values loaded non-atomically are still handled by Miri, so we discard whatever we get from GenMC - let _read_value = self.atomic_load_impl( - machine, - address, - size, - MemOrdering::NotAtomic, - GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value - )?; - return interp_ok(()); - } - - for (address, size) in split_access(address, size) { - let chunk_addr = Size::from_bytes(address); - let chunk_size = Size::from_bytes(size); - let _read_value = self.atomic_load_impl( - machine, - chunk_addr, - chunk_size, - MemOrdering::NotAtomic, - GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value - )?; - } - interp_ok(()) + todo!() } pub(crate) fn memory_store<'tcx>( @@ -476,168 +197,31 @@ impl GenmcCtx { machine: &MiriMachine<'tcx>, address: Size, size: Size, - // old_value: Option, // TODO GENMC(mixed atomic-non-atomic): is this needed? ) -> InterpResult<'tcx, ()> { - if self.allow_data_races.get() { - // TODO GENMC: handle this properly - info!( - "GenMC: skipping `handle_store` for address {addr} == {addr:#x}, size: {}", - size.bytes(), - addr = address.bytes() - ); - return interp_ok(()); - } - // GenMC doesn't like ZSTs, and they can't have any data races, so we skip them - if size.bytes() == 0 { - return interp_ok(()); - } - - // TODO GENMC: can this be improved? - if machine.threads.active_thread() == ThreadId::MAIN_THREAD - && self.main_thread_user_code_finished.get() - { - info!("GenMC: skipping `memory_store` for finished main thread"); - return interp_ok(()); - } - - if size.bytes() <= 8 { - // TODO GENMC(mixed atomic-non-atomics): anything to do here? - let _is_co_max_write = self.atomic_store_impl( - machine, - address, - size, - GenmcScalar::DUMMY, - GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value - MemOrdering::NotAtomic, - )?; - return interp_ok(()); - } - - for (address, size) in split_access(address, size) { - let chunk_addr = Size::from_bytes(address); - let chunk_size = Size::from_bytes(size); - // TODO GENMC(mixed atomic-non-atomics): anything to do here? - let _is_co_max_write = self.atomic_store_impl( - machine, - chunk_addr, - chunk_size, - GenmcScalar::DUMMY, - GenmcScalar::UNINIT, // Don't use DUMMY here, since that might have it stored as the initial value - MemOrdering::NotAtomic, - )?; - } - interp_ok(()) + todo!() } /**** Memory (de)allocation ****/ pub(crate) fn handle_alloc<'tcx>( &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - alloc_id: AllocId, + machine: &MiriMachine<'tcx>, size: Size, alignment: Align, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - let machine = &ecx.machine; - let chosen_address = if memory_kind == MiriMemoryKind::Global.into() { - info!("GenMC: global memory allocation: {alloc_id:?}"); - ecx.get_global_allocation_address(&self.global_allocations, alloc_id)? - } else { - // TODO GENMC: Does GenMC need to know about the kind of Memory? - - // eprintln!( - // "handle_alloc ({memory_kind:?}): Custom backtrace: {}", - // std::backtrace::Backtrace::force_capture() - // ); - // TODO GENMC: should we put this before the special handling for globals? - if self.allow_data_races.get() { - // TODO GENMC: handle this properly - info!("GenMC: skipping `handle_alloc`"); - return interp_ok(0); - } - let thread_infos = self.thread_infos.borrow(); - let curr_thread = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; - // GenMC doesn't support ZSTs, so we set the minimum size to 1 byte - let genmc_size = size_to_genmc(size).max(1); - info!( - "GenMC: handle_alloc (thread: {curr_thread:?} ({genmc_tid:?}), size: {}, alignment: {alignment:?}, memory_kind: {memory_kind:?})", - size.bytes() - ); - // TODO GENMC: can this be improved? - if curr_thread == ThreadId::MAIN_THREAD && self.main_thread_user_code_finished.get() { - panic!("GenMC: `handle_alloc` on finished main thread"); - } - - let alignment = alignment.bytes(); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let chosen_address = pinned_mc.handleMalloc(genmc_tid.0, genmc_size, alignment); - info!("GenMC: handle_alloc: got address '{chosen_address}' ({chosen_address:#x})"); - - // TODO GENMC: - if chosen_address == 0 { - throw_unsup_format!("TODO GENMC: we got address '0' from malloc"); - } - assert_eq!(0, chosen_address & GENMC_GLOBAL_ADDRESSES_MASK); - chosen_address - }; - // Sanity check the address alignment: - assert_eq!( - 0, - chosen_address % alignment.bytes(), - "GenMC returned address {chosen_address} == {chosen_address:#x} with lower alignment than requested ({:})!", - alignment.bytes() - ); - - interp_ok(chosen_address) + todo!() } pub(crate) fn handle_dealloc<'tcx>( &self, machine: &MiriMachine<'tcx>, - alloc_id: AllocId, address: Size, size: Size, align: Align, kind: MemoryKind, ) -> InterpResult<'tcx, ()> { - assert_ne!( - kind, - MiriMemoryKind::Global.into(), - "we probably shouldn't try to deallocate global allocations (alloc_id: {alloc_id:?})" - ); - if self.allow_data_races.get() { - // TODO GENMC: handle this properly, should this be skipped in this mode? - info!("GenMC: skipping `handle_dealloc`"); - return interp_ok(()); - } - // eprintln!("handle_dealloc: Custom backtrace: {}", std::backtrace::Backtrace::force_capture()); - let thread_infos = self.thread_infos.borrow(); - let curr_thread = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread).genmc_tid; - info!( - "GenMC: memory deallocation, thread: {curr_thread:?} ({genmc_tid:?}), address: {addr} == {addr:#x}, size: {size:?}, align: {align:?}, memory_kind: {kind:?}", - addr = address.bytes() - ); - // TODO GENMC: can this be improved? - if curr_thread == ThreadId::MAIN_THREAD && self.main_thread_user_code_finished.get() { - info!("GenMC: skipping `handle_dealloc` for finished main thread"); - return interp_ok(()); - } - - let genmc_address = size_to_genmc(address); - // GenMC doesn't support ZSTs, so we set the minimum size to 1 byte - let genmc_size = size_to_genmc(size).max(1); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleFree(genmc_tid.0, genmc_address, genmc_size); - - // TODO GENMC (ERROR HANDLING): can this ever fail? - interp_ok(()) + todo!() } /**** Thread management ****/ @@ -645,27 +229,10 @@ impl GenmcCtx { pub(crate) fn handle_thread_create<'tcx>( &self, threads: &ThreadManager<'tcx>, - _start_routine: crate::Pointer, // TODO GENMC: pass info to GenMC - _func_arg: &crate::ImmTy<'tcx>, new_thread_id: ThreadId, ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let mut thread_infos = self.thread_infos.borrow_mut(); - - let curr_thread_id = threads.active_thread(); - let genmc_parent_tid = thread_infos.get_info(curr_thread_id).genmc_tid; - let genmc_new_tid = thread_infos.add_thread(new_thread_id); - - info!( - "GenMC: handling thread creation (thread {curr_thread_id:?} ({genmc_parent_tid:?}) spawned thread {new_thread_id:?} ({genmc_new_tid:?}))" - ); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleThreadCreate(genmc_new_tid.0, genmc_parent_tid.0); - - // TODO GENMC (ERROR HANDLING): can this ever fail? - interp_ok(()) + assert!(!self.allow_data_races.get()); + todo!() } pub(crate) fn handle_thread_join<'tcx>( @@ -673,589 +240,46 @@ impl GenmcCtx { active_thread_id: ThreadId, child_thread_id: ThreadId, ) -> InterpResult<'tcx, ()> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let thread_infos = self.thread_infos.borrow(); - - let genmc_curr_tid = thread_infos.get_info(active_thread_id).genmc_tid; - let genmc_child_tid = thread_infos.get_info(child_thread_id).genmc_tid; - - info!( - "GenMC: handling thread joining (thread {active_thread_id:?} ({genmc_curr_tid:?}) joining thread {child_thread_id:?} ({genmc_child_tid:?}))" - ); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - - // TODO GENMC: error handling: - pinned_mc.handleThreadJoin(genmc_curr_tid.0, genmc_child_tid.0); - - interp_ok(()) - } - - pub(crate) fn handle_thread_stack_empty<'tcx>( - &self, - _threads: &ThreadManager<'tcx>, - thread_id: ThreadId, - ) { - // TODO GENMC(CLEANUP): do we need this for all threads? - info!("GenMC: thread stack empty: {thread_id:?}"); - // warn!("GenMC: thread stack empty: {thread_id:?}"); - { - let mut thread_infos = self.thread_infos.borrow_mut(); - let info = thread_infos.get_info_mut(thread_id); - info.user_code_finished = true; - } - - // if thread_id == ThreadId::MAIN_THREAD { - // // Miri stops once the main thread is finished, but GenMC doesn't know that. - // // We tell GenMC that the main thread is already finished now, so it won't be scheduled by GenMC again. - // self.handle_thread_finish(threads); - // } - } - - pub(crate) fn handle_main_thread_stack_empty<'tcx>(&self, threads: &ThreadManager<'tcx>) { - // TODO GENMC(CLEANUP): do we need this for all threads? - info!("GenMC: main thread stack empty"); - // warn!("GenMC: main thread stack empty: {thread_id:?}"); - // { - // let mut thread_infos = self.thread_infos.borrow_mut(); - // let info = thread_infos.get_info_mut(thread_id); - // info.user_code_finished = true; - // } - - // if thread_id == ThreadId::MAIN_THREAD { - // Miri stops once the main thread is finished, but GenMC doesn't know that. - // We tell GenMC that the main thread is already finished now, so it won't be scheduled by GenMC again. - self.handle_thread_finish(threads); - // } - } - - pub(crate) fn handle_thread_finish<'tcx>(&self, threads: &ThreadManager<'tcx>) { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let curr_thread_id = threads.active_thread(); - if curr_thread_id == ThreadId::MAIN_THREAD { - if self.main_thread_user_code_finished.replace(true) { - info!("GenMC: Skip repeated thread finish for main thread."); - // warn!("GenMC: Skip repeated thread finish for main thread."); - return; - } - // self.main_thread_user_code_finished.set(true); - } - - let thread_infos = self.thread_infos.borrow(); - let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; - - // NOTE: Miri doesn't support return values for threads, but GenMC expects one, so we return 0 - let ret_val = 0; - - info!( - "GenMC: handling thread finish (thread {curr_thread_id:?} ({genmc_tid:?}) returns with dummy value 0)" - ); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleThreadFinish(genmc_tid.0, ret_val); - } - - /**** Scheduling functionality ****/ - - pub(crate) fn schedule_thread<'tcx>( - &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - ) -> InterpResult<'tcx, ThreadId> { - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let thread_manager = &ecx.machine.threads; - let active_thread_id = thread_manager.active_thread(); - - let curr_thread_next_instr_kind = - if !thread_manager.active_thread_ref().get_state().is_enabled() - || (active_thread_id == ThreadId::MAIN_THREAD - && self.main_thread_user_code_finished.get()) - { - // There are 2 cases where we need to schedule always: - // - The current thread is blocked (e.g., due to a thread join, assume statement, ...), we need to ask for another thread to schedule. - // - The current thread is the main thread, and it has completed all user code. - info!("GenMC: schedule_thread: overriding check for terminator."); - ActionKind::NonLoad - } else { - let Some(frame) = thread_manager.get_thread_stack(active_thread_id).last() else { - info!("GenMC: Skipping scheduling (0)"); - return interp_ok(active_thread_id); - }; - let either::Either::Left(loc) = frame.current_loc() else { - // We are unwinding. - info!("GenMC: Skipping scheduling (1): unwinding"); - return interp_ok(active_thread_id); - }; - let basic_block = &frame.body().basic_blocks[loc.block]; - if let Some(_statement) = basic_block.statements.get(loc.statement_index) { - info!("GenMC: Skipping scheduling (2): Statement: {_statement:?}"); - return interp_ok(active_thread_id); - } - - // let mut terminator_cache = self.terminator_cache.borrow_mut(); - // let curr_thread_next_instr_kind = - // get_next_instr_kind(ecx, thread_manager, active_thread_id, &mut terminator_cache)?; - // let is_terminator_atomic = - if is_terminator_atomic( - ecx, - basic_block.terminator(), - active_thread_id, - // &mut terminator_cache, - )? { - ActionKind::Load - } else { - ActionKind::NonLoad - } - }; - - info!( - "GenMC: schedule_thread, active thread: {active_thread_id:?}, next instr.: '{curr_thread_next_instr_kind:?}'" - ); - - // let curr_thread_user_block = self.curr_thread_user_block.replace(false); - let thread_infos = self.thread_infos.borrow(); - let curr_thread_info = thread_infos.get_info(active_thread_id); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let result = - pinned_mc.scheduleNext(curr_thread_info.genmc_tid.0, curr_thread_next_instr_kind); - if result >= 0 { - // TODO GENMC: can we ensure this thread_id is valid? - let genmc_next_thread_id = result.try_into().unwrap(); - let genmc_next_thread_id = GenmcThreadId(genmc_next_thread_id); - let thread_infos = self.thread_infos.borrow(); - let next_thread_id = thread_infos.get_info_genmc(genmc_next_thread_id).miri_tid; - - return interp_ok(next_thread_id); - } - - // Negative result means that GenMC has no next thread to schedule. - // We could either be encountering a blocked execution, - // or we are in the special case of the main thread having all user code finished. - // If the latter is true, we schedule the main thread. - info!( - "GenMC: scheduleNext returned no thread to schedule. Is main thread user code finished: {}", - self.main_thread_user_code_finished.get() - ); - if self.main_thread_user_code_finished.get() - && thread_manager.threads_ref().iter_enumerated().all(|(thread_id, thread)| { - thread_id == ThreadId::MAIN_THREAD || thread.get_state().is_terminated() - }) - { - let state = thread_manager.threads_ref()[ThreadId::MAIN_THREAD].get_state(); - if !state.is_terminated() { - info!( - "GenMC: main thread user code finished, but not yet terminated (state: {state:?})" - ); - return interp_ok(ThreadId::MAIN_THREAD); - } - info!( - "GenMC: main thread user code finished and also terminated (state: {state:?})" - ); - } - throw_machine_stop!(TerminationInfo::GenmcBlockedExecution); + assert!(!self.allow_data_races.get()); + todo!() } -} - -impl GenmcCtx { - //* might fails if there's a race, load might also not read anything (returns None) */ - fn atomic_load_impl<'tcx>( - &self, - machine: &MiriMachine<'tcx>, - address: Size, - size: Size, - memory_ordering: MemOrdering, - genmc_old_value: GenmcScalar, - ) -> InterpResult<'tcx, GenmcScalar> { - assert!( - size.bytes() != 0 - && (memory_ordering == MemOrdering::NotAtomic || size.bytes().is_power_of_two()) - ); - if size.bytes() > 8 { - throw_unsup_format!("{UNSUPPORTED_ATOMICS_SIZE_MSG}"); - } - assert!(!self.allow_data_races.get()); // TODO GENMC: handle this properly - let thread_infos = self.thread_infos.borrow(); - let curr_thread_id = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; - - info!( - "GenMC: load, thread: {curr_thread_id:?} ({genmc_tid:?}), address: {addr} == {addr:#x}, size: {size:?}, ordering: {memory_ordering:?}, old_value: {genmc_old_value:x?}", - addr = address.bytes() - ); - let genmc_address = size_to_genmc(address); - let genmc_size = size_to_genmc(size); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let load_result = pinned_mc.handleLoad( - genmc_tid.0, - genmc_address, - genmc_size, - memory_ordering, - genmc_old_value, - ); - - if load_result.is_read_opt { - todo!(); - } - if let Some(error) = load_result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: load operation returned an error: \"{msg}\""); - throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here - } - - info!("GenMC: load returned value: {:?}", load_result.read_value); - - interp_ok(load_result.read_value) + pub(crate) fn handle_thread_stack_empty(&self, thread_id: ThreadId) { + todo!() } - fn atomic_store_impl<'tcx>( + pub(crate) fn handle_thread_finish<'tcx>( &self, - machine: &MiriMachine<'tcx>, - address: Size, - size: Size, - genmc_value: GenmcScalar, - genmc_old_value: GenmcScalar, - memory_ordering: MemOrdering, - ) -> InterpResult<'tcx, bool> { - assert!( - size.bytes() != 0 - && (memory_ordering == MemOrdering::NotAtomic || size.bytes().is_power_of_two()) - ); - if size.bytes() > 8 { - throw_unsup_format!("{UNSUPPORTED_ATOMICS_SIZE_MSG}"); - } - let thread_infos = self.thread_infos.borrow(); - let curr_thread_id = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; - - let genmc_address = size_to_genmc(address); - let genmc_size = size_to_genmc(size); - - info!( - "GenMC: store, thread: {curr_thread_id:?} ({genmc_tid:?}), address: {addr} = {addr:#x}, size: {size:?}, ordering {memory_ordering:?}, value: {genmc_value:?}", - addr = address.bytes() - ); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let store_result = pinned_mc.handleStore( - genmc_tid.0, - genmc_address, - genmc_size, - genmc_value, - genmc_old_value, - memory_ordering, - StoreEventType::Normal, - ); - - if let Some(error) = store_result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: store operation returned an error: \"{msg}\""); - throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here - } - - interp_ok(store_result.isCoMaxWrite) - } - - pub(crate) fn atomic_rmw_op_impl<'tcx>( - &self, - ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, - address: Size, - size: Size, - load_ordering: MemOrdering, - store_ordering: MemOrdering, - genmc_rmw_op: RMWBinOp, - genmc_rhs_scalar: GenmcScalar, - genmc_old_value: GenmcScalar, - ) -> InterpResult<'tcx, (Scalar, Option)> { - assert!( - size.bytes() <= 8, - "TODO GENMC: no support for accesses larger than 8 bytes (got {} bytes)", - size.bytes() - ); - let machine = &ecx.machine; - assert_ne!(0, size.bytes()); - let thread_infos = self.thread_infos.borrow(); - let curr_thread_id = machine.threads.active_thread(); - let genmc_tid = thread_infos.get_info(curr_thread_id).genmc_tid; - - let genmc_address = size_to_genmc(address); - let genmc_size = size_to_genmc(size); - - info!( - "GenMC: atomic_rmw_op, thread: {curr_thread_id:?} ({genmc_tid:?}) (op: {genmc_rmw_op:?}, rhs value: {genmc_rhs_scalar:?}), address: {address:?}, size: {size:?}, orderings: ({load_ordering:?}, {store_ordering:?})", - ); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let rmw_result = pinned_mc.handleReadModifyWrite( - genmc_tid.0, - genmc_address, - genmc_size, - load_ordering, - store_ordering, - genmc_rmw_op, - genmc_rhs_scalar, - genmc_old_value, - ); - - if let Some(error) = rmw_result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: RMW operation returned an error: \"{msg}\""); - throw_ub_format!("{}", msg); // TODO GENMC: proper error handling: find correct error here - } - - let old_value_scalar = genmc_scalar_to_scalar(ecx, rmw_result.old_value, size)?; - - let new_value_scalar = if rmw_result.isCoMaxWrite { - Some(genmc_scalar_to_scalar(ecx, rmw_result.new_value, size)?) - } else { - None - }; - interp_ok((old_value_scalar, new_value_scalar)) - } - - fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { - let thread_infos = self.thread_infos.borrow(); - let curr_thread = machine.threads.active_thread(); - let genmc_curr_thread = thread_infos.get_info(curr_thread).genmc_tid; - info!("GenMC: handle_user_block, blocking thread {curr_thread:?} ({genmc_curr_thread:?})"); - - let mut mc = self.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleUserBlock(genmc_curr_thread.0); - - interp_ok(()) - } -} - -/// Other functionality not directly related to event handling -impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - /// Given a `ty::Instance<'tcx>`, do any required special handling. Returns true if this `instance` should be skipped (i.e., no Mir should be executed for it). - fn check_genmc_intercept_function( - &mut self, - instance: rustc_middle::ty::Instance<'tcx>, - args: &[rustc_const_eval::interpret::FnArg<'tcx, crate::Provenance>], - dest: &crate::PlaceTy<'tcx>, - ret: Option, - ) -> InterpResult<'tcx, bool> { - let this = self.eval_context_mut(); - let genmc_ctx = this - .machine - .data_race - .as_genmc_ref() - .expect("This function should only be called in GenMC mode."); - - let get_mutex_call_infos = || { - // assert!(!args.is_empty()); - assert_eq!(args.len(), 1); - let arg = this.copy_fn_arg(&args[0]); - let addr = this.read_target_usize(&arg)?; - // FIXME(genmc): assert that we have at least 1 byte. - // FIXME(genmc): maybe use actual size of mutex here?. - - let thread_infos = genmc_ctx.thread_infos.borrow(); - let curr_thread = this.machine.threads.active_thread(); - let genmc_curr_thread = thread_infos.get_info(curr_thread).genmc_tid; - interp_ok((genmc_curr_thread, addr, 1)) - }; - - use rustc_span::sym; - if this.tcx.is_diagnostic_item(sym::sys_mutex_lock, instance.def_id()) { - info!("GenMC: handling Mutex::lock()"); - let (genmc_curr_thread, addr, size) = get_mutex_call_infos()?; - - let result = { - let mut mc = genmc_ctx.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleMutexLock(genmc_curr_thread.0, addr, size) - }; - if let Some(error) = result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: handling Mutex::lock: error: {msg:?}"); - throw_ub_format!("{msg}"); - } - // TODO GENMC(HACK): for determining if the Mutex lock blocks this thread. - if !result.is_lock_acquired { - fn create_callback<'tcx>( - genmc_curr_thread: i32, - addr: u64, - size: u64, - ) -> crate::DynUnblockCallback<'tcx> { - crate::callback!( - @capture<'tcx> { - // mutex_ref: MutexRef, - // retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, - genmc_curr_thread: i32, - addr: u64, - size: u64, - } - |this, unblock: crate::UnblockKind| { - assert_eq!(unblock, crate::UnblockKind::Ready); - let genmc_ctx = this.machine.data_race.as_genmc_ref().unwrap(); - - info!("GenMC: handling Mutex::lock: unblocking callback called!"); - let result = { - let mut mc = genmc_ctx.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleMutexLock(genmc_curr_thread, addr, size) - }; - if let Some(error) = result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: handling Mutex::lock: error: {msg:?}"); - throw_ub_format!("{msg}"); - } - // TODO GENMC(HACK): for determining if the Mutex lock blocks this thread. - if !result.is_lock_acquired { - // If this thread gets woken up without the mutex being made available, block the thread again. - this.block_thread( crate::BlockReason::Mutex, None, create_callback(genmc_curr_thread, addr, size)); - // panic!( - // "Somehow, Mutex is still locked after waiting thread was unblocked?!" - // ); - } - interp_ok(()) - } - ) - } - - info!("GenMC: handling Mutex::lock failed, blocking thread"); - // NOTE: We don't write anything back to Miri's memory, the Mutex state is handled only by GenMC. - - info!("GenMC: blocking thread due to intercepted call."); - let genmc_curr_thread = genmc_curr_thread.0; - this.block_thread( - crate::BlockReason::Mutex, - None, - create_callback(genmc_curr_thread, addr, size), - ); - } else { - info!("GenMC: handling Mutex::lock: success: lock acquired."); - } - } else if this.tcx.is_diagnostic_item(sym::sys_mutex_try_lock, instance.def_id()) { - info!("GenMC: handling Mutex::try_lock()"); - let (genmc_curr_thread, addr, size) = get_mutex_call_infos()?; - - let result = { - let mut mc = genmc_ctx.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - pinned_mc.handleMutexTryLock(genmc_curr_thread.0, addr, size) - }; - if let Some(error) = result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - info!("GenMC: handling Mutex::try_lock: error: {msg:?}"); - throw_ub_format!("{msg}"); - } - info!("GenMC: Mutex::try_lock(): writing resulting bool is_lock_acquired ({}) to place: {dest:?}", result.is_lock_acquired); - - this.write_scalar(Scalar::from_bool(result.is_lock_acquired), dest)?; - // todo!("return whether lock was successful or not"); - } else if this.tcx.is_diagnostic_item(sym::sys_mutex_unlock, instance.def_id()) { - info!("GenMC: handling Mutex::unlock()"); - let (genmc_curr_thread, addr, size) = get_mutex_call_infos()?; - - let mut mc = genmc_ctx.handle.borrow_mut(); - let pinned_mc = mc.as_mut(); - let result = pinned_mc.handleMutexUnlock(genmc_curr_thread.0, addr, size); - if let Some(error) = result.error.as_ref() { - let msg = error.to_string_lossy().to_string(); - throw_ub_format!("{msg}"); - } - // NOTE: We don't write anything back to Miri's memory, the Mutex state is handled only by GenMC. - - // this.unblock_thread(, crate::BlockReason::Mutex)?; - } else { - return interp_ok(false); - }; - - this.return_to_block(ret)?; - - interp_ok(true) + threads: &ThreadManager<'tcx>, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() } /**** Scheduling functionality ****/ /// Ask for a scheduling decision. This should be called before every MIR instruction. /// - /// GenMC may realize that the execution is blocked, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcBlockedExecution`). + /// GenMC may realize that the execution got stuck, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). /// /// This is **not** an error by iself! Treat this as if the program ended normally: `handle_execution_end` should be called next, which will determine if were are any actual errors. - fn genmc_schedule_thread( - &mut self, + pub(crate) fn schedule_thread<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, ) -> InterpResult<'tcx, ThreadId> { - let this = self.eval_context_mut(); - loop { - let genmc_ctx = this.machine.data_race.as_genmc_ref().unwrap(); - let next_thread_id = genmc_ctx.schedule_thread(this)?; - - match this.machine.threads.threads_ref()[next_thread_id].get_state() { - ThreadState::Blocked { - reason: block_reason @ (BlockReason::Mutex | BlockReason::GenmcAssume), - .. - } => { - info!( - "GenMC: schedule returned thread {next_thread_id:?}, which is blocked, so we unblock it now." - ); - this.unblock_thread(next_thread_id, *block_reason)?; - - // In some cases, like waiting on a Mutex::lock, the thread might still be blocked here: - if this.machine.threads.threads_ref()[next_thread_id] - .get_state() - .is_blocked_on(crate::BlockReason::Mutex) - { - info!("GenMC: Unblocked thread is blocked on a Mutex again!"); - continue; - } - } - _ => {} - } - - return interp_ok(next_thread_id); - } + assert!(!self.allow_data_races.get()); + todo!() } /**** Blocking instructions ****/ - /// Handle an `assume` statement. This will tell GenMC to block the current thread if the `condition` is false. - /// Returns `true` if the current thread should be blocked in Miri too. - fn handle_genmc_verifier_assume( - &mut self, - condition: &OpTy<'tcx>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let condition_bool = this.read_scalar(condition)?.to_bool()?; - info!("GenMC: handle_verifier_assume, condition: {condition:?} = {condition_bool}"); - if condition_bool { - return interp_ok(()); - } - let genmc_ctx = this.machine.data_race.as_genmc_ref().unwrap(); - genmc_ctx.handle_user_block(&this.machine)?; - let condition = condition.clone(); - this.block_thread( - BlockReason::GenmcAssume, - None, - callback!( - @capture<'tcx> { - condition: OpTy<'tcx>, - } - |this, unblock: UnblockKind| { - assert_eq!(unblock, UnblockKind::Ready); - - let condition = this.run_for_validation_ref(|this| this.read_scalar(&condition))?.to_bool()?; - assert!(condition); - - interp_ok(()) - } - ), - ); - interp_ok(()) + pub(crate) fn handle_verifier_assume<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + condition: bool, + ) -> InterpResult<'tcx, ()> { + if condition { interp_ok(()) } else { self.handle_user_block(machine) } } - } impl VisitProvenance for GenmcCtx { @@ -1264,11 +288,8 @@ impl VisitProvenance for GenmcCtx { } } -impl std::fmt::Debug for GenmcCtx { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("GenmcCtx") - // .field("mc", &self.mc) - .field("thread_infos", &self.thread_infos) - .finish_non_exhaustive() +impl GenmcCtx { + fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { + todo!() } } diff --git a/src/concurrency/genmc/thread_info_manager.rs b/src/concurrency/genmc/thread_info_manager.rs deleted file mode 100644 index 7f4ee682d6..0000000000 --- a/src/concurrency/genmc/thread_info_manager.rs +++ /dev/null @@ -1,95 +0,0 @@ -use genmc_sys::{GENMC_MAIN_THREAD_ID, GenmcThreadId}; -use rustc_data_structures::fx::FxHashMap; - -use crate::ThreadId; - -#[derive(Debug)] -pub struct ThreadInfo { - pub miri_tid: ThreadId, - pub genmc_tid: GenmcThreadId, - // TODO GENMC: Do we need this? Only for the main thread? - pub user_code_finished: bool, -} - -impl ThreadInfo { - const MAIN_THREAD_INFO: Self = Self::new(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); - - #[must_use] - pub const fn new(miri_tid: ThreadId, genmc_tid: GenmcThreadId) -> Self { - Self { miri_tid, genmc_tid, user_code_finished: false } - } -} - -#[derive(Debug)] -pub struct ThreadInfoManager { - tid_map: FxHashMap, - thread_infos: Vec, -} - -impl Default for ThreadInfoManager { - fn default() -> Self { - Self::new() - } -} - -impl ThreadInfoManager { - #[must_use] - pub fn new() -> Self { - let mut tid_map = FxHashMap::default(); - tid_map.insert(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); - let thread_infos = vec![ThreadInfo::MAIN_THREAD_INFO]; - Self { tid_map, thread_infos } - } - - pub fn reset(&mut self) { - self.tid_map.clear(); - self.tid_map.insert(ThreadId::MAIN_THREAD, GENMC_MAIN_THREAD_ID); - self.thread_infos.clear(); - self.thread_infos.push(ThreadInfo::MAIN_THREAD_INFO); - } - - #[must_use] - #[allow(unused)] - pub fn thread_count(&self) -> usize { - self.thread_infos.len() - } - - pub fn add_thread(&mut self, thread_id: ThreadId) -> GenmcThreadId { - // NOTE: GenMC thread ids are integers incremented by one every time - let index = self.thread_infos.len(); - let genmc_tid = GenmcThreadId(index.try_into().unwrap()); - let thread_info = ThreadInfo::new(thread_id, genmc_tid); - // TODO GENMC: Document this in place where ThreadIds are created - assert!( - self.tid_map.insert(thread_id, genmc_tid).is_none(), - "Cannot reuse thread ids: thread id {thread_id:?} already inserted" - ); - self.thread_infos.push(thread_info); - - genmc_tid - } - - #[must_use] - pub fn get_info(&self, thread_id: ThreadId) -> &ThreadInfo { - let genmc_tid = *self.tid_map.get(&thread_id).unwrap(); - self.get_info_genmc(genmc_tid) - } - - #[must_use] - pub fn get_info_genmc(&self, genmc_tid: GenmcThreadId) -> &ThreadInfo { - let index: usize = genmc_tid.0.try_into().unwrap(); - &self.thread_infos[index] - } - - #[must_use] - pub fn get_info_mut(&mut self, thread_id: ThreadId) -> &mut ThreadInfo { - let genmc_tid = *self.tid_map.get(&thread_id).unwrap(); - self.get_info_mut_genmc(genmc_tid) - } - - #[must_use] - pub fn get_info_mut_genmc(&mut self, genmc_tid: GenmcThreadId) -> &mut ThreadInfo { - let index: usize = genmc_tid.0.try_into().unwrap(); - &mut self.thread_infos[index] - } -} diff --git a/src/concurrency/genmc/warnings.rs b/src/concurrency/genmc/warnings.rs deleted file mode 100644 index e8d3b2a922..0000000000 --- a/src/concurrency/genmc/warnings.rs +++ /dev/null @@ -1,66 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_middle::query::TyCtxtAt; -use rustc_span::Span; - -use crate::{AtomicReadOrd, AtomicRwOrd}; - -#[derive(Default)] -pub struct WarningsCache { - emitted_compare_exchange_weak: FxHashSet, - emitted_compare_exchange_failure_ordering: FxHashSet<(Span, AtomicReadOrd, AtomicReadOrd)>, -} - -impl WarningsCache { - /// Warn about unsupported spurious failures of `compare_exchange_weak`, once per span, returning `true` if the warning was printed. - pub fn warn_once_compare_exchange_weak<'tcx>(&mut self, tcx: &TyCtxtAt<'tcx>) -> bool { - if self.emitted_compare_exchange_weak.insert(tcx.span) { - tcx.dcx().span_warn(tcx.span, "GenMC mode currently does not model spurious failures of `compare_exchange_weak`. This may lead to missed bugs (possible unsoundness)!"); - return true; - } - false - } - - /// Check if the given failure ordering is unsupported by GenMC. - /// Warning is printed only once per span and ordering combination. - /// Returns `true` if the warning was printed. - pub fn warn_once_rmw_failure_ordering<'tcx>( - &mut self, - tcx: &TyCtxtAt<'tcx>, - success_ordering: AtomicRwOrd, - failure_load_ordering: AtomicReadOrd, - ) -> bool { - let (success_load_ordering, _success_store_ordering) = - success_ordering.split_memory_orderings(); - let is_failure_ordering_weaker = match (success_load_ordering, failure_load_ordering) { - // Unsound: failure ordering is weaker than success ordering, but GenMC treats them as equally strong. - // Actual program execution might have behavior not modelled by GenMC: - (AtomicReadOrd::Acquire, AtomicReadOrd::Relaxed) - | (AtomicReadOrd::SeqCst, AtomicReadOrd::Relaxed) - | (AtomicReadOrd::SeqCst, AtomicReadOrd::Acquire) => true, - // Possible false positives: failure ordering is stronger than success ordering, but GenMC treats them as equally strong. - // We might explore executions that are not allowed by the program. - (AtomicReadOrd::Relaxed, AtomicReadOrd::Acquire) - | (AtomicReadOrd::Relaxed, AtomicReadOrd::SeqCst) - | (AtomicReadOrd::Acquire, AtomicReadOrd::SeqCst) => false, - // Correct: failure ordering is equally strong as success ordering: - (AtomicReadOrd::Relaxed, AtomicReadOrd::Relaxed) - | (AtomicReadOrd::Acquire, AtomicReadOrd::Acquire) - | (AtomicReadOrd::SeqCst, AtomicReadOrd::SeqCst) => return false, - }; - let key = (tcx.span, success_load_ordering, failure_load_ordering); - if self.emitted_compare_exchange_failure_ordering.insert(key) { - let error = if is_failure_ordering_weaker { - "miss bugs related to this memory access (possible unsoundness)!" - } else { - "incorrectly detect errors related to this memory access (possible false positives)." - }; - let msg = format!( - "GenMC currently does not model the atomic failure ordering for `compare_exchange`. Failure ordering '{failure_load_ordering:?}' is treated like '{success_load_ordering:?}', which means that Miri might {error}", - ); - // FIXME(genmc): this doesn't print a span: - tcx.dcx().span_warn(tcx.span, msg); - return true; - } - false - } -} diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index dee270abe0..c2ea8a00de 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -12,7 +12,5 @@ pub mod weak_memory; mod genmc; pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler}; -pub use self::genmc::{ - EvalContextExt as GenmcEvalContextExt, GenmcConfig, GenmcCtx, miri_genmc, -}; +pub use self::genmc::{GenmcConfig, GenmcCtx}; pub use self::vector_clock::VClock; diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index 444ef143c0..abfee0ee87 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::Span; -use crate::concurrency::{GenmcEvalContextExt as _, GlobalDataRaceHandler}; +use crate::concurrency::GlobalDataRaceHandler; use crate::shims::tls; use crate::*; @@ -110,13 +110,10 @@ pub enum BlockReason { Eventfd, /// Blocked on unnamed_socket. UnnamedSocket, - /// Blocked on a GenMC `assume` statement (GenMC mode only). - GenmcAssume, } /// The state of a thread. -// TODO GENMC: is this ok to be pub? -pub enum ThreadState<'tcx> { +enum ThreadState<'tcx> { /// The thread is enabled and can be executed. Enabled, /// The thread is blocked on something. @@ -138,16 +135,15 @@ impl<'tcx> std::fmt::Debug for ThreadState<'tcx> { } impl<'tcx> ThreadState<'tcx> { - // TODO GENMC: is it ok if these are pub? - pub fn is_enabled(&self) -> bool { + fn is_enabled(&self) -> bool { matches!(self, ThreadState::Enabled) } - pub fn is_terminated(&self) -> bool { + fn is_terminated(&self) -> bool { matches!(self, ThreadState::Terminated) } - pub fn is_blocked_on(&self, reason: BlockReason) -> bool { + fn is_blocked_on(&self, reason: BlockReason) -> bool { matches!(*self, ThreadState::Blocked { reason: actual_reason, .. } if actual_reason == reason) } } @@ -213,11 +209,6 @@ impl<'tcx> Thread<'tcx> { self.thread_name.as_deref() } - pub fn get_state(&self) -> &ThreadState<'tcx> { - // TODO GENMC: should this implementation detail be exposed? - &self.state - } - /// Get the name of the current thread for display purposes; will include thread ID if not set. fn thread_display_name(&self, id: ThreadId) -> String { if let Some(ref thread_name) = self.thread_name { @@ -352,9 +343,8 @@ impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> { } /// The moment in time when a blocked thread should be woken up. -// TODO GENMC: is this ok to be pub? #[derive(Debug)] -pub enum Timeout { +enum Timeout { Monotonic(Instant), RealTime(SystemTime), } @@ -501,11 +491,6 @@ impl<'tcx> ThreadManager<'tcx> { &mut self.threads[self.active_thread].stack } - /// TODO GENMC: this function can probably be removed once the GenmcCtx code is finished: - pub fn get_thread_stack(&self, id: ThreadId) -> &[Frame<'tcx, Provenance, FrameExtra<'tcx>>] { - &self.threads[id].stack - } - pub fn all_stacks( &self, ) -> impl Iterator>])> { @@ -535,21 +520,11 @@ impl<'tcx> ThreadManager<'tcx> { self.active_thread } - pub fn threads_ref(&self) -> &IndexVec> { - // TODO GENMC: should this implementation detail be exposed? - &self.threads - } - /// Get the total number of threads that were ever spawn by this program. pub fn get_total_thread_count(&self) -> usize { self.threads.len() } - /// Get the total of threads that are currently enabled, i.e., could continue executing. - pub fn get_enabled_thread_count(&self) -> usize { - self.threads.iter().filter(|t| t.state.is_enabled()).count() - } - /// Get the total of threads that are currently live, i.e., not yet terminated. /// (They might be blocked.) pub fn get_live_thread_count(&self) -> usize { @@ -593,8 +568,6 @@ impl<'tcx> ThreadManager<'tcx> { fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> InterpResult<'tcx> { trace!("detaching {:?}", id); - tracing::info!("GenMC: TODO GENMC: does GenMC need special handling for detached threads?"); - let is_ub = if allow_terminated_joined && self.threads[id].state.is_terminated() { // "Detached" in particular means "not yet joined". Redundant detaching is still UB. self.threads[id].join_status == ThreadJoinStatus::Detached @@ -703,6 +676,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); + // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let thread_id = this.active_thread(); + genmc_ctx.handle_thread_stack_empty(thread_id); + } let mut callback = this .active_thread_mut() .on_stack_empty @@ -710,11 +688,6 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { .expect("`on_stack_empty` not set up, or already running"); let res = callback(this)?; this.active_thread_mut().on_stack_empty = Some(callback); - // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - let thread_id = this.active_thread(); - genmc_ctx.handle_thread_stack_empty(&this.machine.threads, thread_id); - } interp_ok(res) } @@ -728,10 +701,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// If GenMC mode is active, the scheduling is instead handled by GenMC. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - - // In GenMC mode, we let GenMC do the scheduling. - if this.machine.data_race.as_genmc_ref().is_some() { - let next_thread_id = this.genmc_schedule_thread()?; + // In GenMC mode, we let GenMC do the scheduling + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let next_thread_id = genmc_ctx.schedule_thread(this)?; let thread_manager = &mut this.machine.threads; thread_manager.active_thread = next_thread_id; @@ -741,7 +713,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { return interp_ok(SchedulingAction::ExecuteStep); } - // We are not in GenMC mode, so we control the scheduling. + // We are not in GenMC mode, so we control the schedule let thread_manager = &mut this.machine.threads; let clock = &this.machine.monotonic_clock; let rng = this.machine.rng.get_mut(); @@ -889,12 +861,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { GlobalDataRaceHandler::Vclocks(data_race) => data_race.thread_created(&this.machine.threads, new_thread_id, current_span), GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_thread_create( - &this.machine.threads, - start_routine, - &func_arg, - new_thread_id, - )?, + genmc_ctx.handle_thread_create(&this.machine.threads, new_thread_id)?, } // Write the current thread-id, switch to the next thread later // to treat this write operation as occurring on the current thread. @@ -947,10 +914,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread = this.active_thread_mut(); assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated"); thread.state = ThreadState::Terminated; - - // TODO GENMC (QUESTION): Can we move this down to where the GenmcCtx is? - if let Some(data_race) = this.machine.data_race.as_vclocks_mut() { - data_race.thread_terminated(&this.machine.threads); + match &mut this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_terminated(&this.machine.threads), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_finish(&this.machine.threads)?, } // Deallocate TLS. let gone_thread = this.active_thread(); @@ -982,13 +951,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } - - // Inform GenMC that the thread finished. - // This needs to happen once all accesses to the thread are done, including freeing any TLS statics. - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - genmc_ctx.handle_thread_finish(&this.machine.threads); - } - // Unblock joining threads. let unblock_reason = BlockReason::Join(gone_thread); let threads = &this.machine.threads.threads; @@ -1112,11 +1074,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "{:?} blocked on {:?} when trying to join", thread_mgr.active_thread, joined_thread_id ); - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { - info!("GenMC: informing GenMC about blocked thread join."); - genmc_ctx.handle_thread_join(thread_mgr.active_thread, joined_thread_id)?; - } - // The joined thread is still running, we need to wait for it. // Once we get unblocked, perform the appropriate synchronization and write the return value. let dest = return_dest.clone(); @@ -1247,7 +1204,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); - if !this.machine.threads.fixed_scheduling && this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) { @@ -1278,7 +1234,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { SchedulingAction::ExecuteTimeoutCallback => { this.run_timeout_callback()?; } - // TODO GENMC: do we need to sleep in GenMC Mode? SchedulingAction::Sleep(duration) => { this.machine.monotonic_clock.sleep(duration); } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index ef0332d312..a752ef7e45 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -175,7 +175,6 @@ impl StoreBufferAlloc { /// after all the prior atomic writes so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. pub fn memory_accessed(&self, range: AllocRange, global: &DataRaceState) { - // TODO GENMC: what needs to be done here for GenMC (if anything at all)? if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); @@ -461,7 +460,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; - // TODO GENMC: what needs to be done here for GenMC (if anything at all)? if let ( crate::AllocExtra { data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), @@ -544,7 +542,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?; - // TODO GENMC: what needs to be done here for GenMC (if anything at all)? if let ( crate::AllocExtra { data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8a36fd4356..9ecbd31c5b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -31,8 +31,8 @@ pub enum TerminationInfo { }, Int2PtrWithStrictProvenance, Deadlock, - /// In GenMC mode, an execution can get blocked in certain cases. This is not an error. - GenmcBlockedExecution, + /// In GenMC mode, an execution can get stuck in certain cases. This is not an error. + GenmcStuckExecution, MultipleSymbolDefinitions { link_name: Symbol, first: SpanData, @@ -77,7 +77,7 @@ impl fmt::Display for TerminationInfo { StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), TreeBorrowsUb { title, .. } => write!(f, "{title}"), Deadlock => write!(f, "the evaluated program deadlocked"), - GenmcBlockedExecution => write!(f, "GenMC determined that the execution is blocked"), + GenmcStuckExecution => write!(f, "GenMC determined that the execution got stuck"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => @@ -243,12 +243,11 @@ pub fn report_error<'tcx>( labels.push(format!("this thread got stuck here")); None } - GenmcBlockedExecution => { + GenmcStuckExecution => { // This case should only happen in GenMC mode. We treat it like a normal program exit. - // Leak checks should not be performed, since some threads might not have run to completion. assert!(ecx.machine.data_race.as_genmc_ref().is_some()); - tracing::info!("GenMC: found blocked execution"); - return Some((0, false)); + tracing::info!("GenMC: found stuck execution"); + return Some((0, true)); } MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; diff --git a/src/eval.rs b/src/eval.rs index 1c64e541f0..3c80e60b77 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -261,10 +261,9 @@ impl<'tcx> MainThreadState<'tcx> { match state.on_stack_empty(this)? { Poll::Pending => {} // just keep going Poll::Ready(()) => { - if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + if this.machine.data_race.as_genmc_ref().is_some() { // In GenMC mode, we don't yield at the end of the main thread. // Instead, the `GenmcCtx` will ensure that unfinished threads get a chance to run at this point. - genmc_ctx.handle_main_thread_stack_empty(&this.machine.threads); *self = Done; } else { // Give background threads a chance to finish by yielding the main thread a diff --git a/src/lib.rs b/src/lib.rs index fe5fa6eb19..ae70257653 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ pub use crate::concurrency::thread::{ BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; -pub use crate::concurrency::{GenmcConfig, GenmcCtx, miri_genmc}; +pub use crate::concurrency::{GenmcConfig, GenmcCtx}; pub use crate::data_structures::dedup_range_map::DedupRangeMap; pub use crate::data_structures::mono_hash_map::MonoHashMap; pub use crate::diagnostics::{ diff --git a/src/machine.rs b/src/machine.rs index 3ba7028970..ce33c870b4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -31,9 +31,7 @@ use rustc_target::callconv::FnAbi; use crate::alloc_addresses::EvalContextExt; use crate::concurrency::cpu_affinity::{self, CpuAffinityMask}; use crate::concurrency::data_race::{self, NaReadType, NaWriteType}; -use crate::concurrency::{ - AllocDataRaceHandler, GenmcCtx, GenmcEvalContextExt as _, GlobalDataRaceHandler, weak_memory, -}; +use crate::concurrency::{AllocDataRaceHandler, GenmcCtx, GlobalDataRaceHandler, weak_memory}; use crate::*; /// First real-time signal. @@ -1143,12 +1141,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); } - if ecx.machine.data_race.as_genmc_ref().is_some() - && ecx.check_genmc_intercept_function(instance, args, dest, ret)? - { - return interp_ok(None); - } - // Otherwise, load the MIR. interp_ok(Some((ecx.load_mir(instance.def, None)?, instance))) } @@ -1301,10 +1293,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { size: Size, align: Align, ) -> InterpResult<'tcx, Self::AllocExtra> { - info!( - "GenMC: TODO GENMC: init_local_allocation: id: {id:?}, kind: {kind:?}, size: {size:?}, align: {align:?}" - ); - assert!(kind != MiriMemoryKind::Global.into()); MiriMachine::init_allocation(ecx, id, kind, size, align) } @@ -1396,10 +1384,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { alloc: &'b Allocation, ) -> InterpResult<'tcx, Cow<'b, Allocation>> { - info!( - "GenMC: adjust_global_allocation (TODO GENMC): id: {id:?} ==> Maybe tell GenMC about initial value here?" - ); - let alloc = alloc.adjust_from_tcx( &ecx.tcx, |bytes, align| ecx.get_global_alloc_bytes(id, bytes, align), @@ -1461,9 +1445,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { match &machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Genmc(genmc_ctx) => { - // TODO GENMC(mixed atomic-non-atomic): is this needed? - // let old_val = this.run_for_validation_ref(|this| this.read_scalar(dest)).discard_err(); - genmc_ctx.memory_store(machine, ptr.addr(), range.size /* , old_val */)?; + genmc_ctx.memory_store(machine, ptr.addr(), range.size)?; } GlobalDataRaceHandler::Vclocks(_global_state) => { let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = @@ -1500,7 +1482,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { match &machine.data_race { GlobalDataRaceHandler::None => {} GlobalDataRaceHandler::Genmc(genmc_ctx) => - genmc_ctx.handle_dealloc(machine, alloc_id, ptr.addr(), size, align, kind)?, + genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?, GlobalDataRaceHandler::Vclocks(_global_state) => { let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap(); data_race.write( @@ -1591,7 +1573,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let borrow_tracker = ecx.machine.borrow_tracker.as_ref(); - // TODO GENMC: what needs to be done here for GenMC (if anything at all)? let extra = FrameExtra { borrow_tracker: borrow_tracker.map(|bt| bt.borrow_mut().new_frame()), catch_unwind: None, @@ -1713,7 +1694,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>, local: mir::Local, ) -> InterpResult<'tcx> { - // TODO GENMC: does GenMC care about local reads/writes? if let Some(data_race) = &frame.extra.data_race { data_race.local_read(local, &ecx.machine); } @@ -1725,7 +1705,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { local: mir::Local, storage_live: bool, ) -> InterpResult<'tcx> { - // TODO GENMC: does GenMC care about local reads/writes? if let Some(data_race) = &ecx.frame().extra.data_race { data_race.local_write(local, storage_live, &ecx.machine); } @@ -1755,7 +1734,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine, ); } - // TODO GENMC: how to handle this (if at all)? interp_ok(()) } @@ -1774,7 +1752,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { Option>, ) -> InterpResult<'tcx, OpTy<'tcx>>, { - info!("GenMC: TODO GENMC: evaluating MIR constant: {val:?}"); let frame = ecx.active_thread_stack().last().unwrap(); let mut cache = ecx.machine.const_cache.borrow_mut(); match cache.entry((val, frame.extra.salt)) { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2452bdfa81..94cda57658 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -17,7 +17,6 @@ use rustc_target::callconv::FnAbi; use self::helpers::{ToHost, ToSoft}; use super::alloc::EvalContextExt as _; use super::backtrace::EvalContextExt as _; -use crate::concurrency::GenmcEvalContextExt as _; use crate::*; /// Type of dynamic symbols (for `dlsym` et al) @@ -436,21 +435,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - /*** \/ GENMC VERIFIER CALLS \/ ****/ - "miri_genmc_verifier_assume" => { - let [condition] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?; - if this.machine.data_race.as_genmc_ref().is_some() { - this.handle_genmc_verifier_assume(condition)?; - } else { - tracing::warn!( - "GenMC: function `miri_genmc_verifier_assume` used, but GenMC mode is not active, skip ..." - ); - } - } - - // TODO GENMC: add other genmc functions - - /*** /\ GENMC VERIFIER CALLS /\ ****/ // Aborting the process. "exit" => { let [code] = this.check_shim(abi, CanonAbi::C, link_name, args)?; diff --git a/tests/genmc/pass/test_cxx_build.rs b/tests/genmc/pass/test_cxx_build.rs new file mode 100644 index 0000000000..f621bd9114 --- /dev/null +++ b/tests/genmc/pass/test_cxx_build.rs @@ -0,0 +1,8 @@ +//@compile-flags: -Zmiri-genmc + +#![no_main] + +#[unsafe(no_mangle)] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} diff --git a/tests/genmc/pass/test_cxx_build.stderr b/tests/genmc/pass/test_cxx_build.stderr new file mode 100644 index 0000000000..26cc892215 --- /dev/null +++ b/tests/genmc/pass/test_cxx_build.stderr @@ -0,0 +1,4 @@ +C++: GenMC handle created! +Miri: GenMC handle creation successful! +C++: GenMC handle destroyed! +Miri: Dropping GenMC handle successful! From 4117ec9093500cb4ce85d50962e19daef56f8af0 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 11:52:34 +0200 Subject: [PATCH 04/64] Small cleanup, disable genmc feature by default --- Cargo.toml | 6 +----- genmc-sys/build.rs | 20 ++++++++++---------- genmc-sys/src_cpp/MiriInterface.cpp | 1 - src/concurrency/genmc/config.rs | 5 +++-- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 751559b6fd..d590cd5ab6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ chrono-tz = "0.10" directories = "6" bitflags = "2.6" serde_json = { version = "1.0", optional = true } -# cxx = { version = "1.0.160", features = ["c++20"], optional = true } genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } # Copied from `compiler/rustc/Cargo.toml`. @@ -67,11 +66,8 @@ name = "ui" harness = false [features] -# TODO GENMC (DEBUGGING): `genmc` feature should be turned off in upstream repo for now -default = ["stack-cache", "genmc"] +default = ["stack-cache", "native-lib"] genmc = ["dep:genmc-sys"] -# default = ["stack-cache", "native-lib"] -# genmc = ["dep:cxx", "dep:genmc-sys"] stack-cache = [] stack-cache-consistency-check = ["stack-cache"] tracing = ["serde_json"] diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 1cfbbba682..f0821968b5 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -8,7 +8,7 @@ const GENMC_MODEL_CHECKER: &str = "model_checker"; const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; -// FIXME(genmc,cmake): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB) +// FIXME(GenMC, build): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB) const ENABLE_GENMC_DEBUG: bool = true; #[cfg(feature = "vendor_genmc")] @@ -94,17 +94,17 @@ fn build_cxx_bridge(genmc_path: &Path) { let mut bridge = cxx_build::bridge("src/lib.rs"); - // TODO GENMC: make sure GenMC uses the same compiler / settings as the cxx_bridge - // TODO GENMC: can we use c++23? Does CXX support that? Does rustc CI support that? + // FIXME(GenMC, build): make sure GenMC uses the same compiler / settings as the cxx_bridge + // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? bridge .opt_level(2) - .debug(true) - .warnings(false) // TODO GENMC: try to fix some of those warnings + .debug(true) // Same settings that GenMC uses ("-O2 -g") + .warnings(false) // NOTE: enabling this produces a lot of warnings. .std("c++20") .include(genmc_common_include_path) .include(model_checker_include_path) .include("./src_cpp") - .define("PACKAGE_BUGREPORT", "\"FIXME(GenMC) determine what to do with this!!\"") // FIXME(GenMC): HACK to get stuff to compile + .define("PACKAGE_BUGREPORT", "\"FIXME(GenMC) determine what to do with this!!\"") // FIXME(GenMC): HACK to get stuff to compile (this is normally defined by cmake) .file("./src_cpp/MiriInterface.hpp") .file("./src_cpp/MiriInterface.cpp"); @@ -128,12 +128,12 @@ fn build_genmc_model_checker(genmc_path: &Path) { let cmakelists_path = genmc_path.join("CMakeLists.txt"); let mut config = cmake::Config::new(cmakelists_path); - config.profile("RelWithDebInfo"); // FIXME(genmc,cmake): decide on profile to use + config.profile("RelWithDebInfo"); // FIXME(GenMC,cmake): decide on profile to use if ENABLE_GENMC_DEBUG { config.define("GENMC_DEBUG", "ON"); } - // FIXME(HACK): Required for unknown reasons on older cmake (version 3.22.1, works without this with version 3.31.6) + // FIXME(GenMC,HACK): Required for unknown reasons on older cmake (version 3.22.1, works without this with version 3.31.6) // Without this, the files are written into the source directory by the cmake configure step, and then // the build step cannot find these files, because it correctly tries using the `target` directory. let out_dir = std::env::var("OUT_DIR").unwrap(); @@ -167,12 +167,12 @@ fn main() { vendoring::vendor_genmc() }; - // FIXME(genmc, performance): these *should* be able to build in parallel: + // FIXME(GenMC, performance): these *should* be able to build in parallel: // Build all required components: build_cxx_bridge(&genmc_path); build_genmc_model_checker(&genmc_path); - // FIXME(build): Cloning the GenMC repo triggers a rebuild on the next build (since the directory changed during the first build) + // FIXME(GenMC, build): Cloning the GenMC repo triggers a rebuild on the next build (since the directory changed during the first build) // Only rebuild if anything changes: println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); diff --git a/genmc-sys/src_cpp/MiriInterface.cpp b/genmc-sys/src_cpp/MiriInterface.cpp index 3e6921eb2a..e740d496c1 100644 --- a/genmc-sys/src_cpp/MiriInterface.cpp +++ b/genmc-sys/src_cpp/MiriInterface.cpp @@ -2,7 +2,6 @@ #include "genmc-sys/src/lib.rs.h" -// NOLINTNEXTLINE(readability-convert-member-functions-to-static) auto MiriGenMCShim::createHandle(const GenmcParams &config) -> std::unique_ptr { diff --git a/src/concurrency/genmc/config.rs b/src/concurrency/genmc/config.rs index dbc546d32c..767bcbfcaf 100644 --- a/src/concurrency/genmc/config.rs +++ b/src/concurrency/genmc/config.rs @@ -7,12 +7,12 @@ use super::GenmcParams; pub struct GenmcConfig { pub(super) params: GenmcParams, do_estimation: bool, - // FIXME: add remaining options. + // FIXME(GenMC): add remaining options. } impl GenmcConfig { /// Function for parsing command line options for GenMC mode. - /// + /// /// All GenMC arguments start with the string "-Zmiri-genmc". /// Passing any GenMC argument will enable GenMC mode. /// @@ -25,5 +25,6 @@ impl GenmcConfig { return; // this corresponds to "-Zmiri-genmc" } // FIXME(GenMC): implement remaining parameters. + todo!(); } } From c1f215767c435661007cd401601b94a0d7815a24 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 13:42:40 +0200 Subject: [PATCH 05/64] Update linked GenMC git commit --- genmc-sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index f0821968b5..1b64290743 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -21,7 +21,7 @@ mod vendoring { use super::GENMC_LOCAL_PATH_STR; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; - pub(crate) const GENMC_COMMIT: &str = "338a44e65c8c737fcf4443a1fde241c4afcde278"; + pub(crate) const GENMC_COMMIT: &str = "3791d9a97baeb96e8c8375002fb390a789ba28b0"; pub(crate) const GENMC_VENDORED_PATH_STR: &str = "./vendored/genmc/"; pub(crate) fn vendor_genmc() -> PathBuf { From ac4ab72e60aa31074f65b6b95cb4eeef9c240b2f Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 13:55:44 +0200 Subject: [PATCH 06/64] Update linked GenMC git commit again --- genmc-sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 1b64290743..3634565700 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -21,7 +21,7 @@ mod vendoring { use super::GENMC_LOCAL_PATH_STR; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; - pub(crate) const GENMC_COMMIT: &str = "3791d9a97baeb96e8c8375002fb390a789ba28b0"; + pub(crate) const GENMC_COMMIT: &str = "e362c6f73f3567f972cbefb1323973e7120c9cf6"; pub(crate) const GENMC_VENDORED_PATH_STR: &str = "./vendored/genmc/"; pub(crate) fn vendor_genmc() -> PathBuf { From 718500d934f17e82d5d545bd25a373b2acee1905 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 14:32:34 +0200 Subject: [PATCH 07/64] Update linked GenMC git commit again 2 --- genmc-sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 3634565700..b3169a5f68 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -21,7 +21,7 @@ mod vendoring { use super::GENMC_LOCAL_PATH_STR; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; - pub(crate) const GENMC_COMMIT: &str = "e362c6f73f3567f972cbefb1323973e7120c9cf6"; + pub(crate) const GENMC_COMMIT: &str = "bd4496acaf0994b2515f58f75d21ad8dd15f6603"; pub(crate) const GENMC_VENDORED_PATH_STR: &str = "./vendored/genmc/"; pub(crate) fn vendor_genmc() -> PathBuf { From 95e1f4cdc3db6b04770af5103ed8b63088a2f432 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 14:41:26 +0200 Subject: [PATCH 08/64] Switch terms: 'vendoring' --> 'downloading' --- genmc-sys/.gitignore | 2 +- genmc-sys/Cargo.toml | 6 +++--- genmc-sys/build.rs | 27 +++++++++++++-------------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/genmc-sys/.gitignore b/genmc-sys/.gitignore index f35ff32fdf..f526fe37c0 100644 --- a/genmc-sys/.gitignore +++ b/genmc-sys/.gitignore @@ -1,3 +1,3 @@ genmc/ genmc-*/ -vendored/ +downloaded/ diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index d5085c7eab..048df13d2d 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -4,9 +4,9 @@ version = "0.11.0" # NOTE: should match the GenMC version edition = "2024" [features] -default = ["vendor_genmc"] -# If vendoring is disabled, a local GenMC repo must be available in the "./genmc" path. -vendor_genmc = ["dep:git2"] +default = ["download_genmc"] +# If downloading is disabled, a local GenMC repo must be available in the "./genmc" path. +download_genmc = ["dep:git2"] [dependencies] cxx = { version = "1.0.160", features = ["c++20"] } diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index b3169a5f68..ede79df0ed 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -11,8 +11,8 @@ const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; // FIXME(GenMC, build): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB) const ENABLE_GENMC_DEBUG: bool = true; -#[cfg(feature = "vendor_genmc")] -mod vendoring { +#[cfg(feature = "download_genmc")] +mod downloading { use std::path::PathBuf; use std::str::FromStr; @@ -22,13 +22,13 @@ mod vendoring { pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; pub(crate) const GENMC_COMMIT: &str = "bd4496acaf0994b2515f58f75d21ad8dd15f6603"; - pub(crate) const GENMC_VENDORED_PATH_STR: &str = "./vendored/genmc/"; + pub(crate) const GENMC_DOWNLOAD_PATH_STR: &str = "./downloaded/genmc/"; - pub(crate) fn vendor_genmc() -> PathBuf { - let Ok(genmc_vendored_path) = PathBuf::from_str(GENMC_VENDORED_PATH_STR); + pub(crate) fn download_genmc() -> PathBuf { + let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH_STR); - let repo = Repository::open(&genmc_vendored_path).unwrap_or_else(|open_err| { - match Repository::clone(GENMC_GITHUB_URL, &genmc_vendored_path) { + let repo = Repository::open(&genmc_download_path).unwrap_or_else(|open_err| { + match Repository::clone(GENMC_GITHUB_URL, &genmc_download_path) { Ok(repo) => { repo } @@ -68,7 +68,7 @@ mod vendoring { assert_eq!(head_commit.id(), commit.id()); println!("cargo::warning=Successfully set checked out commit {head_commit:?}"); - genmc_vendored_path + genmc_download_path } fn checkout_commit(repo: &Repository, refname: &str) { @@ -152,19 +152,18 @@ fn build_genmc_model_checker(genmc_path: &Path) { } fn main() { - // Select between local GenMC repo, or vendoring GenMC from a specific commit. + // Select between local GenMC repo, or downloading GenMC from a specific commit. let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH_STR); let genmc_path = if genmc_local_path.exists() { genmc_local_path } else { - #[cfg(not(feature = "vendor_genmc"))] + #[cfg(not(feature = "download_genmc"))] panic!( - "GenMC not found in path '{}', and vendoring GenMC is disabled.", - genmc_local_path.to_string_lossy() + "GenMC not found in path '{GENMC_LOCAL_PATH_STR}', and downloading GenMC is disabled." ); - #[cfg(feature = "vendor_genmc")] - vendoring::vendor_genmc() + #[cfg(feature = "download_genmc")] + downloading::download_genmc() }; // FIXME(GenMC, performance): these *should* be able to build in parallel: From ac42ae433bf7aac6e401e8384018d3c0da3884e4 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 8 Jul 2025 10:18:56 +0200 Subject: [PATCH 09/64] Disable unsupported platforms. --- Cargo.toml | 4 +++- src/concurrency/genmc/dummy.rs | 16 +++++++++++++--- src/concurrency/mod.rs | 10 +++++++++- tests/ui.rs | 8 +++++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d590cd5ab6..b3e7a3618f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ chrono-tz = "0.10" directories = "6" bitflags = "2.6" serde_json = { version = "1.0", optional = true } -genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } # Copied from `compiler/rustc/Cargo.toml`. # But only for some targets, it fails for others. Rustc configures this in its CI, but we can't @@ -49,6 +48,9 @@ nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = ipc-channel = { version = "0.20.0", optional = true } capstone = { version = "0.13", optional = true } +[target.'cfg(all(any(target_os = "linux", target_os = "macos"), target_pointer_width = "64"))'.dependencies] +genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } + [dev-dependencies] ui_test = "0.30.2" colored = "3" diff --git a/src/concurrency/genmc/dummy.rs b/src/concurrency/genmc/dummy.rs index 3d0558fb68..f32bbad4a4 100644 --- a/src/concurrency/genmc/dummy.rs +++ b/src/concurrency/genmc/dummy.rs @@ -228,9 +228,19 @@ impl VisitProvenance for GenmcCtx { impl GenmcConfig { pub fn parse_arg(_genmc_config: &mut Option, trimmed_arg: &str) { - unimplemented!( - "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" - ); + if cfg!(all( + feature = "genmc", + any(target_os = "linux", target_os = "macos"), + target_pointer_width = "64" + )) { + unimplemented!( + "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" + ); + } else { + unimplemented!( + "GenMC mode is not supported on this platform, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" + ); + } } pub fn should_print_graph(&self, _rep: usize) -> bool { diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index c2ea8a00de..ff958fbb83 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -8,7 +8,15 @@ mod vector_clock; pub mod weak_memory; // Import either the real genmc adapter or a dummy module. -#[cfg_attr(not(feature = "genmc"), path = "genmc/dummy.rs")] +// On unsupported platforms, we still include the dummy module, even if the `genmc` feature is enabled. +#[cfg_attr( + not(all( + feature = "genmc", + any(target_os = "linux", target_os = "macos"), + target_pointer_width = "64" + )), + path = "genmc/dummy.rs" +)] mod genmc; pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler}; diff --git a/tests/ui.rs b/tests/ui.rs index a1c2402c47..5d5b506941 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -337,7 +337,13 @@ fn main() -> Result<()> { ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?; ui(Mode::Fail, "tests/native-lib/fail", &target, WithoutDependencies, tmpdir.path())?; } - if cfg!(feature = "genmc") { + + // We only enable GenMC tests when the `genmc` feature is enabled, but also only on platforms we support: + if cfg!(all( + feature = "genmc", + any(target_os = "linux", target_os = "macos"), + target_pointer_width = "64" + )) { ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?; ui(Mode::Fail, "tests/genmc/fail", &target, WithDependencies, tmpdir.path())?; } From 6138dd719efe4eb3279828c83d4dc1f8a687a392 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 14:42:08 +0200 Subject: [PATCH 10/64] Throw an error when the downloaded GenMC repo is modified. --- genmc-sys/build.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index ede79df0ed..de0951d59b 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -40,6 +40,17 @@ mod downloading { } }); + let statuses = repo.statuses(None).expect("should be able to get repository status"); + if !statuses.is_empty() { + println!("cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH_STR}' has been modified"); + for entry in statuses.iter() { + println!("cargo::error= {} is {:?}", entry.path().unwrap_or("unknown"), entry.status()); + } + println!("cargo::error=This repository should only be modified by the 'genmc-sys' build script to load a specific commit ('{GENMC_COMMIT}')"); + println!("cargo::error=HINT: For local development, place a GenMC repository in the path '{GENMC_LOCAL_PATH_STR}'"); + std::process::exit(1); + } + // Check if there are any updates: let commit = if let Ok(oid) = Oid::from_str(GENMC_COMMIT) && let Ok(commit) = repo.find_commit(oid) From a9e87433e99851d0f234a1496ab866d3893a11ed Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 14:56:08 +0200 Subject: [PATCH 11/64] Update rebuild-if-changed paths --- genmc-sys/build.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index de0951d59b..8fd22b21c8 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -182,13 +182,10 @@ fn main() { build_cxx_bridge(&genmc_path); build_genmc_model_checker(&genmc_path); - // FIXME(GenMC, build): Cloning the GenMC repo triggers a rebuild on the next build (since the directory changed during the first build) - // Only rebuild if anything changes: + // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. + // Adding that path here would also trigger an unnecessary rebuild after the repo is cloned (since cargo detects that as a file modification). println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); println!("cargo::rerun-if-changed=./src_cpp"); - let genmc_src_paths = [genmc_path.join("model_checker"), genmc_path.join("common")]; - for genmc_src_path in genmc_src_paths { - println!("cargo::rerun-if-changed={}", genmc_src_path.display()); - } + println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH_STR}"); } From f2497d373bad16c42533e3a5c535dc24604ecb35 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:10:35 +0200 Subject: [PATCH 12/64] Disable unused crate feature --- Cargo.lock | 15 --------------- genmc-sys/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04187e5922..7c0e34515e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -818,7 +818,6 @@ checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" dependencies = [ "cc", "libc", - "libssh2-sys", "libz-sys", "openssl-sys", "pkg-config", @@ -844,20 +843,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libssh2-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - [[package]] name = "libz-sys" version = "1.1.22" diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index 048df13d2d..a7841a71f2 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -13,5 +13,5 @@ cxx = { version = "1.0.160", features = ["c++20"] } [build-dependencies] cmake = "0.1.54" -git2 = { version = "0.20.2", optional = true } +git2 = { version = "0.20.2", optional = true, default-features = false, features = ["https"] } cxx-build = { version = "1.0.160", features = ["parallel"] } From 7a45675e0f0fedd99229c7f3a7d5034729d37c1e Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:33:10 +0200 Subject: [PATCH 13/64] Remove comment, run formatter --- genmc-sys/build.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 8fd22b21c8..d18f8686e6 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -42,12 +42,22 @@ mod downloading { let statuses = repo.statuses(None).expect("should be able to get repository status"); if !statuses.is_empty() { - println!("cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH_STR}' has been modified"); + println!( + "cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH_STR}' has been modified" + ); for entry in statuses.iter() { - println!("cargo::error= {} is {:?}", entry.path().unwrap_or("unknown"), entry.status()); + println!( + "cargo::error= {} is {:?}", + entry.path().unwrap_or("unknown"), + entry.status() + ); } - println!("cargo::error=This repository should only be modified by the 'genmc-sys' build script to load a specific commit ('{GENMC_COMMIT}')"); - println!("cargo::error=HINT: For local development, place a GenMC repository in the path '{GENMC_LOCAL_PATH_STR}'"); + println!( + "cargo::error=This repository should only be modified by the 'genmc-sys' build script to load a specific commit ('{GENMC_COMMIT}')" + ); + println!( + "cargo::error=HINT: For local development, place a GenMC repository in the path '{GENMC_LOCAL_PATH_STR}'" + ); std::process::exit(1); } @@ -177,7 +187,6 @@ fn main() { downloading::download_genmc() }; - // FIXME(GenMC, performance): these *should* be able to build in parallel: // Build all required components: build_cxx_bridge(&genmc_path); build_genmc_model_checker(&genmc_path); From 27f0d7fd10c1dcb61785b995e1ac9211a887f414 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:37:53 +0200 Subject: [PATCH 14/64] Disable MacOS support. --- Cargo.toml | 3 ++- src/concurrency/mod.rs | 3 ++- tests/ui.rs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b3e7a3618f..0a101d4c7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,8 @@ nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = ipc-channel = { version = "0.20.0", optional = true } capstone = { version = "0.13", optional = true } -[target.'cfg(all(any(target_os = "linux", target_os = "macos"), target_pointer_width = "64"))'.dependencies] +# FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. +[target.'cfg(all(target_os = "linux", target_pointer_width = "64"))'.dependencies] genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } [dev-dependencies] diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index ff958fbb83..b574be5ecf 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -9,10 +9,11 @@ pub mod weak_memory; // Import either the real genmc adapter or a dummy module. // On unsupported platforms, we still include the dummy module, even if the `genmc` feature is enabled. +// FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. #[cfg_attr( not(all( feature = "genmc", - any(target_os = "linux", target_os = "macos"), + target_os = "linux", target_pointer_width = "64" )), path = "genmc/dummy.rs" diff --git a/tests/ui.rs b/tests/ui.rs index 5d5b506941..83d138b987 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -339,9 +339,10 @@ fn main() -> Result<()> { } // We only enable GenMC tests when the `genmc` feature is enabled, but also only on platforms we support: + // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. if cfg!(all( feature = "genmc", - any(target_os = "linux", target_os = "macos"), + target_os = "linux", target_pointer_width = "64" )) { ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?; From 2608e292ef314430a2c2aea0ee79473da2652477 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:40:58 +0200 Subject: [PATCH 15/64] Run fmt --- src/concurrency/mod.rs | 6 +----- tests/ui.rs | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index b574be5ecf..637e555b90 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -11,11 +11,7 @@ pub mod weak_memory; // On unsupported platforms, we still include the dummy module, even if the `genmc` feature is enabled. // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. #[cfg_attr( - not(all( - feature = "genmc", - target_os = "linux", - target_pointer_width = "64" - )), + not(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")), path = "genmc/dummy.rs" )] mod genmc; diff --git a/tests/ui.rs b/tests/ui.rs index 83d138b987..c3b99a8349 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -340,11 +340,7 @@ fn main() -> Result<()> { // We only enable GenMC tests when the `genmc` feature is enabled, but also only on platforms we support: // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. - if cfg!(all( - feature = "genmc", - target_os = "linux", - target_pointer_width = "64" - )) { + if cfg!(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")) { ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?; ui(Mode::Fail, "tests/genmc/fail", &target, WithDependencies, tmpdir.path())?; } From dea476313c06dc205f2e13080c446f3b63d88dfd Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 09:43:17 +0200 Subject: [PATCH 16/64] Disable cross-platform testing with GenMC. --- tests/ui.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ui.rs b/tests/ui.rs index c3b99a8349..c3cd047adc 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -340,7 +340,10 @@ fn main() -> Result<()> { // We only enable GenMC tests when the `genmc` feature is enabled, but also only on platforms we support: // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. - if cfg!(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")) { + // FIXME(genmc,cross-platform): remove `host == target` check once cross-platform support with GenMC is possible. + if cfg!(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")) + && host == target + { ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?; ui(Mode::Fail, "tests/genmc/fail", &target, WithDependencies, tmpdir.path())?; } From efdd05bcbd3e382b0b829e403546d502b6687737 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 10:19:37 +0200 Subject: [PATCH 17/64] Clean up GenMC config handling. --- src/bin/miri.rs | 31 ++++++++----------------------- src/concurrency/genmc/dummy.rs | 2 +- src/concurrency/genmc/mod.rs | 4 ++-- src/eval.rs | 6 +++--- src/machine.rs | 5 ++++- 5 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index a96915a6cc..1ec6a3fcd1 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -67,8 +67,6 @@ use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers}; struct MiriCompilerCalls { miri_config: Option, many_seeds: Option, - /// Settings for using GenMC with Miri. - genmc_config: Option, } struct ManySeedsConfig { @@ -77,12 +75,8 @@ struct ManySeedsConfig { } impl MiriCompilerCalls { - fn new( - miri_config: MiriConfig, - many_seeds: Option, - genmc_config: Option, - ) -> Self { - Self { miri_config: Some(miri_config), many_seeds, genmc_config } + fn new(miri_config: MiriConfig, many_seeds: Option) -> Self { + Self { miri_config: Some(miri_config), many_seeds } } } @@ -192,8 +186,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { optimizations is usually marginal at best."); } - if let Some(genmc_config) = &self.genmc_config { - let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config)); + if let Some(_genmc_config) = &config.genmc_config { + let _genmc_ctx = Rc::new(GenmcCtx::new(&config)); todo!("GenMC mode not yet implemented"); }; @@ -487,7 +481,6 @@ fn main() { let mut many_seeds_keep_going = false; let mut miri_config = MiriConfig::default(); miri_config.env = env_snapshot; - let mut genmc_config = None; let mut rustc_args = vec![]; let mut after_dashdash = false; @@ -603,13 +596,9 @@ fn main() { } else if arg == "-Zmiri-many-seeds-keep-going" { many_seeds_keep_going = true; } else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") { - if !miri_config.genmc_mode { - miri_config.genmc_mode = true; - // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. - miri_config.borrow_tracker = None; - } + // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. miri_config.borrow_tracker = None; - GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg); + GenmcConfig::parse_arg(&mut miri_config.genmc_config, trimmed_arg); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") { @@ -744,8 +733,7 @@ fn main() { many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going }); // Validate settings for data race detection and GenMC mode. - assert_eq!(genmc_config.is_some(), miri_config.genmc_mode); - if genmc_config.is_some() { + if miri_config.genmc_config.is_some() { if !miri_config.data_race_detector { fatal_error!("Cannot disable data race detection in GenMC mode (currently)"); } else if !miri_config.weak_memory_emulation { @@ -769,8 +757,5 @@ fn main() { ); } } - run_compiler_and_exit( - &rustc_args, - &mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config), - ) + run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds)) } diff --git a/src/concurrency/genmc/dummy.rs b/src/concurrency/genmc/dummy.rs index f32bbad4a4..dda7e2a7e9 100644 --- a/src/concurrency/genmc/dummy.rs +++ b/src/concurrency/genmc/dummy.rs @@ -16,7 +16,7 @@ pub struct GenmcCtx {} pub struct GenmcConfig {} impl GenmcCtx { - pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self { + pub fn new(_miri_config: &MiriConfig) -> Self { unreachable!() } diff --git a/src/concurrency/genmc/mod.rs b/src/concurrency/genmc/mod.rs index 988c808e30..3617775e27 100644 --- a/src/concurrency/genmc/mod.rs +++ b/src/concurrency/genmc/mod.rs @@ -25,8 +25,8 @@ pub struct GenmcCtx { impl GenmcCtx { /// Create a new `GenmcCtx` from a given config. - pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self { - assert!(miri_config.genmc_mode); + pub fn new(miri_config: &MiriConfig) -> Self { + let genmc_config = miri_config.genmc_config.as_ref().unwrap(); let handle = createGenmcHandle(&genmc_config.params); assert!(!handle.is_null()); diff --git a/src/eval.rs b/src/eval.rs index 3c80e60b77..8a20b7fab5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -125,8 +125,8 @@ pub struct MiriConfig { pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled. pub weak_memory_emulation: bool, - /// Determine if we are running in GenMC mode. In this mode, Miri will explore multiple concurrent executions of the given program. - pub genmc_mode: bool, + /// Determine if we are running in GenMC mode and with which settings. In GenMC mode, Miri will explore multiple concurrent executions of the given program. + pub genmc_config: Option, /// Track when an outdated (weak memory) load happens. pub track_outdated_loads: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, @@ -192,7 +192,7 @@ impl Default for MiriConfig { track_alloc_accesses: false, data_race_detector: true, weak_memory_emulation: true, - genmc_mode: false, + genmc_config: None, track_outdated_loads: false, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, diff --git a/src/machine.rs b/src/machine.rs index ce33c870b4..8b7a8a5865 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -622,6 +622,9 @@ pub struct MiriMachine<'tcx> { } impl<'tcx> MiriMachine<'tcx> { + /// Create a new MiriMachine. + /// + /// Invariant: `genmc_ctx.is_some() == config.genmc_config.is_some()` pub(crate) fn new( config: &MiriConfig, layout_cx: LayoutCx<'tcx>, @@ -645,7 +648,7 @@ impl<'tcx> MiriMachine<'tcx> { }); let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config)); - let data_race = if config.genmc_mode { + let data_race = if config.genmc_config.is_some() { // `genmc_ctx` persists across executions, so we don't create a new one here. GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap()) } else if config.data_race_detector { From 01a1b8d1322c4e0b36f37b80a3eb7fb47e2a1bfb Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 14:48:59 +0200 Subject: [PATCH 18/64] Set genmc-sys version to 0.1.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- genmc-sys/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c0e34515e..2d296f2f61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -526,7 +526,7 @@ dependencies = [ [[package]] name = "genmc-sys" -version = "0.11.0" +version = "0.1.0" dependencies = [ "cmake", "cxx", diff --git a/Cargo.toml b/Cargo.toml index 0a101d4c7f..e30fae12c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ capstone = { version = "0.13", optional = true } # FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. [target.'cfg(all(target_os = "linux", target_pointer_width = "64"))'.dependencies] -genmc-sys = { path = "./genmc-sys/", version = "0.11.0", optional = true } +genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true } [dev-dependencies] ui_test = "0.30.2" diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index a7841a71f2..5ebd733b77 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "genmc-sys" -version = "0.11.0" # NOTE: should match the GenMC version +version = "0.1.0" edition = "2024" [features] From 1456a3b5f9f9df19b9f0ef0c7ac7145790331314 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 15:21:24 +0200 Subject: [PATCH 19/64] Improve build script output --- genmc-sys/build.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index d18f8686e6..652a306305 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -70,13 +70,13 @@ mod downloading { match repo.find_remote("origin") { Ok(mut remote) => match remote.fetch(&[GENMC_COMMIT], None, None) { - Ok(_) => - println!( - "cargo::warning=Successfully fetched commit '{GENMC_COMMIT:?}'" - ), + Ok(_) => println!("Successfully fetched commit '{GENMC_COMMIT}'"), Err(e) => panic!("Failed to fetch from remote: {e}"), }, - Err(e) => println!("cargo::warning=Could not find remote 'origin': {e}"), + Err(e) => { + println!("cargo::error=GenMC repository at path '{GENMC_DOWNLOAD_PATH_STR}' does not contain commit '{GENMC_COMMIT}', and could not load commit from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); + std::process::exit(1); + } } let oid = Oid::from_str(GENMC_COMMIT).unwrap(); repo.find_commit(oid).unwrap() @@ -87,7 +87,7 @@ mod downloading { let head_commit = repo.head().unwrap().peel_to_commit().unwrap(); assert_eq!(head_commit.id(), commit.id()); - println!("cargo::warning=Successfully set checked out commit {head_commit:?}"); + println!("Successfully set checked out commit {head_commit:?}"); genmc_download_path } From c248528218fa959c6fc11ef5819f11d3f98cfae2 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 15:22:07 +0200 Subject: [PATCH 20/64] Remove '_STR' from string constants. --- genmc-sys/build.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 652a306305..fdd9290fdc 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; -const GENMC_LOCAL_PATH_STR: &str = "./genmc/"; +const GENMC_LOCAL_PATH: &str = "./genmc/"; /// Name of the library of the GenMC model checker. const GENMC_MODEL_CHECKER: &str = "model_checker"; @@ -18,14 +18,14 @@ mod downloading { use git2::{Oid, Repository}; - use super::GENMC_LOCAL_PATH_STR; + use super::GENMC_LOCAL_PATH; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; pub(crate) const GENMC_COMMIT: &str = "bd4496acaf0994b2515f58f75d21ad8dd15f6603"; - pub(crate) const GENMC_DOWNLOAD_PATH_STR: &str = "./downloaded/genmc/"; + pub(crate) const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; pub(crate) fn download_genmc() -> PathBuf { - let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH_STR); + let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); let repo = Repository::open(&genmc_download_path).unwrap_or_else(|open_err| { match Repository::clone(GENMC_GITHUB_URL, &genmc_download_path) { @@ -33,7 +33,7 @@ mod downloading { repo } Err(clone_err) => { - println!("cargo::error=Cannot open GenMC repo at path '{GENMC_LOCAL_PATH_STR}': {open_err:?}"); + println!("cargo::error=Cannot open GenMC repo at path '{GENMC_LOCAL_PATH}': {open_err:?}"); println!("cargo::error=Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {clone_err:?}"); std::process::exit(1); } @@ -43,7 +43,7 @@ mod downloading { let statuses = repo.statuses(None).expect("should be able to get repository status"); if !statuses.is_empty() { println!( - "cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH_STR}' has been modified" + "cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified" ); for entry in statuses.iter() { println!( @@ -56,7 +56,7 @@ mod downloading { "cargo::error=This repository should only be modified by the 'genmc-sys' build script to load a specific commit ('{GENMC_COMMIT}')" ); println!( - "cargo::error=HINT: For local development, place a GenMC repository in the path '{GENMC_LOCAL_PATH_STR}'" + "cargo::error=HINT: For local development, place a GenMC repository in the path '{GENMC_LOCAL_PATH}'" ); std::process::exit(1); } @@ -74,7 +74,7 @@ mod downloading { Err(e) => panic!("Failed to fetch from remote: {e}"), }, Err(e) => { - println!("cargo::error=GenMC repository at path '{GENMC_DOWNLOAD_PATH_STR}' does not contain commit '{GENMC_COMMIT}', and could not load commit from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); + println!("cargo::error=GenMC repository at path '{GENMC_DOWNLOAD_PATH}' does not contain commit '{GENMC_COMMIT}', and could not load commit from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); std::process::exit(1); } } @@ -174,13 +174,13 @@ fn build_genmc_model_checker(genmc_path: &Path) { fn main() { // Select between local GenMC repo, or downloading GenMC from a specific commit. - let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH_STR); + let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH); let genmc_path = if genmc_local_path.exists() { genmc_local_path } else { #[cfg(not(feature = "download_genmc"))] panic!( - "GenMC not found in path '{GENMC_LOCAL_PATH_STR}', and downloading GenMC is disabled." + "GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." ); #[cfg(feature = "download_genmc")] @@ -196,5 +196,5 @@ fn main() { // Adding that path here would also trigger an unnecessary rebuild after the repo is cloned (since cargo detects that as a file modification). println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); println!("cargo::rerun-if-changed=./src_cpp"); - println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH_STR}"); + println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH}"); } From f4ed42b2a55dca3739fbf9bf1a8b075146cb64dd Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sun, 13 Jul 2025 12:46:36 +0200 Subject: [PATCH 21/64] Rework GenMC git repo handling --- genmc-sys/build.rs | 179 +++++++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 71 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index fdd9290fdc..dd65312320 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -1,6 +1,9 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; +/// Path used for development of Miri-GenMC. +/// A GenMC repository in this directory will take precedence over the downloaded GenMC repository. +/// If the `download` feature is disabled, this path must contain a GenMC repository. const GENMC_LOCAL_PATH: &str = "./genmc/"; /// Name of the library of the GenMC model checker. @@ -11,14 +14,20 @@ const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; // FIXME(GenMC, build): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB) const ENABLE_GENMC_DEBUG: bool = true; +fn fatal_error() -> ! { + println!("cargo::error="); + println!("cargo::error=HINT: For more information on GenMC, check out 'doc/GenMC.md'"); + std::process::exit(1) +} + #[cfg(feature = "download_genmc")] mod downloading { - use std::path::PathBuf; + use std::path::{Path, PathBuf}; use std::str::FromStr; - use git2::{Oid, Repository}; + use git2::{Commit, Oid, Repository, StatusOptions}; - use super::GENMC_LOCAL_PATH; + use super::{GENMC_LOCAL_PATH, fatal_error}; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; pub(crate) const GENMC_COMMIT: &str = "bd4496acaf0994b2515f58f75d21ad8dd15f6603"; @@ -26,84 +35,113 @@ mod downloading { pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); + let commit_oid = Oid::from_str(GENMC_COMMIT).expect("Commit should be valid."); - let repo = Repository::open(&genmc_download_path).unwrap_or_else(|open_err| { - match Repository::clone(GENMC_GITHUB_URL, &genmc_download_path) { - Ok(repo) => { - repo - } - Err(clone_err) => { - println!("cargo::error=Cannot open GenMC repo at path '{GENMC_LOCAL_PATH}': {open_err:?}"); - println!("cargo::error=Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {clone_err:?}"); - std::process::exit(1); - } + match Repository::open(&genmc_download_path) { + Ok(repo) => { + assert_repo_unmodified(&repo); + let commit = update_local_repo(&repo, commit_oid); + checkout_commit(&repo, &commit); } - }); - - let statuses = repo.statuses(None).expect("should be able to get repository status"); - if !statuses.is_empty() { - println!( - "cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified" - ); - for entry in statuses.iter() { - println!( - "cargo::error= {} is {:?}", - entry.path().unwrap_or("unknown"), - entry.status() - ); + Err(_) => { + let repo = clone_remote_repo(&genmc_download_path); + let Ok(commit) = repo.find_commit(commit_oid) else { + println!( + "cargo::error=Cloned GenMC repository does not contain required commit '{GENMC_COMMIT}'" + ); + fatal_error(); + }; + checkout_commit(&repo, &commit); } - println!( - "cargo::error=This repository should only be modified by the 'genmc-sys' build script to load a specific commit ('{GENMC_COMMIT}')" - ); - println!( - "cargo::error=HINT: For local development, place a GenMC repository in the path '{GENMC_LOCAL_PATH}'" - ); - std::process::exit(1); - } + }; - // Check if there are any updates: - let commit = if let Ok(oid) = Oid::from_str(GENMC_COMMIT) - && let Ok(commit) = repo.find_commit(oid) - { - commit - } else { + genmc_download_path + } + + // Check if the required commit exists already, otherwise try fetching it. + fn update_local_repo(repo: &Repository, commit_oid: Oid) -> Commit<'_> { + repo.find_commit(commit_oid).unwrap_or_else(|_find_error| { + println!("GenMC repository at path '{GENMC_DOWNLOAD_PATH}' does not contain commit '{GENMC_COMMIT}'."); match repo.find_remote("origin") { Ok(mut remote) => - match remote.fetch(&[GENMC_COMMIT], None, None) { - Ok(_) => println!("Successfully fetched commit '{GENMC_COMMIT}'"), - Err(e) => panic!("Failed to fetch from remote: {e}"), - }, + remote.fetch(&[GENMC_COMMIT], None, None).unwrap_or_else(|e| { + println!("cargo::error=Failed to fetch from remote: {e}"); + fatal_error(); + }), Err(e) => { - println!("cargo::error=GenMC repository at path '{GENMC_DOWNLOAD_PATH}' does not contain commit '{GENMC_COMMIT}', and could not load commit from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); - std::process::exit(1); + println!("cargo::error=could not load commit from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); + fatal_error(); } } - let oid = Oid::from_str(GENMC_COMMIT).unwrap(); - repo.find_commit(oid).unwrap() - }; - - // Set the repo to the correct branch: - checkout_commit(&repo, GENMC_COMMIT); + repo.find_commit(commit_oid) + .expect("Remote repository should contain expected commit") + }) + } - let head_commit = repo.head().unwrap().peel_to_commit().unwrap(); - assert_eq!(head_commit.id(), commit.id()); - println!("Successfully set checked out commit {head_commit:?}"); + fn clone_remote_repo(genmc_download_path: &PathBuf) -> Repository { + Repository::clone(GENMC_GITHUB_URL, &genmc_download_path).unwrap_or_else(|e| { + println!("cargo::error=Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {e:?}"); + fatal_error(); + }) + } - genmc_download_path + /// Set the state of the repo to a specific commit + fn checkout_commit(repo: &Repository, commit: &Commit<'_>) { + repo.checkout_tree(commit.as_object(), None).expect("Failed to checkout"); + repo.set_head_detached(commit.id()).expect("Failed to set HEAD"); + println!("Successfully set checked out commit {commit:?}"); } - fn checkout_commit(repo: &Repository, refname: &str) { - let (object, reference) = repo.revparse_ext(refname).expect("Object not found"); + /// Check that the downloaded repository is unmodified. + /// If it is modified, explain that it shouldn't be, and hint at how to do local development with GenMC. + /// We don't overwrite any changes made to the directory, to prevent data loss. + fn assert_repo_unmodified(repo: &Repository) { + let statuses = repo + .statuses(Some( + StatusOptions::new() + .include_untracked(true) + .include_ignored(false) + .include_unmodified(false), + )) + .expect("should be able to get repository status"); + if statuses.is_empty() { + return; + } - repo.checkout_tree(&object, None).expect("Failed to checkout"); + /// Printing too many files makes reading the error message difficult, so we limit the number. + const PRINT_LIMIT: usize = 8; - match reference { - // `gref` is an actual reference like branches or tags. - Some(gref) => repo.set_head(gref.name().unwrap()), - // This is a commit, not a reference. - None => repo.set_head_detached(object.id()), + println!(); + println!( + "cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified:" + ); + for entry in statuses.iter().take(PRINT_LIMIT) { + println!( + "cargo::error= {} is {:?}", + entry.path().unwrap_or("unknown"), + entry.status() + ); + } + if statuses.len() > PRINT_LIMIT { + println!("cargo::error= ..."); + println!("cargo::error= [ Total {} modified files ]", statuses.len()); } - .expect("Failed to set HEAD"); + + println!("cargo::error="); + println!( + "cargo::error=This repository should only be modified by the 'genmc-sys' build script." + ); + println!( + "cargo::error=Please undo any changes made, or delete the '{GENMC_DOWNLOAD_PATH}' directory to have it downloaded again." + ); + + println!("cargo::error="); + let local_path = Path::new(GENMC_LOCAL_PATH); + println!( + "cargo::error=HINT: For local development, place a GenMC repository in the path {:?}.", + std::path::absolute(local_path).unwrap_or_else(|_| local_path.into()) + ); + fatal_error(); } } @@ -177,14 +215,13 @@ fn main() { let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH); let genmc_path = if genmc_local_path.exists() { genmc_local_path + } else if cfg!(feature = "download_genmc") { + downloading::download_genmc() } else { - #[cfg(not(feature = "download_genmc"))] - panic!( - "GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." + println!( + "cargo::error=GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." ); - - #[cfg(feature = "download_genmc")] - downloading::download_genmc() + fatal_error(); }; // Build all required components: From dcac07b718080c2b3a8daaa6b80844b081b264f2 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sun, 13 Jul 2025 23:02:31 +0200 Subject: [PATCH 22/64] Switch to using configuration file for GenMC instead of compile definitions. --- genmc-sys/build.rs | 54 ++++++++++++++--------------- genmc-sys/src_cpp/MiriInterface.hpp | 2 ++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index dd65312320..141151fdc3 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -9,10 +9,16 @@ const GENMC_LOCAL_PATH: &str = "./genmc/"; /// Name of the library of the GenMC model checker. const GENMC_MODEL_CHECKER: &str = "model_checker"; +/// Path where the `cxx_bridge!` macro is used to define the Rust-C++ interface. const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; -// FIXME(GenMC, build): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB) +// FIXME(GenMC, build): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB). +// FIXME(GenMC, build): decide on which profile to use. + +/// Enable/disable additional debug checks, prints and options for GenMC. const ENABLE_GENMC_DEBUG: bool = true; +/// The profile with which to build GenMC. +const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; fn fatal_error() -> ! { println!("cargo::error="); @@ -30,7 +36,7 @@ mod downloading { use super::{GENMC_LOCAL_PATH, fatal_error}; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; - pub(crate) const GENMC_COMMIT: &str = "bd4496acaf0994b2515f58f75d21ad8dd15f6603"; + pub(crate) const GENMC_COMMIT: &str = "31c4d3d280c724c497d4b4563d8ea99849f1c52b"; pub(crate) const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; pub(crate) fn download_genmc() -> PathBuf { @@ -146,36 +152,24 @@ mod downloading { } /// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(genmc_path: &Path) { +fn build_cxx_bridge(genmc_path: &Path, cmake_build_path: &Path) { // Paths for include directories: let model_checker_include_path = genmc_path.join(GENMC_MODEL_CHECKER).join("include"); let genmc_common_include_path = genmc_path.join("common").join("include"); - let mut bridge = cxx_build::bridge("src/lib.rs"); - - // FIXME(GenMC, build): make sure GenMC uses the same compiler / settings as the cxx_bridge // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? - bridge + cxx_build::bridge("src/lib.rs") .opt_level(2) .debug(true) // Same settings that GenMC uses ("-O2 -g") .warnings(false) // NOTE: enabling this produces a lot of warnings. .std("c++20") - .include(genmc_common_include_path) - .include(model_checker_include_path) + .include(genmc_common_include_path) // Required for including GenMC helper files. + .include(model_checker_include_path) // Required for including GenMC model checker files. + .include(cmake_build_path) // Required for including `config.h`. .include("./src_cpp") - .define("PACKAGE_BUGREPORT", "\"FIXME(GenMC) determine what to do with this!!\"") // FIXME(GenMC): HACK to get stuff to compile (this is normally defined by cmake) .file("./src_cpp/MiriInterface.hpp") - .file("./src_cpp/MiriInterface.cpp"); - - // NOTE: It is very important to ensure that this and similar flags are set/unset both here and - // for the cmake build below, otherwise, certain structs/classes can have different - // sizes and field offsets in the cxx bridge library compared to the model_checker library. - // This will lead to data corruption in these fields, which can be hard to debug (fields change values randomly). - if ENABLE_GENMC_DEBUG { - bridge.define("ENABLE_GENMC_DEBUG", "1"); - } - - bridge.compile("genmc_interop"); + .file("./src_cpp/MiriInterface.cpp") + .compile("genmc_interop"); // Link the Rust-C++ interface library generated by cxx_build: println!("cargo::rustc-link-lib=static=genmc_interop"); @@ -183,11 +177,11 @@ fn build_cxx_bridge(genmc_path: &Path) { /// Build the GenMC model checker library. /// Returns the path -fn build_genmc_model_checker(genmc_path: &Path) { +fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { let cmakelists_path = genmc_path.join("CMakeLists.txt"); let mut config = cmake::Config::new(cmakelists_path); - config.profile("RelWithDebInfo"); // FIXME(GenMC,cmake): decide on profile to use + config.profile(GENMC_CMAKE_PROFILE); if ENABLE_GENMC_DEBUG { config.define("GENMC_DEBUG", "ON"); } @@ -196,7 +190,8 @@ fn build_genmc_model_checker(genmc_path: &Path) { // Without this, the files are written into the source directory by the cmake configure step, and then // the build step cannot find these files, because it correctly tries using the `target` directory. let out_dir = std::env::var("OUT_DIR").unwrap(); - config.configure_arg(format!("-B {out_dir}/build")); + let genmc_build_path: PathBuf = [&out_dir, "build"].into_iter().collect(); + config.configure_arg(format!("-B {}", genmc_build_path.display())); // Enable only the components of GenMC that we need: config.define("BUILD_LLI", "OFF"); @@ -204,10 +199,13 @@ fn build_genmc_model_checker(genmc_path: &Path) { config.define("BUILD_MODEL_CHECKER", "ON"); config.build_target(GENMC_MODEL_CHECKER); - let dst = config.build(); + let _dst = config.build(); - println!("cargo::rustc-link-search=native={}/build/{GENMC_MODEL_CHECKER}", dst.display()); + let genmc_model_checker_build_directory = genmc_build_path.join(GENMC_MODEL_CHECKER); + println!("cargo::rustc-link-search=native={}", genmc_model_checker_build_directory.display()); println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); + + genmc_build_path } fn main() { @@ -225,8 +223,8 @@ fn main() { }; // Build all required components: - build_cxx_bridge(&genmc_path); - build_genmc_model_checker(&genmc_path); + let genmc_build_path = build_genmc_model_checker(&genmc_path); + build_cxx_bridge(&genmc_path, &genmc_build_path); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. diff --git a/genmc-sys/src_cpp/MiriInterface.hpp b/genmc-sys/src_cpp/MiriInterface.hpp index 9d07182ac3..2591abb128 100644 --- a/genmc-sys/src_cpp/MiriInterface.hpp +++ b/genmc-sys/src_cpp/MiriInterface.hpp @@ -3,6 +3,8 @@ #include "rust/cxx.h" +#include "config.h" + #include "Verification/GenMCDriver.hpp" #include "Verification/VerificationConfig.hpp" From 2d065b32c8e25fb038afb95eebf0fe1478a2fd41 Mon Sep 17 00:00:00 2001 From: Patrick-6 <93388547+Patrick-6@users.noreply.github.com> Date: Sun, 13 Jul 2025 23:04:19 +0200 Subject: [PATCH 23/64] Apply suggestions from code review Co-authored-by: Ralf Jung --- Cargo.toml | 2 +- src/concurrency/genmc/dummy.rs | 2 +- src/concurrency/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e30fae12c4..42bbe14c49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = ipc-channel = { version = "0.20.0", optional = true } capstone = { version = "0.13", optional = true } -# FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. +# FIXME(genmc,macos): Add `target_os = "macos"` once https://github.com/dtolnay/cxx/issues/1535 is fixed. [target.'cfg(all(target_os = "linux", target_pointer_width = "64"))'.dependencies] genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true } diff --git a/src/concurrency/genmc/dummy.rs b/src/concurrency/genmc/dummy.rs index dda7e2a7e9..ef1e5cfd3c 100644 --- a/src/concurrency/genmc/dummy.rs +++ b/src/concurrency/genmc/dummy.rs @@ -234,7 +234,7 @@ impl GenmcConfig { target_pointer_width = "64" )) { unimplemented!( - "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" + "GenMC is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" ); } else { unimplemented!( diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index 637e555b90..2a0398c864 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -8,7 +8,7 @@ mod vector_clock; pub mod weak_memory; // Import either the real genmc adapter or a dummy module. -// On unsupported platforms, we still include the dummy module, even if the `genmc` feature is enabled. +// On unsupported platforms, we always include the dummy module, even if the `genmc` feature is enabled. // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. #[cfg_attr( not(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")), From ba6bbca9c2b8ded1f99bae8013e350cbfb5eeac9 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 14:49:24 +0200 Subject: [PATCH 24/64] Improve include directory handling with cmake --- genmc-sys/build.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 141151fdc3..dc99e42d4e 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -36,7 +36,7 @@ mod downloading { use super::{GENMC_LOCAL_PATH, fatal_error}; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; - pub(crate) const GENMC_COMMIT: &str = "31c4d3d280c724c497d4b4563d8ea99849f1c52b"; + pub(crate) const GENMC_COMMIT: &str = "2f503036ae14dc91746bfc292d142f332f31727e"; pub(crate) const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; pub(crate) fn download_genmc() -> PathBuf { @@ -152,7 +152,7 @@ mod downloading { } /// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(genmc_path: &Path, cmake_build_path: &Path) { +fn build_cxx_bridge(genmc_path: &Path, genmc_install_dir: &Path) { // Paths for include directories: let model_checker_include_path = genmc_path.join(GENMC_MODEL_CHECKER).join("include"); let genmc_common_include_path = genmc_path.join("common").join("include"); @@ -165,7 +165,7 @@ fn build_cxx_bridge(genmc_path: &Path, cmake_build_path: &Path) { .std("c++20") .include(genmc_common_include_path) // Required for including GenMC helper files. .include(model_checker_include_path) // Required for including GenMC model checker files. - .include(cmake_build_path) // Required for including `config.h`. + .include(genmc_install_dir) // Required for including `config.h`. .include("./src_cpp") .file("./src_cpp/MiriInterface.hpp") .file("./src_cpp/MiriInterface.cpp") @@ -176,7 +176,7 @@ fn build_cxx_bridge(genmc_path: &Path, cmake_build_path: &Path) { } /// Build the GenMC model checker library. -/// Returns the path +/// Returns the path where cmake installs the model checker library and the config.h file. fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { let cmakelists_path = genmc_path.join("CMakeLists.txt"); @@ -198,14 +198,13 @@ fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { config.define("BUILD_INSTRUMENTATION", "OFF"); config.define("BUILD_MODEL_CHECKER", "ON"); - config.build_target(GENMC_MODEL_CHECKER); - let _dst = config.build(); + let cmake_install_dir = config.build(); - let genmc_model_checker_build_directory = genmc_build_path.join(GENMC_MODEL_CHECKER); - println!("cargo::rustc-link-search=native={}", genmc_model_checker_build_directory.display()); + // Add the model checker library to be linked and the install directory where it is located: + println!("cargo::rustc-link-search=native={}", cmake_install_dir.display()); println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); - genmc_build_path + cmake_install_dir } fn main() { @@ -223,8 +222,8 @@ fn main() { }; // Build all required components: - let genmc_build_path = build_genmc_model_checker(&genmc_path); - build_cxx_bridge(&genmc_path, &genmc_build_path); + let genmc_install_dir = build_genmc_model_checker(&genmc_path); + build_cxx_bridge(&genmc_path, &genmc_install_dir); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. From c2eafc21d7c7991261a0eb63aa72b0ba2f290e8c Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 14:51:51 +0200 Subject: [PATCH 25/64] Remove 'doc/' from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index ed2d0ba7ba..4a238dc031 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ target -/doc tex/*/out *.dot *.out From 173c8b4a8de55518df5c7c06e543fdc87465fb6b Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 14:53:53 +0200 Subject: [PATCH 26/64] Add little endian to supported platform conditions, add extra FIXME for checking supported targets. --- Cargo.toml | 2 +- src/bin/miri.rs | 1 + src/concurrency/genmc/config.rs | 11 +++++++++++ src/concurrency/genmc/dummy.rs | 4 +++- src/concurrency/mod.rs | 7 ++++++- tests/ui.rs | 8 ++++++-- 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 42bbe14c49..5afde9b23d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ ipc-channel = { version = "0.20.0", optional = true } capstone = { version = "0.13", optional = true } # FIXME(genmc,macos): Add `target_os = "macos"` once https://github.com/dtolnay/cxx/issues/1535 is fixed. -[target.'cfg(all(target_os = "linux", target_pointer_width = "64"))'.dependencies] +[target.'cfg(all(target_os = "linux", target_pointer_width = "64", target_endian = "little"))'.dependencies] genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true } [dev-dependencies] diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1ec6a3fcd1..0b81317421 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -734,6 +734,7 @@ fn main() { // Validate settings for data race detection and GenMC mode. if miri_config.genmc_config.is_some() { + // FIXME(genmc): Add checks for currently supported platforms (64bit, target == host) if !miri_config.data_race_detector { fatal_error!("Cannot disable data race detection in GenMC mode (currently)"); } else if !miri_config.weak_memory_emulation { diff --git a/src/concurrency/genmc/config.rs b/src/concurrency/genmc/config.rs index 767bcbfcaf..42591c9ac2 100644 --- a/src/concurrency/genmc/config.rs +++ b/src/concurrency/genmc/config.rs @@ -18,6 +18,17 @@ impl GenmcConfig { /// /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed. pub fn parse_arg(genmc_config: &mut Option, trimmed_arg: &str) { + // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. + if !cfg!(all( + feature = "genmc", + any(target_os = "linux", target_os = "macos"), + target_pointer_width = "64", + target_endian = "little" + )) { + unimplemented!( + "GenMC mode is not supported on this platform, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" + ); + } if genmc_config.is_none() { *genmc_config = Some(Default::default()); } diff --git a/src/concurrency/genmc/dummy.rs b/src/concurrency/genmc/dummy.rs index ef1e5cfd3c..7570f8ba36 100644 --- a/src/concurrency/genmc/dummy.rs +++ b/src/concurrency/genmc/dummy.rs @@ -228,10 +228,12 @@ impl VisitProvenance for GenmcCtx { impl GenmcConfig { pub fn parse_arg(_genmc_config: &mut Option, trimmed_arg: &str) { + // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. if cfg!(all( feature = "genmc", any(target_os = "linux", target_os = "macos"), - target_pointer_width = "64" + target_pointer_width = "64", + target_endian = "little" )) { unimplemented!( "GenMC is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index 2a0398c864..435615efd9 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -11,7 +11,12 @@ pub mod weak_memory; // On unsupported platforms, we always include the dummy module, even if the `genmc` feature is enabled. // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. #[cfg_attr( - not(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")), + not(all( + feature = "genmc", + target_os = "linux", + target_pointer_width = "64", + target_endian = "little" + )), path = "genmc/dummy.rs" )] mod genmc; diff --git a/tests/ui.rs b/tests/ui.rs index c3cd047adc..73fbe2cc02 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -341,8 +341,12 @@ fn main() -> Result<()> { // We only enable GenMC tests when the `genmc` feature is enabled, but also only on platforms we support: // FIXME(genmc,macos): Add `target_os = "macos"` once `https://github.com/dtolnay/cxx/issues/1535` is fixed. // FIXME(genmc,cross-platform): remove `host == target` check once cross-platform support with GenMC is possible. - if cfg!(all(feature = "genmc", target_os = "linux", target_pointer_width = "64")) - && host == target + if cfg!(all( + feature = "genmc", + target_os = "linux", + target_pointer_width = "64", + target_endian = "little" + )) && host == target { ui(Mode::Pass, "tests/genmc/pass", &target, WithDependencies, tmpdir.path())?; ui(Mode::Fail, "tests/genmc/fail", &target, WithDependencies, tmpdir.path())?; From 2851d22881871cd3fd45e435142b61a7d47c9ac4 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 15:35:27 +0200 Subject: [PATCH 27/64] Switch to using panic! for error handling in build script --- genmc-sys/build.rs | 65 +++++++++++----------------------------------- 1 file changed, 15 insertions(+), 50 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index dc99e42d4e..8859673e54 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -1,6 +1,9 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; +// Build script for running Miri with GenMC. +// Check out doc/GenMC.md for more info. + /// Path used for development of Miri-GenMC. /// A GenMC repository in this directory will take precedence over the downloaded GenMC repository. /// If the `download` feature is disabled, this path must contain a GenMC repository. @@ -20,12 +23,6 @@ const ENABLE_GENMC_DEBUG: bool = true; /// The profile with which to build GenMC. const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; -fn fatal_error() -> ! { - println!("cargo::error="); - println!("cargo::error=HINT: For more information on GenMC, check out 'doc/GenMC.md'"); - std::process::exit(1) -} - #[cfg(feature = "download_genmc")] mod downloading { use std::path::{Path, PathBuf}; @@ -33,7 +30,7 @@ mod downloading { use git2::{Commit, Oid, Repository, StatusOptions}; - use super::{GENMC_LOCAL_PATH, fatal_error}; + use super::GENMC_LOCAL_PATH; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; pub(crate) const GENMC_COMMIT: &str = "2f503036ae14dc91746bfc292d142f332f31727e"; @@ -52,10 +49,9 @@ mod downloading { Err(_) => { let repo = clone_remote_repo(&genmc_download_path); let Ok(commit) = repo.find_commit(commit_oid) else { - println!( - "cargo::error=Cloned GenMC repository does not contain required commit '{GENMC_COMMIT}'" + panic!( + "Cloned GenMC repository does not contain required commit '{GENMC_COMMIT}'" ); - fatal_error(); }; checkout_commit(&repo, &commit); } @@ -68,15 +64,12 @@ mod downloading { fn update_local_repo(repo: &Repository, commit_oid: Oid) -> Commit<'_> { repo.find_commit(commit_oid).unwrap_or_else(|_find_error| { println!("GenMC repository at path '{GENMC_DOWNLOAD_PATH}' does not contain commit '{GENMC_COMMIT}'."); + // The commit is not in the checkout. Try `git fetch` and hope that we find the commit then. match repo.find_remote("origin") { Ok(mut remote) => - remote.fetch(&[GENMC_COMMIT], None, None).unwrap_or_else(|e| { - println!("cargo::error=Failed to fetch from remote: {e}"); - fatal_error(); - }), + remote.fetch(&[GENMC_COMMIT], None, None).expect("Failed to fetch from remote."), Err(e) => { - println!("cargo::error=could not load commit from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); - fatal_error(); + panic!("Could not load commit ({GENMC_COMMIT}) from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); } } repo.find_commit(commit_oid) @@ -86,8 +79,7 @@ mod downloading { fn clone_remote_repo(genmc_download_path: &PathBuf) -> Repository { Repository::clone(GENMC_GITHUB_URL, &genmc_download_path).unwrap_or_else(|e| { - println!("cargo::error=Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {e:?}"); - fatal_error(); + panic!("Cannot clone GenMC repo from '{GENMC_GITHUB_URL}': {e:?}"); }) } @@ -114,40 +106,14 @@ mod downloading { return; } - /// Printing too many files makes reading the error message difficult, so we limit the number. - const PRINT_LIMIT: usize = 8; - - println!(); - println!( - "cargo::error=Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified:" - ); - for entry in statuses.iter().take(PRINT_LIMIT) { - println!( - "cargo::error= {} is {:?}", - entry.path().unwrap_or("unknown"), - entry.status() - ); - } - if statuses.len() > PRINT_LIMIT { - println!("cargo::error= ..."); - println!("cargo::error= [ Total {} modified files ]", statuses.len()); - } - - println!("cargo::error="); - println!( - "cargo::error=This repository should only be modified by the 'genmc-sys' build script." - ); - println!( - "cargo::error=Please undo any changes made, or delete the '{GENMC_DOWNLOAD_PATH}' directory to have it downloaded again." - ); - - println!("cargo::error="); let local_path = Path::new(GENMC_LOCAL_PATH); println!( - "cargo::error=HINT: For local development, place a GenMC repository in the path {:?}.", + "HINT: For local development, place a GenMC repository in the path {:?}.", std::path::absolute(local_path).unwrap_or_else(|_| local_path.into()) ); - fatal_error(); + panic!( + "Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified. Please undo any changes made, or delete the '{GENMC_DOWNLOAD_PATH}' directory to have it downloaded again." + ); } } @@ -215,10 +181,9 @@ fn main() { } else if cfg!(feature = "download_genmc") { downloading::download_genmc() } else { - println!( + panic!( "cargo::error=GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." ); - fatal_error(); }; // Build all required components: From 57250afd4656f6a02f64905dbb1431595c900740 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 15:39:11 +0200 Subject: [PATCH 28/64] Only check local GenMC repo path for changes if it exists --- genmc-sys/build.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 8859673e54..93b9ce6bfe 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -177,6 +177,11 @@ fn main() { // Select between local GenMC repo, or downloading GenMC from a specific commit. let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH); let genmc_path = if genmc_local_path.exists() { + // If the local repository exists, cargo should watch it for changes: + // FIXME(genmc,cargo): We could always watch this path even if it doesn't (yet) exist, depending on how `https://github.com/rust-lang/cargo/issues/6003` is resolved. + // Adding it here means we don't rebuild if a user creates `GENMC_LOCAL_PATH`, which isn't ideal. + // Cargo currently always rebuilds if a watched directory doesn't exist, so we can only add it if it exists. + println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH}"); genmc_local_path } else if cfg!(feature = "download_genmc") { downloading::download_genmc() @@ -195,5 +200,4 @@ fn main() { // Adding that path here would also trigger an unnecessary rebuild after the repo is cloned (since cargo detects that as a file modification). println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); println!("cargo::rerun-if-changed=./src_cpp"); - println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH}"); } From b2760679e5d060dd8a9f8eefe999d97267f43128 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 16:31:00 +0200 Subject: [PATCH 29/64] Remove extra string in print. --- genmc-sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 93b9ce6bfe..25e2e5c52b 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -187,7 +187,7 @@ fn main() { downloading::download_genmc() } else { panic!( - "cargo::error=GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." + "GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." ); }; From 4eaec536a600bac3225012ab7aaa33a34b3531fc Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 21:36:29 +0200 Subject: [PATCH 30/64] Add warning for enabled borrow tracking in GenMC mode --- src/bin/miri.rs | 10 ++++++++-- tests/genmc/pass/test_cxx_build.stderr | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0b81317421..11d17994cc 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -596,8 +596,6 @@ fn main() { } else if arg == "-Zmiri-many-seeds-keep-going" { many_seeds_keep_going = true; } else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") { - // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. - miri_config.borrow_tracker = None; GenmcConfig::parse_arg(&mut miri_config.genmc_config, trimmed_arg); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); @@ -740,6 +738,14 @@ fn main() { } else if !miri_config.weak_memory_emulation { fatal_error!("Cannot disable weak memory emulation in GenMC mode"); } + // FIXME(genmc): Remove once GenMC mode is compatible with borrow tracking: + if miri_config.borrow_tracker.is_some() { + eprintln!( + "warning: Borrow tracking has been disabled, it is not (yet) supported in GenMC mode." + ); + eprintln!(); + miri_config.borrow_tracker = None; + } } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector { fatal_error!( "Weak memory emulation cannot be enabled when the data race detector is disabled" diff --git a/tests/genmc/pass/test_cxx_build.stderr b/tests/genmc/pass/test_cxx_build.stderr index 26cc892215..3773dbeff3 100644 --- a/tests/genmc/pass/test_cxx_build.stderr +++ b/tests/genmc/pass/test_cxx_build.stderr @@ -1,3 +1,5 @@ +warning: Borrow tracking has been disabled, it is not (yet) supported in GenMC mode. + C++: GenMC handle created! Miri: GenMC handle creation successful! C++: GenMC handle destroyed! From 73e01d479dade7950085811428577587f790b1bb Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 21:52:12 +0200 Subject: [PATCH 31/64] WIP: Add documentation for GenMC mode usage and development. --- doc/GenMC.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 doc/GenMC.md diff --git a/doc/GenMC.md b/doc/GenMC.md new file mode 100644 index 0000000000..2ecaa01620 --- /dev/null +++ b/doc/GenMC.md @@ -0,0 +1,42 @@ +# **(WIP)** Documentation for Miri-GenMC +[GenMC](https://github.com/MPI-SWS/genmc) is a stateless model checker for exploring concurrent executions of a program. + +**NOTE: Currently, no actual GenMC functionality is part of Miri, this is still WIP.** + + + +## Usage +Basic usage: +```shell +MIRIFLAGS="-Zmiri-genmc" cargo miri run +``` + + + + + +## Tips + + + +## Limitations + +Some or all of these limitations might get removed in the future: + +- Borrow tracking is currently incompatible (stacked/tree borrows). +- Only Linux is supported for now. +- No 32-bit platform support. +- No cross-platform interpretation. + + + +## Development + +GenMC is written in C++, which complicates development a bit. +For Rust-C++ interop, Miri uses [CXX.rs](https://cxx.rs/), and all handling of C++ code is contained in the `genmc-sys` crate (located in the Miri repository root directory: `miri/genmc-sys/`). + +The actual code for GenMC is not contained in the Miri repo itself, but in a [separate GenMC repo](https://github.com/MPI-SWS/genmc) (with different maintainers). +Note that this repo is just a mirror repo. + + + From 7d6e79e163a5ae7e4b2e44c750e940a2bfb257ff Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 21:53:52 +0200 Subject: [PATCH 32/64] Run fmt. --- genmc-sys/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 25e2e5c52b..17c854673c 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -186,9 +186,7 @@ fn main() { } else if cfg!(feature = "download_genmc") { downloading::download_genmc() } else { - panic!( - "GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled." - ); + panic!("GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled."); }; // Build all required components: From 0362d47bc65b9426ca97a1fbcdef06ed0f6c6d12 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 10:35:03 +0200 Subject: [PATCH 33/64] Make file name lowercase --- doc/{GenMC.md => genmc.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/{GenMC.md => genmc.md} (100%) diff --git a/doc/GenMC.md b/doc/genmc.md similarity index 100% rename from doc/GenMC.md rename to doc/genmc.md From cd0bb79b8b21a3318e71ee14587c2e05e538f2d1 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 14:20:59 +0200 Subject: [PATCH 34/64] Switch to minimally changed GenMC repo (with LLVM dependency not yet removed) --- genmc-sys/build.rs | 63 +++++++++++++++++++++-------- genmc-sys/src_cpp/MiriInterface.cpp | 39 +++++++++--------- genmc-sys/src_cpp/MiriInterface.hpp | 6 +-- 3 files changed, 69 insertions(+), 39 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 17c854673c..7720d81b51 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -10,7 +10,7 @@ use std::str::FromStr; const GENMC_LOCAL_PATH: &str = "./genmc/"; /// Name of the library of the GenMC model checker. -const GENMC_MODEL_CHECKER: &str = "model_checker"; +const GENMC_MODEL_CHECKER: &str = "genmc_lib"; /// Path where the `cxx_bridge!` macro is used to define the Rust-C++ interface. const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; @@ -33,7 +33,7 @@ mod downloading { use super::GENMC_LOCAL_PATH; pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; - pub(crate) const GENMC_COMMIT: &str = "2f503036ae14dc91746bfc292d142f332f31727e"; + pub(crate) const GENMC_COMMIT: &str = "a3c6cbb3b0be78fbd1edbfe7e4ec76e5003b2e96"; pub(crate) const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; pub(crate) fn download_genmc() -> PathBuf { @@ -117,11 +117,36 @@ mod downloading { } } +// FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. +/// The linked LLVM version is in the generated `config.h`` file, which we parse and use to link to LLVM. +fn link_to_llvm(config_file: &Path) { + let file_content = std::fs::read_to_string(&config_file).unwrap_or_else(|err| { + panic!("GenMC config file ({}) should exist, but got errror {err:?}", config_file.display()) + }); + // Look for line '#define LLVM_VERSION "X.Y.Z"' + let llvm_version = file_content + .lines() + .find_map(|line| { + if let Some(suffix) = line.strip_prefix("#define LLVM_VERSION") + && let Some(version_str) = suffix.split('"').nth(1) + && let Some(major) = version_str.split('.').next() + { + // FIXME(genmc,debugging): remove warning print + println!( + "cargo::warning=Found llvm version {version_str}" + ); + return Some(major); + } + None + }) + .expect("Config file should contain LLVM version"); + + println!("cargo::rustc-link-lib=dylib=LLVM-{llvm_version}"); +} + /// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(genmc_path: &Path, genmc_install_dir: &Path) { - // Paths for include directories: - let model_checker_include_path = genmc_path.join(GENMC_MODEL_CHECKER).join("include"); - let genmc_common_include_path = genmc_path.join("common").join("include"); +fn build_cxx_bridge(genmc_install_dir: &Path) { + let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? cxx_build::bridge("src/lib.rs") @@ -129,9 +154,7 @@ fn build_cxx_bridge(genmc_path: &Path, genmc_install_dir: &Path) { .debug(true) // Same settings that GenMC uses ("-O2 -g") .warnings(false) // NOTE: enabling this produces a lot of warnings. .std("c++20") - .include(genmc_common_include_path) // Required for including GenMC helper files. - .include(model_checker_include_path) // Required for including GenMC model checker files. - .include(genmc_install_dir) // Required for including `config.h`. + .include(genmc_include_dir) .include("./src_cpp") .file("./src_cpp/MiriInterface.hpp") .file("./src_cpp/MiriInterface.cpp") @@ -159,18 +182,24 @@ fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { let genmc_build_path: PathBuf = [&out_dir, "build"].into_iter().collect(); config.configure_arg(format!("-B {}", genmc_build_path.display())); - // Enable only the components of GenMC that we need: - config.define("BUILD_LLI", "OFF"); - config.define("BUILD_INSTRUMENTATION", "OFF"); + // Enable and install the components of GenMC that we need: + config.define("BUILD_LLI", "OFF"); // No need to build the GenMC executable. config.define("BUILD_MODEL_CHECKER", "ON"); + config.define("INSTALL_MODEL_CHECKER", "ON"); - let cmake_install_dir = config.build(); + let genmc_install_dir = config.build(); - // Add the model checker library to be linked and the install directory where it is located: - println!("cargo::rustc-link-search=native={}", cmake_install_dir.display()); + // Add the model checker library to be linked and tell GenMC where to find it: + let cmake_lib_dir = genmc_install_dir.join("lib").join("genmc"); + println!("cargo::warning=lib dir: {}", cmake_lib_dir.display()); + println!("cargo::rustc-link-search=native={}", cmake_lib_dir.display()); println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); - cmake_install_dir + // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. + let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); + link_to_llvm(&config_file); + + genmc_install_dir } fn main() { @@ -191,7 +220,7 @@ fn main() { // Build all required components: let genmc_install_dir = build_genmc_model_checker(&genmc_path); - build_cxx_bridge(&genmc_path, &genmc_install_dir); + build_cxx_bridge(&genmc_install_dir); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. diff --git a/genmc-sys/src_cpp/MiriInterface.cpp b/genmc-sys/src_cpp/MiriInterface.cpp index e740d496c1..0827bb3d40 100644 --- a/genmc-sys/src_cpp/MiriInterface.cpp +++ b/genmc-sys/src_cpp/MiriInterface.cpp @@ -5,45 +5,46 @@ auto MiriGenMCShim::createHandle(const GenmcParams &config) -> std::unique_ptr { - auto vConf = std::make_shared(); + auto conf = std::make_shared(); // Miri needs all threads to be replayed, even fully completed ones. - vConf->replayCompletedThreads = true; + conf->replayCompletedThreads = true; // We only support the RC11 memory model for Rust. - vConf->model = ModelType::RC11; + conf->model = ModelType::RC11; - vConf->printRandomScheduleSeed = config.print_random_schedule_seed; + conf->printRandomScheduleSeed = config.print_random_schedule_seed; - // FIXME(GenMC): disable any options we don't support currently: - vConf->ipr = false; - vConf->disableBAM = true; - vConf->instructionCaching = false; + // FIXME(genmc): disable any options we don't support currently: + conf->ipr = false; + conf->disableBAM = true; + conf->instructionCaching = false; ERROR_ON(config.do_symmetry_reduction, "Symmetry reduction is currently unsupported in GenMC mode."); - vConf->symmetryReduction = config.do_symmetry_reduction; + conf->symmetryReduction = config.do_symmetry_reduction; - // FIXME(GenMC): Should there be a way to change this option from Miri? - vConf->schedulePolicy = SchedulePolicy::WF; + // FIXME(genmc): Should there be a way to change this option from Miri? + conf->schedulePolicy = SchedulePolicy::WF; - // FIXME(GenMC): implement estimation mode: - vConf->estimate = false; - vConf->estimationMax = 1000; - const auto mode = vConf->estimate ? GenMCDriver::Mode(GenMCDriver::EstimationMode{}) + // FIXME(genmc): implement estimation mode: + conf->estimate = false; + conf->estimationMax = 1000; + const auto mode = conf->estimate ? GenMCDriver::Mode(GenMCDriver::EstimationMode{}) : GenMCDriver::Mode(GenMCDriver::VerificationMode{}); // Running Miri-GenMC without race detection is not supported. // Disabling this option also changes the behavior of the replay scheduler to only schedule at atomic operations, which is required with Miri. // This happens because Miri can generate multiple GenMC events for a single MIR terminator. Without this option, // the scheduler might incorrectly schedule an atomic MIR terminator because the first event it creates is a non-atomic (e.g., `StorageLive`). - vConf->disableRaceDetection = false; + conf->disableRaceDetection = false; // Miri can already check for unfreed memory. Also, GenMC cannot distinguish between memory // that is allowed to leak and memory that is not. - vConf->warnUnfreedMemory = false; + conf->warnUnfreedMemory = false; - checkVerificationConfigOptions(*vConf); + // FIXME(genmc): check config: + // checkConfigOptions(*conf); - auto driver = std::make_unique(std::move(vConf), mode); + auto driver = std::make_unique(std::move(conf), mode); return driver; } diff --git a/genmc-sys/src_cpp/MiriInterface.hpp b/genmc-sys/src_cpp/MiriInterface.hpp index 2591abb128..e55522ef41 100644 --- a/genmc-sys/src_cpp/MiriInterface.hpp +++ b/genmc-sys/src_cpp/MiriInterface.hpp @@ -5,8 +5,8 @@ #include "config.h" +#include "Config/Config.hpp" #include "Verification/GenMCDriver.hpp" -#include "Verification/VerificationConfig.hpp" #include @@ -19,8 +19,8 @@ struct MiriGenMCShim : private GenMCDriver { public: - MiriGenMCShim(std::shared_ptr vConf, Mode mode /* = VerificationMode{} */) - : GenMCDriver(std::move(vConf), nullptr, mode) + MiriGenMCShim(std::shared_ptr conf, Mode mode /* = VerificationMode{} */) + : GenMCDriver(std::move(conf), nullptr, mode) { std::cerr << "C++: GenMC handle created!" << std::endl; } From d3eee66891965024e5df146719ad7397e4aa5d56 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 14:21:38 +0200 Subject: [PATCH 35/64] Remove hack for building on older version of Ubuntu. --- genmc-sys/build.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 7720d81b51..a4cc361086 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -175,13 +175,6 @@ fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { config.define("GENMC_DEBUG", "ON"); } - // FIXME(GenMC,HACK): Required for unknown reasons on older cmake (version 3.22.1, works without this with version 3.31.6) - // Without this, the files are written into the source directory by the cmake configure step, and then - // the build step cannot find these files, because it correctly tries using the `target` directory. - let out_dir = std::env::var("OUT_DIR").unwrap(); - let genmc_build_path: PathBuf = [&out_dir, "build"].into_iter().collect(); - config.configure_arg(format!("-B {}", genmc_build_path.display())); - // Enable and install the components of GenMC that we need: config.define("BUILD_LLI", "OFF"); // No need to build the GenMC executable. config.define("BUILD_MODEL_CHECKER", "ON"); From 6c0665113e2887341e5fc25370b8dcb2df8dc12f Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 14:35:36 +0200 Subject: [PATCH 36/64] Enable GenMC debugging based on Rust compilation profile. --- genmc-sys/build.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index a4cc361086..620a112380 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -15,14 +15,6 @@ const GENMC_MODEL_CHECKER: &str = "genmc_lib"; /// Path where the `cxx_bridge!` macro is used to define the Rust-C++ interface. const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; -// FIXME(GenMC, build): decide whether to keep debug enabled or not (without this: calling BUG() ==> UB). -// FIXME(GenMC, build): decide on which profile to use. - -/// Enable/disable additional debug checks, prints and options for GenMC. -const ENABLE_GENMC_DEBUG: bool = true; -/// The profile with which to build GenMC. -const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; - #[cfg(feature = "download_genmc")] mod downloading { use std::path::{Path, PathBuf}; @@ -132,9 +124,7 @@ fn link_to_llvm(config_file: &Path) { && let Some(major) = version_str.split('.').next() { // FIXME(genmc,debugging): remove warning print - println!( - "cargo::warning=Found llvm version {version_str}" - ); + println!("cargo::warning=Found llvm version {version_str}"); return Some(major); } None @@ -167,13 +157,19 @@ fn build_cxx_bridge(genmc_install_dir: &Path) { /// Build the GenMC model checker library. /// Returns the path where cmake installs the model checker library and the config.h file. fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { + /// The profile with which to build GenMC. + const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; + + // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release) + let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); + // FIXME(genmc,debugging): remove warning print + println!("cargo::warning=GENMC_DEBUG = {enable_genmc_debug}"); + let cmakelists_path = genmc_path.join("CMakeLists.txt"); let mut config = cmake::Config::new(cmakelists_path); config.profile(GENMC_CMAKE_PROFILE); - if ENABLE_GENMC_DEBUG { - config.define("GENMC_DEBUG", "ON"); - } + config.define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" }); // Enable and install the components of GenMC that we need: config.define("BUILD_LLI", "OFF"); // No need to build the GenMC executable. @@ -184,6 +180,7 @@ fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { // Add the model checker library to be linked and tell GenMC where to find it: let cmake_lib_dir = genmc_install_dir.join("lib").join("genmc"); + // FIXME(genmc,debugging): remove warning print println!("cargo::warning=lib dir: {}", cmake_lib_dir.display()); println!("cargo::rustc-link-search=native={}", cmake_lib_dir.display()); println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); From 03976802a073153fb61df7166626ba8d71612118 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 17:49:31 +0200 Subject: [PATCH 37/64] Improve doc comments. --- genmc-sys/build.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 620a112380..114d841b80 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -5,7 +5,7 @@ use std::str::FromStr; // Check out doc/GenMC.md for more info. /// Path used for development of Miri-GenMC. -/// A GenMC repository in this directory will take precedence over the downloaded GenMC repository. +/// A GenMC repository in this directory (relative to the `genmc-sys` directory) will take precedence over the downloaded GenMC repository. /// If the `download` feature is disabled, this path must contain a GenMC repository. const GENMC_LOCAL_PATH: &str = "./genmc/"; @@ -24,8 +24,12 @@ mod downloading { use super::GENMC_LOCAL_PATH; + /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; + /// The GenMC commit we depend on. It must be available on the specified GenMC repository. pub(crate) const GENMC_COMMIT: &str = "a3c6cbb3b0be78fbd1edbfe7e4ec76e5003b2e96"; + /// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory). + /// Note that this directory is *not* cleaned up automatically by `cargo clean`. pub(crate) const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; pub(crate) fn download_genmc() -> PathBuf { From 90d9b760e74c00c8692fc9e9d3f64708469b43ee Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 20:27:37 +0200 Subject: [PATCH 38/64] Add GENMC_SRC_PATH env var for overriding which GenMC repo is used by Miri --- genmc-sys/build.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 114d841b80..2274c7dac9 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -9,6 +9,11 @@ use std::str::FromStr; /// If the `download` feature is disabled, this path must contain a GenMC repository. const GENMC_LOCAL_PATH: &str = "./genmc/"; +/// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory). +/// Note that this directory is *not* cleaned up automatically by `cargo clean`. +#[cfg(feature = "download_genmc")] +const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; + /// Name of the library of the GenMC model checker. const GENMC_MODEL_CHECKER: &str = "genmc_lib"; @@ -22,15 +27,12 @@ mod downloading { use git2::{Commit, Oid, Repository, StatusOptions}; - use super::GENMC_LOCAL_PATH; + use super::{GENMC_LOCAL_PATH, GENMC_DOWNLOAD_PATH}; /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. pub(crate) const GENMC_COMMIT: &str = "a3c6cbb3b0be78fbd1edbfe7e4ec76e5003b2e96"; - /// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory). - /// Note that this directory is *not* cleaned up automatically by `cargo clean`. - pub(crate) const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); @@ -197,9 +199,18 @@ fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { } fn main() { - // Select between local GenMC repo, or downloading GenMC from a specific commit. + // Select which path to use for the GenMC repo: let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH); - let genmc_path = if genmc_local_path.exists() { + let genmc_path = if let Ok(genmc_src_path) = std::env::var("GENMC_SRC_PATH") { + let genmc_src_path = + PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path"); + assert!( + genmc_src_path.exists(), + "GENMC_SRC_PATH ({}) does not exist!", + genmc_src_path.display() + ); + genmc_src_path + } else if genmc_local_path.exists() { // If the local repository exists, cargo should watch it for changes: // FIXME(genmc,cargo): We could always watch this path even if it doesn't (yet) exist, depending on how `https://github.com/rust-lang/cargo/issues/6003` is resolved. // Adding it here means we don't rebuild if a user creates `GENMC_LOCAL_PATH`, which isn't ideal. From da80f0fc78be7158797c4c582aaba7f8fd2fc973 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 20:28:18 +0200 Subject: [PATCH 39/64] Improve documentation for building GenMC. --- doc/genmc.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/genmc.md b/doc/genmc.md index 2ecaa01620..5a083e3d7f 100644 --- a/doc/genmc.md +++ b/doc/genmc.md @@ -35,8 +35,27 @@ Some or all of these limitations might get removed in the future: GenMC is written in C++, which complicates development a bit. For Rust-C++ interop, Miri uses [CXX.rs](https://cxx.rs/), and all handling of C++ code is contained in the `genmc-sys` crate (located in the Miri repository root directory: `miri/genmc-sys/`). +Building GenMC requires a compiler with C++23 support. + +Currently, building GenMC also requires linking to LLVM, which needs to be installed manually. + The actual code for GenMC is not contained in the Miri repo itself, but in a [separate GenMC repo](https://github.com/MPI-SWS/genmc) (with different maintainers). Note that this repo is just a mirror repo. + +### Building the GenMC Library +The build script in the `genmc-sys` crate handles locating, downloading, building and linking the GenMC library. + +To determine which GenMC repo path will be used, the following steps are taken: +- If the env var `GENMC_SRC_PATH` contains a path to a directory with a GenMC repo, use that path. +- If the path `genmc-sys/genmc` exists, use that path. +- If the path `genmc-sys/downloaded/genmc` exists, try to set the GenMC repo there to the commit we need. +- If the downloaded repo doesn't exist or is missing the commit, the build script will fetch the commit over the network. + - Note that the build script will *not* access the network if any of the steps previous steps succeeds. + +Once we get the path to the repo, the compilation proceeds in two steps: +- Compile GenMC into a library (using cmake). +- Compile the cxx.rs bridge to connect the library to the Rust code. +The first step is where all build settings are made, the relevant ones are then stored in a `config.h` file that can be included in the second compilation step. From e18a86444a584e02090f02aa57cffb5f4b1114ed Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 19 Jul 2025 21:00:26 +0200 Subject: [PATCH 40/64] Run fmt --- genmc-sys/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 2274c7dac9..988cff37e1 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -27,7 +27,7 @@ mod downloading { use git2::{Commit, Oid, Repository, StatusOptions}; - use super::{GENMC_LOCAL_PATH, GENMC_DOWNLOAD_PATH}; + use super::{GENMC_DOWNLOAD_PATH, GENMC_LOCAL_PATH}; /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; From 1e251121a5f51f2d533315d5f7e8fb86c0029251 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sun, 20 Jul 2025 11:29:32 +0200 Subject: [PATCH 41/64] Add llvm compiler definitions to cxx_build step --- genmc-sys/build.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 988cff37e1..9a6d7664a8 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -117,7 +117,8 @@ mod downloading { // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. /// The linked LLVM version is in the generated `config.h`` file, which we parse and use to link to LLVM. -fn link_to_llvm(config_file: &Path) { +/// Returns c++ flags required for building with/including LLVM. +fn link_to_llvm(config_file: &Path) -> String { let file_content = std::fs::read_to_string(&config_file).unwrap_or_else(|err| { panic!("GenMC config file ({}) should exist, but got errror {err:?}", config_file.display()) }); @@ -138,14 +139,32 @@ fn link_to_llvm(config_file: &Path) { .expect("Config file should contain LLVM version"); println!("cargo::rustc-link-lib=dylib=LLVM-{llvm_version}"); + + // Get required compile flags for LLVM. + let llvm_config = format!("llvm-config-{}", llvm_version); + let output = std::process::Command::new(&llvm_config) + .arg("--cppflags") + .output() + .expect("Failed to run llvm-config"); + if !output.status.success() { + panic!("llvm-config command failed: {}", String::from_utf8_lossy(&output.stderr)); + } + let cpp_flags = String::from_utf8(output.stdout) + .expect("llvm-config output should be valid UTF-8") + .trim() + .to_string(); + + println!("cargo::warning=LLVM cpp_flags: '{cpp_flags}'"); + cpp_flags } /// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(genmc_install_dir: &Path) { +fn build_cxx_bridge(genmc_install_dir: &Path, llvm_cpp_flags: &str) { let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? cxx_build::bridge("src/lib.rs") + .flag(llvm_cpp_flags) // FIXME(genmc,llvm): remove once LLVM dependency is removed. .opt_level(2) .debug(true) // Same settings that GenMC uses ("-O2 -g") .warnings(false) // NOTE: enabling this produces a lot of warnings. @@ -162,7 +181,8 @@ fn build_cxx_bridge(genmc_install_dir: &Path) { /// Build the GenMC model checker library. /// Returns the path where cmake installs the model checker library and the config.h file. -fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { +/// FIXME(genmc,llvm): Also returns the cpp_flags required to compile with LLVM (remove once LLVM dependency is removed). +fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String) { /// The profile with which to build GenMC. const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; @@ -193,9 +213,9 @@ fn build_genmc_model_checker(genmc_path: &Path) -> PathBuf { // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); - link_to_llvm(&config_file); + let llvm_cpp_flags = link_to_llvm(&config_file); - genmc_install_dir + (genmc_install_dir, llvm_cpp_flags) } fn main() { @@ -224,8 +244,8 @@ fn main() { }; // Build all required components: - let genmc_install_dir = build_genmc_model_checker(&genmc_path); - build_cxx_bridge(&genmc_install_dir); + let (genmc_install_dir, llvm_cpp_flags) = build_genmc_model_checker(&genmc_path); + build_cxx_bridge(&genmc_install_dir, &llvm_cpp_flags); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. From b45676d2eedd3e4ff44ab44663b7a66336ef3a99 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sun, 20 Jul 2025 12:02:04 +0200 Subject: [PATCH 42/64] Split up c++ flags --- genmc-sys/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 9a6d7664a8..f45a10ae0d 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -162,9 +162,12 @@ fn link_to_llvm(config_file: &Path) -> String { fn build_cxx_bridge(genmc_install_dir: &Path, llvm_cpp_flags: &str) { let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); + // FIXME(genmc,debugging): remove this: + println!("cargo::warning=cpp_flags: {:?}", llvm_cpp_flags.split(" ").collect::>()); + // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? cxx_build::bridge("src/lib.rs") - .flag(llvm_cpp_flags) // FIXME(genmc,llvm): remove once LLVM dependency is removed. + .flags(llvm_cpp_flags.split(" ")) // FIXME(genmc,llvm): remove once LLVM dependency is removed. .opt_level(2) .debug(true) // Same settings that GenMC uses ("-O2 -g") .warnings(false) // NOTE: enabling this produces a lot of warnings. From e119755030ab01b5d008c1ee52536d6a32b2b812 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 21 Jul 2025 16:24:47 +0200 Subject: [PATCH 43/64] Improve building/linking with LLVM by passing required info in configure file. --- genmc-sys/build.rs | 94 +++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index f45a10ae0d..81f19548dd 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -32,7 +32,7 @@ mod downloading { /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. - pub(crate) const GENMC_COMMIT: &str = "a3c6cbb3b0be78fbd1edbfe7e4ec76e5003b2e96"; + pub(crate) const GENMC_COMMIT: &str = "128310845621cfe9e1807e344f103da40cd5226e"; pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); @@ -117,62 +117,72 @@ mod downloading { // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. /// The linked LLVM version is in the generated `config.h`` file, which we parse and use to link to LLVM. -/// Returns c++ flags required for building with/including LLVM. -fn link_to_llvm(config_file: &Path) -> String { - let file_content = std::fs::read_to_string(&config_file).unwrap_or_else(|err| { - panic!("GenMC config file ({}) should exist, but got errror {err:?}", config_file.display()) - }); - // Look for line '#define LLVM_VERSION "X.Y.Z"' - let llvm_version = file_content - .lines() - .find_map(|line| { - if let Some(suffix) = line.strip_prefix("#define LLVM_VERSION") - && let Some(version_str) = suffix.split('"').nth(1) - && let Some(major) = version_str.split('.').next() +/// Returns c++ compiler definitions required for building with/including LLVM, and the include path for LLVM headers. +fn link_to_llvm(config_file: &Path) -> (String, String) { + /// Search a string for a line matching `//@VARIABLE_NAME: VARIABLE CONTENT` + fn extract_value<'a>(input: &'a str, name: &str) -> Option<&'a str> { + input.lines().find_map(|line| { + if let Some(suffix) = line.strip_prefix("//@") + && let Some(suffix) = suffix.strip_prefix(name) + && let Some(suffix) = suffix.strip_prefix(": ") { // FIXME(genmc,debugging): remove warning print - println!("cargo::warning=Found llvm version {version_str}"); - return Some(major); + println!("cargo::warning=Found value '{name}': '{suffix}'"); + return Some(suffix); } None }) - .expect("Config file should contain LLVM version"); - - println!("cargo::rustc-link-lib=dylib=LLVM-{llvm_version}"); - - // Get required compile flags for LLVM. - let llvm_config = format!("llvm-config-{}", llvm_version); - let output = std::process::Command::new(&llvm_config) - .arg("--cppflags") - .output() - .expect("Failed to run llvm-config"); - if !output.status.success() { - panic!("llvm-config command failed: {}", String::from_utf8_lossy(&output.stderr)); } - let cpp_flags = String::from_utf8(output.stdout) - .expect("llvm-config output should be valid UTF-8") - .trim() - .to_string(); - println!("cargo::warning=LLVM cpp_flags: '{cpp_flags}'"); - cpp_flags + let file_content = std::fs::read_to_string(&config_file).unwrap_or_else(|err| { + panic!("GenMC config file ({}) should exist, but got errror {err:?}", config_file.display()) + }); + + let llvm_definitions = extract_value(&file_content, "LLVM_DEFINITIONS") + .expect("Config file should contain LLVM_DEFINITIONS"); + let llvm_include_dirs = extract_value(&file_content, "LLVM_INCLUDE_DIRS") + .expect("Config file should contain LLVM_INCLUDE_DIRS"); + let llvm_library_dirs = extract_value(&file_content, "LLVM_LIBRARY_DIRS") + .expect("Config file should contain LLVM_LIBRARY_DIRS"); + let llvm_link_libs = extract_value(&file_content, "LLVM_LINK_LIBS") + .expect("Config file should contain LLVM_LINK_LIBS"); + + // FIXME(genmc,debugging): remove warning print + println!("cargo::warning=Search path for linking: '{llvm_library_dirs}'"); + let lib_dir = PathBuf::from_str(llvm_library_dirs).unwrap(); + println!("cargo::rustc-link-search=native={}", lib_dir.display()); + + for link_lib in llvm_link_libs.split(" ") { + // FIXME(genmc,debugging): remove warning print + println!("cargo::warning=Linking with '{link_lib}'"); + let link_lib = link_lib.strip_prefix("-l").unwrap(); + println!("cargo::rustc-link-lib=dylib={link_lib}"); + } + + (llvm_definitions.to_string(), llvm_include_dirs.to_string()) } /// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(genmc_install_dir: &Path, llvm_cpp_flags: &str) { +fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_include_dirs: &str) { let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); // FIXME(genmc,debugging): remove this: - println!("cargo::warning=cpp_flags: {:?}", llvm_cpp_flags.split(" ").collect::>()); + // println!("cargo::warning=llvm_definitions: {:?}", llvm_definitions.split(" ").collect::>()); + println!("cargo::warning=llvm_definitions: '{llvm_definitions}'"); + + // FIXME(genmc,llvm): remove once LLVM dependency is removed. + // HACK: We filter out _GNU_SOURCE, since it is already set and produces a warning if set again. + let definitions = llvm_definitions.split(";").filter(|definition| definition != &"-D_GNU_SOURCE"); // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? cxx_build::bridge("src/lib.rs") - .flags(llvm_cpp_flags.split(" ")) // FIXME(genmc,llvm): remove once LLVM dependency is removed. + .flags(definitions) .opt_level(2) .debug(true) // Same settings that GenMC uses ("-O2 -g") .warnings(false) // NOTE: enabling this produces a lot of warnings. .std("c++20") .include(genmc_include_dir) + .include(llvm_include_dirs) .include("./src_cpp") .file("./src_cpp/MiriInterface.hpp") .file("./src_cpp/MiriInterface.cpp") @@ -184,8 +194,8 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_cpp_flags: &str) { /// Build the GenMC model checker library. /// Returns the path where cmake installs the model checker library and the config.h file. -/// FIXME(genmc,llvm): Also returns the cpp_flags required to compile with LLVM (remove once LLVM dependency is removed). -fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String) { +/// FIXME(genmc,llvm): Also returns the c++ compiler definitions required for building with/including LLVM, and the include path for LLVM headers. (remove once LLVM dependency is removed). +fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String, String) { /// The profile with which to build GenMC. const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; @@ -216,9 +226,9 @@ fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String) { // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); - let llvm_cpp_flags = link_to_llvm(&config_file); + let (llvm_definitions, llvm_include_dirs) = link_to_llvm(&config_file); - (genmc_install_dir, llvm_cpp_flags) + (genmc_install_dir, llvm_definitions, llvm_include_dirs) } fn main() { @@ -247,8 +257,8 @@ fn main() { }; // Build all required components: - let (genmc_install_dir, llvm_cpp_flags) = build_genmc_model_checker(&genmc_path); - build_cxx_bridge(&genmc_install_dir, &llvm_cpp_flags); + let (genmc_install_dir, llvm_definitions, llvm_include_dirs) = build_genmc_model_checker(&genmc_path); + build_cxx_bridge(&genmc_install_dir, &llvm_definitions, &llvm_include_dirs); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. From 9908f075180ad4862c26ee14faf66b8029eb1d7d Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 21 Jul 2025 16:25:29 +0200 Subject: [PATCH 44/64] Run fmt --- genmc-sys/build.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 81f19548dd..4646fb67bc 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -172,7 +172,8 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_inclu // FIXME(genmc,llvm): remove once LLVM dependency is removed. // HACK: We filter out _GNU_SOURCE, since it is already set and produces a warning if set again. - let definitions = llvm_definitions.split(";").filter(|definition| definition != &"-D_GNU_SOURCE"); + let definitions = + llvm_definitions.split(";").filter(|definition| definition != &"-D_GNU_SOURCE"); // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? cxx_build::bridge("src/lib.rs") @@ -257,7 +258,8 @@ fn main() { }; // Build all required components: - let (genmc_install_dir, llvm_definitions, llvm_include_dirs) = build_genmc_model_checker(&genmc_path); + let (genmc_install_dir, llvm_definitions, llvm_include_dirs) = + build_genmc_model_checker(&genmc_path); build_cxx_bridge(&genmc_install_dir, &llvm_definitions, &llvm_include_dirs); // Only rebuild if anything changes: From fd8d97320c20aa7f71610b30b938db3a1775f65c Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 22 Jul 2025 10:24:27 +0200 Subject: [PATCH 45/64] Clean up LLVM linking by using llvm-config --- genmc-sys/build.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 4646fb67bc..20b7c00140 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -32,7 +32,7 @@ mod downloading { /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. - pub(crate) const GENMC_COMMIT: &str = "128310845621cfe9e1807e344f103da40cd5226e"; + pub(crate) const GENMC_COMMIT: &str = "f8d41c7d8c7d88e47f71ef6bd7914041a2691aab"; pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); @@ -142,20 +142,28 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { .expect("Config file should contain LLVM_DEFINITIONS"); let llvm_include_dirs = extract_value(&file_content, "LLVM_INCLUDE_DIRS") .expect("Config file should contain LLVM_INCLUDE_DIRS"); - let llvm_library_dirs = extract_value(&file_content, "LLVM_LIBRARY_DIRS") - .expect("Config file should contain LLVM_LIBRARY_DIRS"); - let llvm_link_libs = extract_value(&file_content, "LLVM_LINK_LIBS") - .expect("Config file should contain LLVM_LINK_LIBS"); + let llvm_library_dir = extract_value(&file_content, "LLVM_LIBRARY_DIR") + .expect("Config file should contain LLVM_LIBRARY_DIR"); + let llvm_config_path = extract_value(&file_content, "LLVM_CONFIG_PATH") + .expect("Config file should contain LLVM_CONFIG_PATH"); - // FIXME(genmc,debugging): remove warning print - println!("cargo::warning=Search path for linking: '{llvm_library_dirs}'"); - let lib_dir = PathBuf::from_str(llvm_library_dirs).unwrap(); + // Add linker search path. + let lib_dir = PathBuf::from_str(llvm_library_dir).unwrap(); println!("cargo::rustc-link-search=native={}", lib_dir.display()); - for link_lib in llvm_link_libs.split(" ") { + // Add libraries to link. + let output = std::process::Command::new(llvm_config_path) + .arg("--libs") // Print the libraries to link to (space-separated list) + .output() + .expect("failed to execute llvm-config"); + let llvm_link_libs = + String::try_from(output.stdout).expect("llvm-config output should be a valid string"); + + for link_lib in llvm_link_libs.trim().split(" ") { // FIXME(genmc,debugging): remove warning print println!("cargo::warning=Linking with '{link_lib}'"); - let link_lib = link_lib.strip_prefix("-l").unwrap(); + let link_lib = + link_lib.strip_prefix("-l").expect("Linker parameter should start with \"-l\""); println!("cargo::rustc-link-lib=dylib={link_lib}"); } From 7d3d3a25d596ae195f753714a323b2f6b33fa291 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 22 Jul 2025 11:04:03 +0200 Subject: [PATCH 46/64] Remove debug prints, minor cleanup. --- genmc-sys/build.rs | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 20b7c00140..6c4d9b6d2c 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -20,6 +20,9 @@ const GENMC_MODEL_CHECKER: &str = "genmc_lib"; /// Path where the `cxx_bridge!` macro is used to define the Rust-C++ interface. const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; +/// The profile with which to build GenMC. +const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; + #[cfg(feature = "download_genmc")] mod downloading { use std::path::{Path, PathBuf}; @@ -121,17 +124,9 @@ mod downloading { fn link_to_llvm(config_file: &Path) -> (String, String) { /// Search a string for a line matching `//@VARIABLE_NAME: VARIABLE CONTENT` fn extract_value<'a>(input: &'a str, name: &str) -> Option<&'a str> { - input.lines().find_map(|line| { - if let Some(suffix) = line.strip_prefix("//@") - && let Some(suffix) = suffix.strip_prefix(name) - && let Some(suffix) = suffix.strip_prefix(": ") - { - // FIXME(genmc,debugging): remove warning print - println!("cargo::warning=Found value '{name}': '{suffix}'"); - return Some(suffix); - } - None - }) + input + .lines() + .find_map(|line| line.strip_prefix("//@")?.strip_prefix(name)?.strip_prefix(": ")) } let file_content = std::fs::read_to_string(&config_file).unwrap_or_else(|err| { @@ -160,8 +155,6 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { String::try_from(output.stdout).expect("llvm-config output should be a valid string"); for link_lib in llvm_link_libs.trim().split(" ") { - // FIXME(genmc,debugging): remove warning print - println!("cargo::warning=Linking with '{link_lib}'"); let link_lib = link_lib.strip_prefix("-l").expect("Linker parameter should start with \"-l\""); println!("cargo::rustc-link-lib=dylib={link_lib}"); @@ -174,10 +167,6 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_include_dirs: &str) { let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); - // FIXME(genmc,debugging): remove this: - // println!("cargo::warning=llvm_definitions: {:?}", llvm_definitions.split(" ").collect::>()); - println!("cargo::warning=llvm_definitions: '{llvm_definitions}'"); - // FIXME(genmc,llvm): remove once LLVM dependency is removed. // HACK: We filter out _GNU_SOURCE, since it is already set and produces a warning if set again. let definitions = @@ -187,7 +176,7 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_inclu cxx_build::bridge("src/lib.rs") .flags(definitions) .opt_level(2) - .debug(true) // Same settings that GenMC uses ("-O2 -g") + .debug(true) // Same settings that GenMC uses (default for cmake `RelWithDebInfo`) .warnings(false) // NOTE: enabling this produces a lot of warnings. .std("c++20") .include(genmc_include_dir) @@ -205,13 +194,9 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_inclu /// Returns the path where cmake installs the model checker library and the config.h file. /// FIXME(genmc,llvm): Also returns the c++ compiler definitions required for building with/including LLVM, and the include path for LLVM headers. (remove once LLVM dependency is removed). fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String, String) { - /// The profile with which to build GenMC. - const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; - + // FIXME(genmc,cargo): Switch to using `CARGO_CFG_DEBUG_ASSERTIONS` once https://github.com/rust-lang/cargo/issues/15760 is completed. // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release) let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); - // FIXME(genmc,debugging): remove warning print - println!("cargo::warning=GENMC_DEBUG = {enable_genmc_debug}"); let cmakelists_path = genmc_path.join("CMakeLists.txt"); @@ -228,8 +213,6 @@ fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String, String) { // Add the model checker library to be linked and tell GenMC where to find it: let cmake_lib_dir = genmc_install_dir.join("lib").join("genmc"); - // FIXME(genmc,debugging): remove warning print - println!("cargo::warning=lib dir: {}", cmake_lib_dir.display()); println!("cargo::rustc-link-search=native={}", cmake_lib_dir.display()); println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); From da61f52c6902d30cdaf0913245efe2b7f90a3d00 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 22 Jul 2025 11:04:52 +0200 Subject: [PATCH 47/64] Switch cxx build step to C++23. --- genmc-sys/build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 6c4d9b6d2c..f7a06fdf8e 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -172,13 +172,12 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_inclu let definitions = llvm_definitions.split(";").filter(|definition| definition != &"-D_GNU_SOURCE"); - // FIXME(GenMC, build): can we use c++23? Does CXX support that? Does rustc CI support that? cxx_build::bridge("src/lib.rs") .flags(definitions) .opt_level(2) .debug(true) // Same settings that GenMC uses (default for cmake `RelWithDebInfo`) .warnings(false) // NOTE: enabling this produces a lot of warnings. - .std("c++20") + .std("c++23") .include(genmc_include_dir) .include(llvm_include_dirs) .include("./src_cpp") From 245b31c5573122a0205d84faa37de404ba5954ef Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 23 Jul 2025 14:40:55 +0200 Subject: [PATCH 48/64] Permanently enable downloading of GenMC (i.e, remove downloading feature) --- genmc-sys/Cargo.toml | 7 +------ genmc-sys/build.rs | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index 5ebd733b77..f6d98c695c 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -3,15 +3,10 @@ name = "genmc-sys" version = "0.1.0" edition = "2024" -[features] -default = ["download_genmc"] -# If downloading is disabled, a local GenMC repo must be available in the "./genmc" path. -download_genmc = ["dep:git2"] - [dependencies] cxx = { version = "1.0.160", features = ["c++20"] } [build-dependencies] cmake = "0.1.54" -git2 = { version = "0.20.2", optional = true, default-features = false, features = ["https"] } +git2 = { version = "0.20.2", default-features = false, features = ["https"] } cxx-build = { version = "1.0.160", features = ["parallel"] } diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index f7a06fdf8e..aa4e2d2bd9 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -6,12 +6,10 @@ use std::str::FromStr; /// Path used for development of Miri-GenMC. /// A GenMC repository in this directory (relative to the `genmc-sys` directory) will take precedence over the downloaded GenMC repository. -/// If the `download` feature is disabled, this path must contain a GenMC repository. const GENMC_LOCAL_PATH: &str = "./genmc/"; /// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory). /// Note that this directory is *not* cleaned up automatically by `cargo clean`. -#[cfg(feature = "download_genmc")] const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; /// Name of the library of the GenMC model checker. @@ -23,7 +21,6 @@ const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; /// The profile with which to build GenMC. const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; -#[cfg(feature = "download_genmc")] mod downloading { use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -241,10 +238,8 @@ fn main() { // Cargo currently always rebuilds if a watched directory doesn't exist, so we can only add it if it exists. println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH}"); genmc_local_path - } else if cfg!(feature = "download_genmc") { - downloading::download_genmc() } else { - panic!("GenMC not found in path '{GENMC_LOCAL_PATH}', and downloading GenMC is disabled."); + downloading::download_genmc() }; // Build all required components: From 3e5d3ab93f63de767bdc501855f6b1a56555e35e Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 13:48:44 +0200 Subject: [PATCH 49/64] Remove local GenMC path for development, only support local path through GENMC_SRC_PATH env var. --- doc/genmc.md | 3 +-- genmc-sys/build.rs | 30 ++++++++---------------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/doc/genmc.md b/doc/genmc.md index 5a083e3d7f..5c1b324808 100644 --- a/doc/genmc.md +++ b/doc/genmc.md @@ -49,8 +49,7 @@ Note that this repo is just a mirror repo. The build script in the `genmc-sys` crate handles locating, downloading, building and linking the GenMC library. To determine which GenMC repo path will be used, the following steps are taken: -- If the env var `GENMC_SRC_PATH` contains a path to a directory with a GenMC repo, use that path. -- If the path `genmc-sys/genmc` exists, use that path. +- If the env var `GENMC_SRC_PATH` is set, it's value is used as a path to a directory with a GenMC repo. - If the path `genmc-sys/downloaded/genmc` exists, try to set the GenMC repo there to the commit we need. - If the downloaded repo doesn't exist or is missing the commit, the build script will fetch the commit over the network. - Note that the build script will *not* access the network if any of the steps previous steps succeeds. diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index aa4e2d2bd9..729c8f2de4 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -2,11 +2,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; // Build script for running Miri with GenMC. -// Check out doc/GenMC.md for more info. - -/// Path used for development of Miri-GenMC. -/// A GenMC repository in this directory (relative to the `genmc-sys` directory) will take precedence over the downloaded GenMC repository. -const GENMC_LOCAL_PATH: &str = "./genmc/"; +// Check out doc/genmc.md for more info. /// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory). /// Note that this directory is *not* cleaned up automatically by `cargo clean`. @@ -22,12 +18,12 @@ const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; mod downloading { - use std::path::{Path, PathBuf}; + use std::path::PathBuf; use std::str::FromStr; use git2::{Commit, Oid, Repository, StatusOptions}; - use super::{GENMC_DOWNLOAD_PATH, GENMC_LOCAL_PATH}; + use super::GENMC_DOWNLOAD_PATH; /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; @@ -104,10 +100,8 @@ mod downloading { return; } - let local_path = Path::new(GENMC_LOCAL_PATH); println!( - "HINT: For local development, place a GenMC repository in the path {:?}.", - std::path::absolute(local_path).unwrap_or_else(|_| local_path.into()) + "HINT: For local development, set the environment variable 'GENMC_SRC_PATH' to the path of a GenMC repository.", ); panic!( "Downloaded GenMC repository at path '{GENMC_DOWNLOAD_PATH}' has been modified. Please undo any changes made, or delete the '{GENMC_DOWNLOAD_PATH}' directory to have it downloaded again." @@ -165,9 +159,8 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_inclu let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); // FIXME(genmc,llvm): remove once LLVM dependency is removed. - // HACK: We filter out _GNU_SOURCE, since it is already set and produces a warning if set again. - let definitions = - llvm_definitions.split(";").filter(|definition| definition != &"-D_GNU_SOURCE"); + // These definitions are parsed into a cmake list and then printed to the config.h file, so they are ';' separated. + let definitions = llvm_definitions.split(";"); cxx_build::bridge("src/lib.rs") .flags(definitions) @@ -221,23 +214,15 @@ fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String, String) { fn main() { // Select which path to use for the GenMC repo: - let Ok(genmc_local_path) = PathBuf::from_str(GENMC_LOCAL_PATH); let genmc_path = if let Ok(genmc_src_path) = std::env::var("GENMC_SRC_PATH") { let genmc_src_path = PathBuf::from_str(&genmc_src_path).expect("GENMC_SRC_PATH should contain a valid path"); assert!( genmc_src_path.exists(), - "GENMC_SRC_PATH ({}) does not exist!", + "GENMC_SRC_PATH={} does not exist!", genmc_src_path.display() ); genmc_src_path - } else if genmc_local_path.exists() { - // If the local repository exists, cargo should watch it for changes: - // FIXME(genmc,cargo): We could always watch this path even if it doesn't (yet) exist, depending on how `https://github.com/rust-lang/cargo/issues/6003` is resolved. - // Adding it here means we don't rebuild if a user creates `GENMC_LOCAL_PATH`, which isn't ideal. - // Cargo currently always rebuilds if a watched directory doesn't exist, so we can only add it if it exists. - println!("cargo::rerun-if-changed={GENMC_LOCAL_PATH}"); - genmc_local_path } else { downloading::download_genmc() }; @@ -252,4 +237,5 @@ fn main() { // Adding that path here would also trigger an unnecessary rebuild after the repo is cloned (since cargo detects that as a file modification). println!("cargo::rerun-if-changed={RUST_CXX_BRIDGE_FILE_PATH}"); println!("cargo::rerun-if-changed=./src_cpp"); + println!("cargo::rerun-if-env-changed=GENMC_SRC_PATH"); } From 2ee2e379005fafe2a7555d229f4cc7c3b0f0c849 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 14:25:25 +0200 Subject: [PATCH 50/64] Switch to passing cxx_build compiler parameters as struct. --- genmc-sys/build.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 729c8f2de4..9200de4a15 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -17,6 +17,15 @@ const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; /// The profile with which to build GenMC. const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; +/// Info required to be passed to subsequent compilation steps. +struct CompileInfo { + /// Directory where cmake installs the GenMC library into. + pub genmc_install_dir: PathBuf, + // FIXME(genmc,llvm): remove once LLVM dependency is removed. + pub llvm_definitions: String, + pub llvm_include_dirs: String, +} + mod downloading { use std::path::PathBuf; use std::str::FromStr; @@ -155,7 +164,9 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { } /// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_include_dirs: &str) { +fn build_cxx_bridge(compile_info: CompileInfo) { + let CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs } = compile_info; + let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); // FIXME(genmc,llvm): remove once LLVM dependency is removed. @@ -182,7 +193,7 @@ fn build_cxx_bridge(genmc_install_dir: &Path, llvm_definitions: &str, llvm_inclu /// Build the GenMC model checker library. /// Returns the path where cmake installs the model checker library and the config.h file. /// FIXME(genmc,llvm): Also returns the c++ compiler definitions required for building with/including LLVM, and the include path for LLVM headers. (remove once LLVM dependency is removed). -fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String, String) { +fn build_genmc_model_checker(genmc_path: &Path) -> CompileInfo { // FIXME(genmc,cargo): Switch to using `CARGO_CFG_DEBUG_ASSERTIONS` once https://github.com/rust-lang/cargo/issues/15760 is completed. // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release) let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); @@ -209,7 +220,7 @@ fn build_genmc_model_checker(genmc_path: &Path) -> (PathBuf, String, String) { let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); let (llvm_definitions, llvm_include_dirs) = link_to_llvm(&config_file); - (genmc_install_dir, llvm_definitions, llvm_include_dirs) + CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs } } fn main() { @@ -228,9 +239,8 @@ fn main() { }; // Build all required components: - let (genmc_install_dir, llvm_definitions, llvm_include_dirs) = - build_genmc_model_checker(&genmc_path); - build_cxx_bridge(&genmc_install_dir, &llvm_definitions, &llvm_include_dirs); + let compile_info = build_genmc_model_checker(&genmc_path); + build_cxx_bridge(compile_info); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. From a86b775b777c91f0c3e0022337106a2f50106bcc Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 14:43:41 +0200 Subject: [PATCH 51/64] [temporary] Pass GenMC debug setting manually until GenMC makes it available in the configuration file. --- genmc-sys/build.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 9200de4a15..085a012222 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -24,6 +24,8 @@ struct CompileInfo { // FIXME(genmc,llvm): remove once LLVM dependency is removed. pub llvm_definitions: String, pub llvm_include_dirs: String, + // FIXME(genmc,cmake): Remove once the GenMC debug setting is available in the config.h file. + pub enable_genmc_debug: bool, } mod downloading { @@ -37,7 +39,7 @@ mod downloading { /// The GenMC repository the we get our commit from. pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. - pub(crate) const GENMC_COMMIT: &str = "f8d41c7d8c7d88e47f71ef6bd7914041a2691aab"; + pub(crate) const GENMC_COMMIT: &str = "833322934f7608690340a284a496402e2daa0ef3"; pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); @@ -165,7 +167,8 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { /// Build the Rust-C++ interop library with cxx.rs fn build_cxx_bridge(compile_info: CompileInfo) { - let CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs } = compile_info; + let CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs, enable_genmc_debug } = + compile_info; let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); @@ -173,7 +176,12 @@ fn build_cxx_bridge(compile_info: CompileInfo) { // These definitions are parsed into a cmake list and then printed to the config.h file, so they are ';' separated. let definitions = llvm_definitions.split(";"); - cxx_build::bridge("src/lib.rs") + let mut bridge = cxx_build::bridge("src/lib.rs"); + // FIXME(genmc,cmake): Remove once the GenMC debug setting is available in the config.h file. + if enable_genmc_debug { + bridge.define("ENABLE_GENMC_DEBUG", None); + } + bridge .flags(definitions) .opt_level(2) .debug(true) // Same settings that GenMC uses (default for cmake `RelWithDebInfo`) @@ -220,7 +228,7 @@ fn build_genmc_model_checker(genmc_path: &Path) -> CompileInfo { let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); let (llvm_definitions, llvm_include_dirs) = link_to_llvm(&config_file); - CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs } + CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs, enable_genmc_debug } } fn main() { From 012781c9145b069bcaeab5e1cce38fa2bc2fe359 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 15:26:09 +0200 Subject: [PATCH 52/64] Clean up C++ compilation steps and combine them into 1 function. --- genmc-sys/build.rs | 80 +++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 085a012222..ec34e86e67 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -17,17 +17,6 @@ const RUST_CXX_BRIDGE_FILE_PATH: &str = "src/lib.rs"; /// The profile with which to build GenMC. const GENMC_CMAKE_PROFILE: &str = "RelWithDebInfo"; -/// Info required to be passed to subsequent compilation steps. -struct CompileInfo { - /// Directory where cmake installs the GenMC library into. - pub genmc_install_dir: PathBuf, - // FIXME(genmc,llvm): remove once LLVM dependency is removed. - pub llvm_definitions: String, - pub llvm_include_dirs: String, - // FIXME(genmc,cmake): Remove once the GenMC debug setting is available in the config.h file. - pub enable_genmc_debug: bool, -} - mod downloading { use std::path::PathBuf; use std::str::FromStr; @@ -165,10 +154,35 @@ fn link_to_llvm(config_file: &Path) -> (String, String) { (llvm_definitions.to_string(), llvm_include_dirs.to_string()) } -/// Build the Rust-C++ interop library with cxx.rs -fn build_cxx_bridge(compile_info: CompileInfo) { - let CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs, enable_genmc_debug } = - compile_info; +/// Build the GenMC model checker library and the Rust-C++ interop library with cxx.rs +fn compile_cpp_dependencies(genmc_path: &Path) { + // Part 1: + // Compile the GenMC library using cmake. + + let cmakelists_path = genmc_path.join("CMakeLists.txt"); + + // FIXME(genmc,cargo): Switch to using `CARGO_CFG_DEBUG_ASSERTIONS` once https://github.com/rust-lang/cargo/issues/15760 is completed. + // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release) + let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); + + let mut config = cmake::Config::new(cmakelists_path); + config.profile(GENMC_CMAKE_PROFILE); + config.define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" }); + + // The actual compilation happens here: + let genmc_install_dir = config.build(); + + // Add the model checker library to be linked and tell GenMC where to find it: + let cmake_lib_dir = genmc_install_dir.join("lib").join("genmc"); + println!("cargo::rustc-link-search=native={}", cmake_lib_dir.display()); + println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); + + // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. + let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); + let (llvm_definitions, llvm_include_dirs) = link_to_llvm(&config_file); + + // Part 2: + // Compile the cxx_bridge (the link between the Rust and C++ code). let genmc_include_dir = genmc_install_dir.join("include").join("genmc"); @@ -198,39 +212,6 @@ fn build_cxx_bridge(compile_info: CompileInfo) { println!("cargo::rustc-link-lib=static=genmc_interop"); } -/// Build the GenMC model checker library. -/// Returns the path where cmake installs the model checker library and the config.h file. -/// FIXME(genmc,llvm): Also returns the c++ compiler definitions required for building with/including LLVM, and the include path for LLVM headers. (remove once LLVM dependency is removed). -fn build_genmc_model_checker(genmc_path: &Path) -> CompileInfo { - // FIXME(genmc,cargo): Switch to using `CARGO_CFG_DEBUG_ASSERTIONS` once https://github.com/rust-lang/cargo/issues/15760 is completed. - // Enable/disable additional debug checks, prints and options for GenMC, based on the Rust profile (debug/release) - let enable_genmc_debug = matches!(std::env::var("PROFILE").as_deref().unwrap(), "debug"); - - let cmakelists_path = genmc_path.join("CMakeLists.txt"); - - let mut config = cmake::Config::new(cmakelists_path); - config.profile(GENMC_CMAKE_PROFILE); - config.define("GENMC_DEBUG", if enable_genmc_debug { "ON" } else { "OFF" }); - - // Enable and install the components of GenMC that we need: - config.define("BUILD_LLI", "OFF"); // No need to build the GenMC executable. - config.define("BUILD_MODEL_CHECKER", "ON"); - config.define("INSTALL_MODEL_CHECKER", "ON"); - - let genmc_install_dir = config.build(); - - // Add the model checker library to be linked and tell GenMC where to find it: - let cmake_lib_dir = genmc_install_dir.join("lib").join("genmc"); - println!("cargo::rustc-link-search=native={}", cmake_lib_dir.display()); - println!("cargo::rustc-link-lib=static={GENMC_MODEL_CHECKER}"); - - // FIXME(genmc,llvm): Remove once the LLVM dependency of the GenMC model checker is removed. - let config_file = genmc_install_dir.join("include").join("genmc").join("config.h"); - let (llvm_definitions, llvm_include_dirs) = link_to_llvm(&config_file); - - CompileInfo { genmc_install_dir, llvm_definitions, llvm_include_dirs, enable_genmc_debug } -} - fn main() { // Select which path to use for the GenMC repo: let genmc_path = if let Ok(genmc_src_path) = std::env::var("GENMC_SRC_PATH") { @@ -247,8 +228,7 @@ fn main() { }; // Build all required components: - let compile_info = build_genmc_model_checker(&genmc_path); - build_cxx_bridge(compile_info); + compile_cpp_dependencies(&genmc_path); // Only rebuild if anything changes: // Note that we don't add the downloaded GenMC repo, since that should never be modified manually. From c16d4206c1e30fc2210deab9222c2561507a4d17 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 15:27:01 +0200 Subject: [PATCH 53/64] Add genmc-sys to rust-analyzer linkedProjects paths. --- etc/rust_analyzer_helix.toml | 1 + etc/rust_analyzer_vscode.json | 1 + 2 files changed, 2 insertions(+) diff --git a/etc/rust_analyzer_helix.toml b/etc/rust_analyzer_helix.toml index 91e4070478..c46b246049 100644 --- a/etc/rust_analyzer_helix.toml +++ b/etc/rust_analyzer_helix.toml @@ -5,6 +5,7 @@ source = "discover" linkedProjects = [ "Cargo.toml", "cargo-miri/Cargo.toml", + "genmc-sys/Cargo.toml", "miri-script/Cargo.toml", ] diff --git a/etc/rust_analyzer_vscode.json b/etc/rust_analyzer_vscode.json index 6917c6a1fd..8e647f5331 100644 --- a/etc/rust_analyzer_vscode.json +++ b/etc/rust_analyzer_vscode.json @@ -3,6 +3,7 @@ "rust-analyzer.linkedProjects": [ "Cargo.toml", "cargo-miri/Cargo.toml", + "genmc-sys/Cargo.toml", "miri-script/Cargo.toml", ], "rust-analyzer.check.invocationStrategy": "once", From 09772063d4437ea874e87131826280c0ab712bb9 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 19:39:50 +0200 Subject: [PATCH 54/64] Prevent Miri fmt from formatting downloaded GenMC Rust files. --- miri-script/src/commands.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri-script/src/commands.rs b/miri-script/src/commands.rs index 9aaad9ca04..5456b2becd 100644 --- a/miri-script/src/commands.rs +++ b/miri-script/src/commands.rs @@ -757,8 +757,8 @@ impl Command { if ty.is_file() { name.ends_with(".rs") } else { - // dir or symlink. skip `target` and `.git`. - &name != "target" && &name != ".git" + // dir or symlink. skip `target`, `.git` and `downloaded` (last is used in `genmc-sys` subcrate of Miri). + &name != "target" && &name != ".git" && &name != "downloaded" } }) .filter_ok(|item| item.file_type().is_file()) From e6a0ff31f0a51c8225ab50606c30964d74f5f2fd Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 19:46:34 +0200 Subject: [PATCH 55/64] Add handling for changing remote URL for downloaded GenMC repo. --- genmc-sys/build.rs | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index ec34e86e67..7d952c59e8 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -21,7 +21,7 @@ mod downloading { use std::path::PathBuf; use std::str::FromStr; - use git2::{Commit, Oid, Repository, StatusOptions}; + use git2::{Commit, Oid, Remote, Repository, StatusOptions}; use super::GENMC_DOWNLOAD_PATH; @@ -54,18 +54,40 @@ mod downloading { genmc_download_path } + fn get_remote(repo: &Repository) -> Remote<'_> { + let remote = repo.find_remote("origin").unwrap_or_else(|e| { + panic!( + "Could not load commit ({GENMC_COMMIT}) from remote repository '{GENMC_GITHUB_URL}'. Error: {e}" + ); + }); + + // Ensure that the correct remote URL is set. + let remote_url = remote.url(); + if let Some(remote_url) = remote_url + && remote_url == GENMC_GITHUB_URL + { + return remote; + } + + // Update remote URL. + println!( + "cargo::warning=GenMC repository remote URL has changed from '{remote_url:?}' to '{GENMC_GITHUB_URL}'" + ); + repo.remote_set_url("origin", GENMC_GITHUB_URL) + .expect("cannot rename url of remote 'origin'"); + + // Reacquire the `Remote`, since `remote_set_url` doesn't update Remote objects already in memory. + repo.find_remote("origin").unwrap() + } + // Check if the required commit exists already, otherwise try fetching it. fn update_local_repo(repo: &Repository, commit_oid: Oid) -> Commit<'_> { repo.find_commit(commit_oid).unwrap_or_else(|_find_error| { println!("GenMC repository at path '{GENMC_DOWNLOAD_PATH}' does not contain commit '{GENMC_COMMIT}'."); // The commit is not in the checkout. Try `git fetch` and hope that we find the commit then. - match repo.find_remote("origin") { - Ok(mut remote) => - remote.fetch(&[GENMC_COMMIT], None, None).expect("Failed to fetch from remote."), - Err(e) => { - panic!("Could not load commit ({GENMC_COMMIT}) from remote repository '{GENMC_GITHUB_URL}'. Error: {e}"); - } - } + let mut remote = get_remote(repo); + remote.fetch(&[GENMC_COMMIT], None, None).expect("Failed to fetch from remote."); + repo.find_commit(commit_oid) .expect("Remote repository should contain expected commit") }) From 41d796edf2ec3b5a11995357101637188d76cdf9 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Thu, 24 Jul 2025 19:47:10 +0200 Subject: [PATCH 56/64] Update GenMC repo to officially released version. --- genmc-sys/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 7d952c59e8..8f10913a30 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -26,9 +26,9 @@ mod downloading { use super::GENMC_DOWNLOAD_PATH; /// The GenMC repository the we get our commit from. - pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/Patrick-6/genmc.git"; + pub(crate) const GENMC_GITHUB_URL: &str = "https://github.com/MPI-SWS/genmc.git"; /// The GenMC commit we depend on. It must be available on the specified GenMC repository. - pub(crate) const GENMC_COMMIT: &str = "833322934f7608690340a284a496402e2daa0ef3"; + pub(crate) const GENMC_COMMIT: &str = "3438dd2c1202cd4a47ed7881d099abf23e4167ab"; pub(crate) fn download_genmc() -> PathBuf { let Ok(genmc_download_path) = PathBuf::from_str(GENMC_DOWNLOAD_PATH); From 9f14cd30016097e909b282bd232dca56a6ea5635 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 25 Jul 2025 00:50:22 +0200 Subject: [PATCH 57/64] Give downloaded GenMC directory a better name. Improve docs about formatting exception for downloaded GenMC. --- doc/genmc.md | 11 +++++++++-- genmc-sys/.gitignore | 4 +--- genmc-sys/build.rs | 2 +- miri-script/src/commands.rs | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/doc/genmc.md b/doc/genmc.md index 5c1b324808..4efd1d66ef 100644 --- a/doc/genmc.md +++ b/doc/genmc.md @@ -49,8 +49,8 @@ Note that this repo is just a mirror repo. The build script in the `genmc-sys` crate handles locating, downloading, building and linking the GenMC library. To determine which GenMC repo path will be used, the following steps are taken: -- If the env var `GENMC_SRC_PATH` is set, it's value is used as a path to a directory with a GenMC repo. -- If the path `genmc-sys/downloaded/genmc` exists, try to set the GenMC repo there to the commit we need. +- If the env var `GENMC_SRC_PATH` is set, it's value is used as a path to a directory with a GenMC repo (e.g., `GENMC_SRC_PATH="path/to/miri/genmc-sys/genmc-sys-local"`). +- If the path `genmc-sys/genmc-src/genmc` exists, try to set the GenMC repo there to the commit we need. - If the downloaded repo doesn't exist or is missing the commit, the build script will fetch the commit over the network. - Note that the build script will *not* access the network if any of the steps previous steps succeeds. @@ -58,3 +58,10 @@ Once we get the path to the repo, the compilation proceeds in two steps: - Compile GenMC into a library (using cmake). - Compile the cxx.rs bridge to connect the library to the Rust code. The first step is where all build settings are made, the relevant ones are then stored in a `config.h` file that can be included in the second compilation step. + +#### Code Formatting +Note that all directories with names starting with `genmc-src` are ignored by `./miri fmt` on purpose. +GenMC also contains Rust files, but they should not be formatted with Miri's formatting rules. +For working on Miri-GenMC locally, placing the GenMC repo into such a path (e.g., `miri/genmc-sys/genmc-src-local`) ensures that it is also exempt from formatting. + + diff --git a/genmc-sys/.gitignore b/genmc-sys/.gitignore index f526fe37c0..276a053cd0 100644 --- a/genmc-sys/.gitignore +++ b/genmc-sys/.gitignore @@ -1,3 +1 @@ -genmc/ -genmc-*/ -downloaded/ +genmc-src*/ diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index 8f10913a30..b0140f1a94 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -6,7 +6,7 @@ use std::str::FromStr; /// Path where the downloaded GenMC repository will be stored (relative to the `genmc-sys` directory). /// Note that this directory is *not* cleaned up automatically by `cargo clean`. -const GENMC_DOWNLOAD_PATH: &str = "./downloaded/genmc/"; +const GENMC_DOWNLOAD_PATH: &str = "./genmc-src/genmc/"; /// Name of the library of the GenMC model checker. const GENMC_MODEL_CHECKER: &str = "genmc_lib"; diff --git a/miri-script/src/commands.rs b/miri-script/src/commands.rs index 5456b2becd..7f3bc1bc75 100644 --- a/miri-script/src/commands.rs +++ b/miri-script/src/commands.rs @@ -757,8 +757,8 @@ impl Command { if ty.is_file() { name.ends_with(".rs") } else { - // dir or symlink. skip `target`, `.git` and `downloaded` (last is used in `genmc-sys` subcrate of Miri). - &name != "target" && &name != ".git" && &name != "downloaded" + // dir or symlink. skip `target`, `.git` and `genmc-src*` + &name != "target" && &name != ".git" && !name.starts_with("genmc-src") } }) .filter_ok(|item| item.file_type().is_file()) From a1239bd806c64b6f5630ae9dbfeb871f5b5cf99c Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 25 Jul 2025 12:41:22 +0200 Subject: [PATCH 58/64] Pin cc crate version to higher than what cxx_build requires. --- Cargo.lock | 1 + genmc-sys/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 2d296f2f61..ece51f2ba7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -528,6 +528,7 @@ dependencies = [ name = "genmc-sys" version = "0.1.0" dependencies = [ + "cc", "cmake", "cxx", "cxx-build", diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index f6d98c695c..2215c634bc 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" cxx = { version = "1.0.160", features = ["c++20"] } [build-dependencies] +cc = "1.2.30" cmake = "0.1.54" git2 = { version = "0.20.2", default-features = false, features = ["https"] } cxx-build = { version = "1.0.160", features = ["parallel"] } From 517794618296ddfdbb6e4d37462249c6053fd474 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 25 Jul 2025 13:06:13 +0200 Subject: [PATCH 59/64] Set genmc-sys license and update docs about licensing issues. --- doc/genmc.md | 10 +++ genmc-sys/Cargo.toml | 2 + genmc-sys/LICENSE | 176 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 genmc-sys/LICENSE diff --git a/doc/genmc.md b/doc/genmc.md index 4efd1d66ef..f22010251c 100644 --- a/doc/genmc.md +++ b/doc/genmc.md @@ -6,6 +6,16 @@ ## Usage + +**IMPORTANT: The license of GenMC and thus the `genmc-sys` crate in the Miri repo is currently "GPL-3.0-or-later", which is NOT compatible with Miri's "MIT OR Apache" license.** + +**IMPORTANT: There should be no distribution of Miri-GenMC until all licensing questions are clarified (the `genmc` feature of Miri is OFF-BY-DEFAULT and should be OFF for all Miri releases).** + +For testing/developing Miri-GenMC (while keeping in mind the licensing issues): +- clone the Miri repo. +- build Miri-GenMC with `./miri build --features=genmc`. +- OR: install Miri-GenMC in the current system with `./miri install --features=genmc` + Basic usage: ```shell MIRIFLAGS="-Zmiri-genmc" cargo miri run diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index 2215c634bc..3da6413ba1 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -1,4 +1,6 @@ [package] +authors = ["Miri Team"] +license = "GPL-3.0-or-later" name = "genmc-sys" version = "0.1.0" edition = "2024" diff --git a/genmc-sys/LICENSE b/genmc-sys/LICENSE new file mode 100644 index 0000000000..ee80278cc3 --- /dev/null +++ b/genmc-sys/LICENSE @@ -0,0 +1,176 @@ +Copyright © 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The GNU General Public License is a free, copyleft license for software and other kinds of works. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. + +Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based on the Program. + + To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + 1. Source Code. + The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. + + A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. + + The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + + The Corresponding Source for a work in source code form is that same work. + 2. Basic Permissions. + All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + + When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + 4. Conveying Verbatim Copies. + You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + 5. Conveying Modified Source Versions. + You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + a) The work must carry prominent notices stating that you modified it, and giving a relevant date. + b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". + c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. + d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. + + A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + 6. Conveying Non-Source Forms. + You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. + b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. + c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. + d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. + e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + + If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + + The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + 7. Additional Terms. + "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or + b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or + c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or + d) Limiting the use for publicity purposes of names of licensors or authors of the material; or + e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or + f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. + + All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + 8. Termination. + You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + + However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + + Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + 9. Acceptance Not Required for Having Copies. + You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + 10. Automatic Licensing of Downstream Recipients. + Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + 11. Patents. + A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + + If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + + A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + 12. No Surrender of Others' Freedom. + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + 13. Use with the GNU Affero General Public License. + Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. + 14. Revised Versions of this License. + The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + + Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + 15. Disclaimer of Warranty. + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + 16. Limitation of Liability. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +The genmc-sys crate allows Miri to build and link to GenMC , a stateless mdoel checker for C programs. +Copyright (C) 2025 Miri Team + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see . From 2f401badfb37d2d2eadc214621aefd007c48fb3c Mon Sep 17 00:00:00 2001 From: Patrick-6 <93388547+Patrick-6@users.noreply.github.com> Date: Fri, 25 Jul 2025 13:07:32 +0200 Subject: [PATCH 60/64] Add warning about genmc-sys license Co-authored-by: Ralf Jung --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5afde9b23d..91dadf78a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ harness = false [features] default = ["stack-cache", "native-lib"] -genmc = ["dep:genmc-sys"] +genmc = ["dep:genmc-sys"] # this enables a GPL dependency! stack-cache = [] stack-cache-consistency-check = ["stack-cache"] tracing = ["serde_json"] From c3ca2f2cc11912ae9d8f333bbba85bbff8518a44 Mon Sep 17 00:00:00 2001 From: Patrick-6 <93388547+Patrick-6@users.noreply.github.com> Date: Fri, 25 Jul 2025 13:08:30 +0200 Subject: [PATCH 61/64] Add error when compiling genmc-sys in rustc workspace (due to licensing issues) Co-authored-by: Ralf Jung --- genmc-sys/build.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index b0140f1a94..ece922017b 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -235,6 +235,11 @@ fn compile_cpp_dependencies(genmc_path: &Path) { } fn main() { + // Make sure we don't accidentally distribute a binary with GPL code. + if option_env!("RUSTC_STAGE").is_some() { + panic!("genmc should not be enabled in the rustc workspace since it includes a GPL dependency"); + } + // Select which path to use for the GenMC repo: let genmc_path = if let Ok(genmc_src_path) = std::env::var("GENMC_SRC_PATH") { let genmc_src_path = From 5cc2046050cee290f8b120b8bae6b8735b2f4f1a Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 25 Jul 2025 13:11:33 +0200 Subject: [PATCH 62/64] run fmt --- genmc-sys/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/genmc-sys/build.rs b/genmc-sys/build.rs index ece922017b..16f7b69cc2 100644 --- a/genmc-sys/build.rs +++ b/genmc-sys/build.rs @@ -237,7 +237,9 @@ fn compile_cpp_dependencies(genmc_path: &Path) { fn main() { // Make sure we don't accidentally distribute a binary with GPL code. if option_env!("RUSTC_STAGE").is_some() { - panic!("genmc should not be enabled in the rustc workspace since it includes a GPL dependency"); + panic!( + "genmc should not be enabled in the rustc workspace since it includes a GPL dependency" + ); } // Select which path to use for the GenMC repo: From b9d958660d5ddfbd2380f9a694a32f8d64344bbe Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 26 Jul 2025 14:07:25 +0200 Subject: [PATCH 63/64] Change genmc-sys license to MIT/Apache, with note about GenMC license. --- genmc-sys/Cargo.toml | 4 +- genmc-sys/LICENSE | 176 ------------------------------------------- 2 files changed, 3 insertions(+), 177 deletions(-) delete mode 100644 genmc-sys/LICENSE diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index 3da6413ba1..95aef75afc 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -1,6 +1,8 @@ [package] authors = ["Miri Team"] -license = "GPL-3.0-or-later" +# The parts in this repo are MIT OR Apache-2.0, but we are linking in +# code from https://github.com/MPI-SWS/genmc which is GPL-3.0-or-later. +license = "(MIT OR Apache-2.0) AND GPL-3.0-or-later" name = "genmc-sys" version = "0.1.0" edition = "2024" diff --git a/genmc-sys/LICENSE b/genmc-sys/LICENSE deleted file mode 100644 index ee80278cc3..0000000000 --- a/genmc-sys/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - -Preamble - -The GNU General Public License is a free, copyleft license for software and other kinds of works. - -The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. - -To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. - -The precise terms and conditions for copying, distribution and modification follow. - -TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based on the Program. - - To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. - 1. Source Code. - The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. - - A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. - - The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. - - The Corresponding Source for a work in source code form is that same work. - 2. Basic Permissions. - All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. - - When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - 4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - 5. Conveying Modified Source Versions. - You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: - a) The work must carry prominent notices stating that you modified it, and giving a relevant date. - b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". - c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. - - A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. - 6. Conveying Non-Source Forms. - You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: - a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. - b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. - c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. - d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. - e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. - - If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). - - The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. - 7. Additional Terms. - "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: - a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or - b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or - c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or - d) Limiting the use for publicity purposes of names of licensors or authors of the material; or - e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or - f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - - All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. - 8. Termination. - You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). - - However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. - - Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. - 9. Acceptance Not Required for Having Copies. - You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - 10. Automatic Licensing of Downstream Recipients. - Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. - 11. Patents. - A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. - - If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - - A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - 12. No Surrender of Others' Freedom. - If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. - 13. Use with the GNU Affero General Public License. - Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. - 14. Revised Versions of this License. - The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. - - Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. - 15. Disclaimer of Warranty. - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 16. Limitation of Liability. - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - -The genmc-sys crate allows Miri to build and link to GenMC , a stateless mdoel checker for C programs. -Copyright (C) 2025 Miri Team - -This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program. If not, see . From df4dbe2a4abd314366b30504c7cc9b8e97f3ebe9 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 26 Jul 2025 14:09:07 +0200 Subject: [PATCH 64/64] Add comment about setting GENMC_SRC_PATH env var also for Rust Analyzer --- doc/genmc.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/genmc.md b/doc/genmc.md index f22010251c..4839919557 100644 --- a/doc/genmc.md +++ b/doc/genmc.md @@ -60,6 +60,7 @@ The build script in the `genmc-sys` crate handles locating, downloading, buildin To determine which GenMC repo path will be used, the following steps are taken: - If the env var `GENMC_SRC_PATH` is set, it's value is used as a path to a directory with a GenMC repo (e.g., `GENMC_SRC_PATH="path/to/miri/genmc-sys/genmc-sys-local"`). + - Note that this variable must be set wherever Miri is built, e.g., in the terminal, or in the Rust Analyzer settings. - If the path `genmc-sys/genmc-src/genmc` exists, try to set the GenMC repo there to the commit we need. - If the downloaded repo doesn't exist or is missing the commit, the build script will fetch the commit over the network. - Note that the build script will *not* access the network if any of the steps previous steps succeeds.