mysten_common/
assert_reachable.rs1use once_cell::sync::Lazy;
5use std::io::Write;
6use std::path::PathBuf;
7use std::sync::Mutex;
8
9pub struct ReachableAssertion {
10 pub assertion_type: &'static str,
11 pub loc: &'static str,
12 pub msg: &'static str,
13}
14
15static REACHABLE_LOG_DIR: Lazy<Option<PathBuf>> = Lazy::new(|| {
16 std::env::var("MSIM_LOG_REACHABLE_ASSERTIONS")
17 .ok()
18 .map(PathBuf::from)
19 .filter(|p| p.is_dir())
20});
21
22static REACHABLE_LOG_FILE: Lazy<Option<Mutex<std::fs::File>>> = Lazy::new(|| {
23 let dir = REACHABLE_LOG_DIR.as_ref()?;
24 let seed = std::env::var("MSIM_TEST_SEED").unwrap_or_else(|_| "unknown".to_string());
25 let filename = format!("{}.reached", seed);
26 let path = dir.join(filename);
27 std::fs::OpenOptions::new()
28 .create(true)
29 .append(true)
30 .open(path)
31 .ok()
32 .map(Mutex::new)
33});
34
35static SOMETIMES_LOG_FILE: Lazy<Option<Mutex<std::fs::File>>> = Lazy::new(|| {
36 let dir = REACHABLE_LOG_DIR.as_ref()?;
37 let seed = std::env::var("MSIM_TEST_SEED").unwrap_or_else(|_| "unknown".to_string());
38 let filename = format!("{}.sometimes", seed);
39 let path = dir.join(filename);
40 std::fs::OpenOptions::new()
41 .create(true)
42 .append(true)
43 .open(path)
44 .ok()
45 .map(Mutex::new)
46});
47
48pub fn log_reached_assertion(loc: &'static str) {
49 if let Some(file) = REACHABLE_LOG_FILE.as_ref()
50 && let Ok(mut f) = file.lock()
51 {
52 let _ = writeln!(f, "{}", loc);
53 }
54}
55
56pub fn log_sometimes_assertion(loc: &'static str) {
57 if let Some(file) = SOMETIMES_LOG_FILE.as_ref()
58 && let Ok(mut f) = file.lock()
59 {
60 let _ = writeln!(f, "{}", loc);
61 }
62}
63
64#[macro_export]
65macro_rules! assert_reachable_simtest_impl {
66 ($assertion_type:literal, $condition:expr, $message:literal, $log_fn:path) => {{
67 use std::sync::atomic::{AtomicBool, Ordering};
68 use $crate::assert_reachable::ReachableAssertion;
69
70 const LOC: &str = concat!(file!(), ":", line!(), ":", column!());
71
72 #[used]
73 #[cfg_attr(
74 any(target_os = "linux", target_os = "android"),
75 unsafe(link_section = ".reach_points")
76 )]
77 #[cfg_attr(target_os = "macos", unsafe(link_section = "__DATA,__reach_points"))]
78 #[cfg_attr(target_os = "windows", unsafe(link_section = ".reach_points"))]
79 static RP: ReachableAssertion = ReachableAssertion {
80 assertion_type: $assertion_type,
81 loc: LOC,
82 msg: $message,
83 };
84
85 if $condition {
86 static LOGGED: AtomicBool = AtomicBool::new(false);
87 if !LOGGED.swap(true, Ordering::Relaxed) {
88 $log_fn(LOC);
89 }
90 }
91 }};
92}
93
94#[macro_export]
95macro_rules! assert_reachable_simtest {
96 ($message:literal) => {
97 $crate::assert_reachable_simtest_impl!(
98 "reachable",
99 true,
100 $message,
101 $crate::assert_reachable::log_reached_assertion
102 )
103 };
104}
105
106#[macro_export]
107macro_rules! assert_sometimes_simtest {
108 ($expr:expr, $message:literal) => {
109 $crate::assert_reachable_simtest_impl!(
110 "sometimes",
111 $expr,
112 $message,
113 $crate::assert_reachable::log_sometimes_assertion
114 )
115 };
116}