Skip to content

Instantly share code, notes, and snippets.

@ProgramCrafter
Created September 28, 2024 09:48
Show Gist options
  • Save ProgramCrafter/3c0c47d8818d4a820a3d9cb7ab02f8e2 to your computer and use it in GitHub Desktop.
Save ProgramCrafter/3c0c47d8818d4a820a3d9cb7ab02f8e2 to your computer and use it in GitHub Desktop.
No-UB debugging for Rust script
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