Created
September 28, 2024 09:48
-
-
Save ProgramCrafter/3c0c47d8818d4a820a3d9cb7ab02f8e2 to your computer and use it in GitHub Desktop.
No-UB debugging for Rust script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::mem::*; | |
use std::ptr::read_unaligned; | |
use std::sync::atomic::*; | |
use std::thread::*; | |
use std::time::*; | |
#[cfg(windows)] | |
mod our_mem { | |
use windows::prelude::*; | |
pub unsafe fn read_threadsafe(base: *const u8, cap: usize) -> Vec<u8> { | |
let our_process = GetCurrentProcess(); | |
let mut buffer = Vec::with_capacity(cap); | |
let mut read = 0; | |
let result = ReadProcessMemory(our_process, base, buffer.as_mut_ptr(), cap, &mut read); | |
buffer.set_len(read); | |
buffer | |
} | |
} | |
#[cfg(unix)] | |
mod our_mem { | |
use libc::*; | |
pub unsafe fn read_threadsafe(base: *const u8, cap: usize) -> Vec<u8> { | |
let mut buffer = Vec::<u8>::with_capacity(cap); | |
let our_process = getpid(); | |
let read = iovec { | |
iov_base: base as *mut c_void, | |
iov_len: cap, | |
}; | |
let write = iovec { | |
iov_base: buffer.as_mut_ptr().cast(), | |
iov_len: cap, | |
}; | |
let have_read = process_vm_readv( | |
our_process, | |
&write as *const iovec, | |
1, | |
&read as *const iovec, | |
1, | |
0, | |
); | |
assert!(have_read >= 0); | |
buffer.set_len(have_read as usize); | |
println!("have_read={have_read} buffer={buffer:?}"); | |
buffer | |
} | |
} | |
unsafe fn read_interpret<T>(ptr: *const T) -> ManuallyDrop<T> { | |
let base = ptr.cast(); | |
let content = our_mem::read_threadsafe(base, size_of::<T>()); | |
assert_eq!(content.len(), size_of::<T>()); | |
let data_start: *const u8 = content.as_ptr(); | |
read_unaligned(data_start as *const ManuallyDrop<T>) | |
} | |
fn main() { | |
let u: AtomicPtr<String> = AtomicPtr::new(std::ptr::null_mut()); | |
scope(|spawner| { | |
let str_producer = spawner.spawn(|| { | |
let mut s = Box::new(String::new()); | |
let v = s.as_mut() as *mut String; | |
u.store(v, Ordering::SeqCst); | |
for i in 0..80 { | |
s.push((i + 40) as u8 as char); | |
for j in 100..120 { | |
s.push_str(&format!("{}", j - i)); | |
} | |
let a = std::hint::black_box(&s); | |
compiler_fence(Ordering::SeqCst); | |
let _a = a; | |
sleep(Duration::from_millis(20)); | |
} | |
s | |
}); | |
let str_consumer = spawner.spawn(|| { | |
sleep(Duration::from_millis(760)); | |
let s_content: String = unsafe { | |
let s_obj: ManuallyDrop<String> = read_interpret(u.load(Ordering::SeqCst)); | |
s_obj.as_str().to_owned() | |
}; | |
println!("s_content: {s_content:?}"); | |
}); | |
let mut v = std::hint::black_box(str_producer.join()); | |
// now, the string MUST be calculated | |
match &mut v { | |
Ok(w) => {w.truncate(20)}, _ => {} | |
}; | |
println!("{v:?}"); | |
let _ = str_consumer.join(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment