From b1a52768061f4d15f9a2ac805a83574415a44f4d Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Fri, 14 Mar 2025 09:58:46 +0100 Subject: [PATCH 01/34] 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 | 913 +++++++++++-- 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 | 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 + .../_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, 8347 insertions(+), 312 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 aa6f059cec..525e8de1a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" @@ -44,40 +44,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" dependencies = [ "anstyle", - "unicode-width 0.2.0", + "unicode-width 0.2.1", ] [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -91,15 +91,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -108,15 +108,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] @@ -166,18 +166,20 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.17" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ + "jobserver", + "libc", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -187,9 +189,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "num-traits", ] @@ -225,29 +227,75 @@ dependencies = [ "inout", ] +[[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 0.2.1", +] + [[package]] name = "color-eyre" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" dependencies = [ "backtrace", "color-spantrace", "eyre", "indenter", "once_cell", - "owo-colors", + "owo-colors 4.2.1", "tracing-error", ] [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" dependencies = [ "once_cell", - "owo-colors", + "owo-colors 4.2.1", "tracing-core", "tracing-error", ] @@ -277,7 +325,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.0", + "unicode-width 0.2.1", "windows-sys 0.59.0", ] @@ -315,6 +363,68 @@ dependencies = [ "typenum", ] +[[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 = "directories" version = "6.0.0" @@ -333,7 +443,18 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "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]] @@ -342,11 +463,17 @@ 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.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -374,6 +501,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" @@ -384,22 +526,32 @@ dependencies = [ "version_check", ] +[[package]] +name = "genmc-sys" +version = "0.11.0" +dependencies = [ + "cmake", + "cxx", + "cxx-build", + "git2", +] + [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -409,9 +561,137 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +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 = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +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" @@ -419,6 +699,16 @@ 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" @@ -428,7 +718,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.0", + "unicode-width 0.2.1", "web-time", ] @@ -466,6 +756,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" @@ -490,15 +790,15 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libffi" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074" +checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838" dependencies = [ "libc", "libffi-sys", @@ -506,21 +806,35 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84" +checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3" 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.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.53.2", ] [[package]] @@ -533,17 +847,58 @@ 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.3" +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 = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -571,9 +926,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -586,23 +941,23 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -615,15 +970,17 @@ dependencies = [ "chrono", "chrono-tz", "colored", + "cxx", "directories", - "getrandom 0.3.2", + "genmc-sys", + "getrandom 0.3.3", "ipc-channel", "libc", "libffi", "libloading", "measureme", "nix", - "rand 0.9.0", + "rand 0.9.1", "regex", "rustc_version", "serde", @@ -663,9 +1020,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -676,6 +1033,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" @@ -688,6 +1063,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "owo-colors" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" + [[package]] name = "pad" version = "0.1.6" @@ -699,9 +1080,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -709,15 +1090,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -729,6 +1110,12 @@ dependencies = [ "regex", ] +[[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" @@ -782,11 +1169,26 @@ 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.0" +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 = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] [[package]] name = "ppv-lite86" @@ -803,15 +1205,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "owo-colors", + "owo-colors 3.5.0", "pad", ] [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -827,9 +1229,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -844,13 +1246,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy", ] [[package]] @@ -879,7 +1280,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -888,14 +1289,14 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags", ] @@ -906,7 +1307,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -942,9 +1343,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -975,9 +1376,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", @@ -986,6 +1387,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.20" @@ -998,6 +1405,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" @@ -1062,9 +1475,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "spanned" @@ -1076,30 +1489,62 @@ 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.100" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" 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 = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "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" @@ -1142,12 +1587,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -1160,6 +1604,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" @@ -1172,9 +1626,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -1247,17 +1701,36 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.0" +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 = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +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.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -1266,6 +1739,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" @@ -1274,9 +1753,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -1295,6 +1774,7 @@ checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] @@ -1354,6 +1834,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" @@ -1361,7 +1850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1374,7 +1863,7 @@ dependencies = [ "windows-interface", "windows-result", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1405,7 +1894,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1415,25 +1904,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.2", ] [[package]] @@ -1442,14 +1931,30 @@ 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", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -1458,48 +1963,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[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_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[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_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -1509,20 +2062,104 @@ 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.24" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "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 = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 75476d7923..a94f985a6d 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 @@ -64,8 +66,10 @@ name = "ui" harness = false [features] -default = ["stack-cache"] -genmc = [] +# TODO GENMC (DEBUGGING): `genmc` feature should be turned off in upstream repo for now +default = ["stack-cache", "genmc"] +# default = ["stack-cache"] +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 e3b579a4ac..c109b0b792 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() { @@ -598,8 +623,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()); @@ -736,9 +764,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 b5e7e9d0ac..811920cb63 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 49bcc0d30b..0805997ea4 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -13,5 +13,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 56c1979485..41039d2904 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,11 +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. - 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 @@ -688,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) } @@ -701,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; @@ -713,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(); @@ -861,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. @@ -914,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(); @@ -951,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; @@ -1074,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(); @@ -1204,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) { @@ -1234,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 95c010be2f..c004c7bedf 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 63578912c2..467647a646 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -241,9 +241,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 c86e33e518..8743db999a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,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::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; diff --git a/src/machine.rs b/src/machine.rs index 4f3dc48532..9479f0bde5 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. @@ -1144,6 +1146,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))) } @@ -1296,6 +1304,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) } @@ -1387,6 +1399,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), @@ -1448,7 +1464,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) = @@ -1485,7 +1503,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( @@ -1576,6 +1594,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, @@ -1697,6 +1716,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); } @@ -1708,6 +1728,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); } @@ -1737,6 +1758,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine, ); } + // TODO GENMC: how to handle this (if at all)? interp_ok(()) } @@ -1755,6 +1777,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 97070eb742..3578f15e8d 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 5239f8338e..106722772d 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 86ce52ac2eaa6c3d359da7bb198931e1119812ba Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 10:02:31 +0200 Subject: [PATCH 02/34] 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 0d45dbdc4442cd342314afa9cfaa63f13c5e3124 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 11:38:19 +0200 Subject: [PATCH 03/34] Miri-GenMC build PR: Reduce code changes to minimum needed to test build. --- Cargo.lock | 352 +++--- 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, 375 insertions(+), 4096 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 525e8de1a1..e9920b49d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] [[package]] -name = "adler2" -version = "2.0.1" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" @@ -44,40 +44,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" dependencies = [ "anstyle", - "unicode-width 0.2.1", + "unicode-width 0.2.0", ] [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", + "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", ] [[package]] @@ -91,15 +91,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bstr" -version = "1.12.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "regex-automata", @@ -108,15 +108,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "camino" -version = "1.1.10" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.27" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" @@ -189,9 +189,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "num-traits", ] @@ -270,32 +270,32 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.1", + "unicode-width 0.2.0", ] [[package]] name = "color-eyre" -version = "0.6.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "color-spantrace", "eyre", "indenter", "once_cell", - "owo-colors 4.2.1", + "owo-colors", "tracing-error", ] [[package]] name = "color-spantrace" -version = "0.3.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" dependencies = [ "once_cell", - "owo-colors 4.2.1", + "owo-colors", "tracing-core", "tracing-error", ] @@ -325,7 +325,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width 0.2.0", "windows-sys 0.59.0", ] @@ -443,7 +443,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -471,9 +471,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -538,20 +538,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", @@ -561,9 +561,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" @@ -718,7 +718,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.1", + "unicode-width 0.2.0", "web-time", ] @@ -762,7 +762,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.2", "libc", ] @@ -790,15 +790,15 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libffi" -version = "4.1.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838" +checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074" dependencies = [ "libc", "libffi-sys", @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "3.3.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3" +checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84" dependencies = [ "cc", ] @@ -829,12 +829,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-targets", ] [[package]] @@ -884,9 +884,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" @@ -896,9 +896,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -926,9 +926,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -941,23 +941,23 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.9" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ - "adler2", + "adler", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] @@ -970,17 +970,16 @@ dependencies = [ "chrono", "chrono-tz", "colored", - "cxx", "directories", "genmc-sys", - "getrandom 0.3.3", + "getrandom 0.3.2", "ipc-channel", "libc", "libffi", "libloading", "measureme", "nix", - "rand 0.9.1", + "rand 0.9.0", "regex", "rustc_version", "serde", @@ -1020,9 +1019,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.7" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -1063,12 +1062,6 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" -[[package]] -name = "owo-colors" -version = "4.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" - [[package]] name = "pad" version = "0.1.6" @@ -1080,9 +1073,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1090,15 +1083,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1177,9 +1170,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "potential_utf" @@ -1205,15 +1198,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "owo-colors 3.5.0", + "owo-colors", "pad", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -1229,9 +1222,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.3.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "rand" @@ -1246,12 +1239,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", + "zerocopy", ] [[package]] @@ -1280,7 +1274,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.15", ] [[package]] @@ -1289,14 +1283,14 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.2", ] [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags", ] @@ -1307,7 +1301,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.15", "libredox", "thiserror 2.0.12", ] @@ -1343,9 +1337,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -1376,9 +1370,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", @@ -1475,9 +1469,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "spanned" @@ -1503,9 +1497,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.103" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -1525,12 +1519,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.20.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.2", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1587,11 +1581,12 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", + "once_cell", ] [[package]] @@ -1626,9 +1621,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -1701,9 +1696,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "url" @@ -1724,13 +1719,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.17.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.3.3", - "js-sys", - "wasm-bindgen", + "getrandom 0.3.2", ] [[package]] @@ -1753,9 +1746,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" @@ -1774,7 +1767,6 @@ checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", - "rustversion", "wasm-bindgen-macro", ] @@ -1850,7 +1842,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ "windows-core", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1863,7 +1855,7 @@ dependencies = [ "windows-interface", "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1894,7 +1886,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1904,25 +1896,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.53.2", + "windows-targets", ] [[package]] @@ -1931,30 +1923,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "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]] @@ -1963,96 +1939,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[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_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[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_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[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_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[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_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -2094,18 +2022,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index a94f985a6d..1aa1cae59f 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`. @@ -68,8 +68,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"] -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 c109b0b792..7d06dde3e3 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() { @@ -628,6 +603,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()); @@ -764,9 +740,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 811920cb63..b5e7e9d0ac 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 0805997ea4..49bcc0d30b 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -13,7 +13,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 41039d2904..56c1979485 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 c004c7bedf..95c010be2f 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 467647a646..63578912c2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -241,10 +241,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 8743db999a..c86e33e518 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,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::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; diff --git a/src/machine.rs b/src/machine.rs index 9479f0bde5..4f3dc48532 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. @@ -1146,12 +1144,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))) } @@ -1304,10 +1296,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) } @@ -1399,10 +1387,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), @@ -1464,9 +1448,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) = @@ -1503,7 +1485,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( @@ -1594,7 +1576,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, @@ -1716,7 +1697,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); } @@ -1728,7 +1708,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); } @@ -1758,7 +1737,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine, ); } - // TODO GENMC: how to handle this (if at all)? interp_ok(()) } @@ -1777,7 +1755,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 3578f15e8d..97070eb742 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 c058b1d8d7a9c3afe34a653ac6d4678a64d061c6 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 11:52:34 +0200 Subject: [PATCH 04/34] 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 1aa1cae59f..6a3d1d6543 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`. @@ -66,11 +65,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"] genmc = ["dep:genmc-sys"] -# default = ["stack-cache"] -# 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 d53d4b9993637bea7dffa0669a11a2c3d4116963 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 13:42:40 +0200 Subject: [PATCH 05/34] 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 00671fae9b0dcd6d6bbe06df914cb050cb1d2c43 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 13:55:44 +0200 Subject: [PATCH 06/34] 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 28b9640878e8e0556a620bcee2beabfeb401e6e1 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 14:32:34 +0200 Subject: [PATCH 07/34] 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 04102b2875dca9a6b8432f6b6dbd2b2439abb1a1 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 7 Jul 2025 14:41:26 +0200 Subject: [PATCH 08/34] 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 9d425a31aa74307dc48e1cf9962f05cb817258bb Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 8 Jul 2025 10:18:56 +0200 Subject: [PATCH 09/34] 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 6a3d1d6543..364f6ad1d4 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 @@ -48,6 +47,9 @@ ipc-channel = "0.19.0" serde = { version = "1.0.219", features = ["derive"] } capstone = "0.13" +[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.29.1" colored = "2" 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 49bcc0d30b..5dc103e126 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -9,7 +9,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 106722772d..42fed3a55f 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 8c0109fbd89be100d71aa9b3071bc21fa5ba91c6 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Tue, 8 Jul 2025 11:24:30 +0200 Subject: [PATCH 10/34] WIP: Temporarily patch cxx crate to debug MacOS failure. --- Cargo.lock | 12 ++++-------- genmc-sys/Cargo.toml | 3 ++- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9920b49d0..84d36c76a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -366,8 +366,7 @@ dependencies = [ [[package]] name = "cxx" version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1149bab7a5580cb267215751389597c021bfad13c0bb00c54e19559333764c" +source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" dependencies = [ "cc", "cxxbridge-cmd", @@ -395,8 +394,7 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36ac1f9a72064b1f41fd7b49a4c1b3bf33b9ccb1274874dda6d264f57c55964" +source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" dependencies = [ "clap", "codespan-reporting", @@ -409,14 +407,12 @@ dependencies = [ [[package]] name = "cxxbridge-flags" version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170c6ff5d009663866857a91ebee55b98ea4d4b34e7d7aba6dc4a4c95cc7b748" +source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" [[package]] name = "cxxbridge-macro" version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4984a142211026786011a7e79fa22faa1eca1e9cbf0e60bffecfd57fd3db88f1" +source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" dependencies = [ "indexmap", "proc-macro2", diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index 048df13d2d..da67f6562e 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -9,7 +9,8 @@ default = ["download_genmc"] download_genmc = ["dep:git2"] [dependencies] -cxx = { version = "1.0.160", features = ["c++20"] } +# cxx = { version = "1.0.160", features = ["c++20"] } +cxx = { git = "https://github.com/Patrick-6/cxx.git", rev = "e16e210970fe1a5d17e5f9651f2f1d83590586eb" } [build-dependencies] cmake = "0.1.54" From ca46c214c95616effe626364fc0f8bca11637f06 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 14:37:20 +0200 Subject: [PATCH 11/34] Undo patching cxx crate. --- Cargo.lock | 12 ++++++++---- genmc-sys/Cargo.toml | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84d36c76a7..e9920b49d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -366,7 +366,8 @@ dependencies = [ [[package]] name = "cxx" version = "1.0.160" -source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1149bab7a5580cb267215751389597c021bfad13c0bb00c54e19559333764c" dependencies = [ "cc", "cxxbridge-cmd", @@ -394,7 +395,8 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" version = "1.0.160" -source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36ac1f9a72064b1f41fd7b49a4c1b3bf33b9ccb1274874dda6d264f57c55964" dependencies = [ "clap", "codespan-reporting", @@ -407,12 +409,14 @@ dependencies = [ [[package]] name = "cxxbridge-flags" version = "1.0.160" -source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170c6ff5d009663866857a91ebee55b98ea4d4b34e7d7aba6dc4a4c95cc7b748" [[package]] name = "cxxbridge-macro" version = "1.0.160" -source = "git+https://github.com/Patrick-6/cxx.git?rev=e16e210970fe1a5d17e5f9651f2f1d83590586eb#e16e210970fe1a5d17e5f9651f2f1d83590586eb" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4984a142211026786011a7e79fa22faa1eca1e9cbf0e60bffecfd57fd3db88f1" dependencies = [ "indexmap", "proc-macro2", diff --git a/genmc-sys/Cargo.toml b/genmc-sys/Cargo.toml index da67f6562e..048df13d2d 100644 --- a/genmc-sys/Cargo.toml +++ b/genmc-sys/Cargo.toml @@ -9,8 +9,7 @@ default = ["download_genmc"] download_genmc = ["dep:git2"] [dependencies] -# cxx = { version = "1.0.160", features = ["c++20"] } -cxx = { git = "https://github.com/Patrick-6/cxx.git", rev = "e16e210970fe1a5d17e5f9651f2f1d83590586eb" } +cxx = { version = "1.0.160", features = ["c++20"] } [build-dependencies] cmake = "0.1.54" From b5c532a5b144f748207f5bd8dfe4b4e7f70d00e7 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 14:42:08 +0200 Subject: [PATCH 12/34] 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 943c44e3ec9cc0b521e8aaf70d75d74708dc2a28 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 14:56:08 +0200 Subject: [PATCH 13/34] 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 d1328d9e7772aff3f21a7e333baf9123b32d3638 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:10:35 +0200 Subject: [PATCH 14/34] 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 e9920b49d0..1ec2dc037b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -821,7 +821,6 @@ checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" dependencies = [ "cc", "libc", - "libssh2-sys", "libz-sys", "openssl-sys", "pkg-config", @@ -847,20 +846,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 8baec722f7251acfc4eeb28d64b137f7c5958c25 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:33:10 +0200 Subject: [PATCH 15/34] 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 232faa803ea014e41aa5f0598b1a801b5b672ebd Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:37:53 +0200 Subject: [PATCH 16/34] 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 364f6ad1d4..a4469aeef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,8 @@ ipc-channel = "0.19.0" serde = { version = "1.0.219", features = ["derive"] } capstone = "0.13" -[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 5dc103e126..4ccd004f6a 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -10,10 +10,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 42fed3a55f..99e114c035 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 2839dc4fe637fdf7966ed8454087bd6d8eada9ff Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 9 Jul 2025 15:40:58 +0200 Subject: [PATCH 17/34] 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 4ccd004f6a..179ad768b9 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -12,11 +12,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 99e114c035..8fccbfe5be 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 c914943917f1c7a1ae6b79280efcc5af443f78fd Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 09:43:17 +0200 Subject: [PATCH 18/34] 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 8fccbfe5be..eeb86faae0 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 9472c1993d8f21835b8ceb41f0f31143c2d31bd1 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 10:19:37 +0200 Subject: [PATCH 19/34] 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 7d06dde3e3..c20baeed96 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"); }; @@ -484,7 +478,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; @@ -598,13 +591,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=") { @@ -739,8 +728,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 { @@ -764,8 +752,5 @@ fn main() { // are async-signal-safe, as is accessing atomics //let _ = unsafe { miri::native_lib::init_sv() }; } - 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 63578912c2..af6e5e369c 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, @@ -190,7 +190,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 4f3dc48532..99d1617950 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -621,6 +621,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>, @@ -644,7 +647,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 34d1e9247e8683eba5b5ecb766c6fba06cf33813 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 14:48:59 +0200 Subject: [PATCH 20/34] 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 1ec2dc037b..17134ec582 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -528,7 +528,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 a4469aeef7..72ddac98a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ capstone = "0.13" # 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.29.1" 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 5cfc8b45730371626fe6affa163c67178754ae03 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 15:21:24 +0200 Subject: [PATCH 21/34] 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 27a81f4f592a1fcfdbcc89e2118105195ba7e785 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sat, 12 Jul 2025 15:22:07 +0200 Subject: [PATCH 22/34] 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 a8bfb1a01663be214150aa91efe0cd09d6f213fc Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sun, 13 Jul 2025 12:46:36 +0200 Subject: [PATCH 23/34] 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 5c83f129c401fa85d22ad138a4547719859d1f6c Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Sun, 13 Jul 2025 23:02:31 +0200 Subject: [PATCH 24/34] 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 29a03c5f72d541ba60ab38a130b78f18878da6e1 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 25/34] 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 72ddac98a9..a95c058b60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ ipc-channel = "0.19.0" serde = { version = "1.0.219", features = ["derive"] } capstone = "0.13" -# 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 179ad768b9..003aada681 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -9,7 +9,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 34f67f7efbed539557aef6daa01625258af7a47d Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 14:49:24 +0200 Subject: [PATCH 26/34] 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 91146cec1df45bb9726faec31e57725b0b9f0087 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 14:51:51 +0200 Subject: [PATCH 27/34] 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 a7b8597bf309bb9ae5755cb843fb99e62cc712a4 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 14:53:53 +0200 Subject: [PATCH 28/34] 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 a95c058b60..52257a17d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ serde = { version = "1.0.219", features = ["derive"] } capstone = "0.13" # 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 c20baeed96..8aee44f680 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -729,6 +729,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 003aada681..190dd3f3ed 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -12,7 +12,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 eeb86faae0..9c43918fdb 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 fb33c77405a14ced4b45841bc7867186e4a5a99e Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 15:35:27 +0200 Subject: [PATCH 29/34] 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 570a0694f1f71ccf642a4003bbdd900fdcaafa2a Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 15:39:11 +0200 Subject: [PATCH 30/34] 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 e9f3c8a2771b8dd4990717f3db9f4d562f46930b Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 16:31:00 +0200 Subject: [PATCH 31/34] 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 b4fb84f57eeae3f833b8a18e37148c72585edf5e Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 21:36:29 +0200 Subject: [PATCH 32/34] 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 8aee44f680..45c5a320fc 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -591,8 +591,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()); @@ -735,6 +733,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 e252faa2b0814d68b9e70791db7e3631089c13cf Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 21:52:12 +0200 Subject: [PATCH 33/34] 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 4adb4bca38e23f2a9a294e575f55e085ba5ee096 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Mon, 14 Jul 2025 21:53:52 +0200 Subject: [PATCH 34/34] 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: