1 // SPDX-License-Identifier: Apache-2.0 2 3 use std::fs::File; 4 use std::io::Read; 5 use std::io::Write; 6 use std::os::raw::c_int; 7 use std::os::unix::io::{FromRawFd, RawFd}; 8 9 use ciborium::{de::from_reader, value::Value}; 10 use rand::Rng; 11 12 const ITERATIONS: usize = 128 * 1024; 13 14 #[allow(non_camel_case_types)] 15 type pid_t = i32; 16 17 extern "C" { close(fd: RawFd) -> c_int18 fn close(fd: RawFd) -> c_int; fork() -> pid_t19 fn fork() -> pid_t; pipe(pipefd: &mut [RawFd; 2]) -> c_int20 fn pipe(pipefd: &mut [RawFd; 2]) -> c_int; waitpid(pid: pid_t, wstatus: *mut c_int, options: c_int) -> pid_t21 fn waitpid(pid: pid_t, wstatus: *mut c_int, options: c_int) -> pid_t; 22 } 23 24 #[test] fuzz()25 fn fuzz() { 26 let mut fds: [RawFd; 2] = [0; 2]; 27 assert_eq!(unsafe { pipe(&mut fds) }, 0); 28 29 let pid = unsafe { fork() }; 30 assert!(pid >= 0); 31 32 match pid { 33 0 => { 34 let mut child = unsafe { File::from_raw_fd(fds[1]) }; 35 unsafe { close(fds[0]) }; 36 37 let mut rng = rand::thread_rng(); 38 let mut buffer = [0u8; 32]; 39 40 for _ in 0..ITERATIONS { 41 let len = rng.gen_range(0..buffer.len()); 42 rng.fill(&mut buffer[..len]); 43 44 writeln!(child, "{}", hex::encode(&buffer[..len])).unwrap(); 45 writeln!(child, "{:?}", from_reader::<Value, _>(&buffer[..len])).unwrap(); 46 } 47 } 48 49 pid => { 50 let mut parent = unsafe { File::from_raw_fd(fds[0]) }; 51 unsafe { close(fds[1]) }; 52 53 let mut string = String::new(); 54 parent.read_to_string(&mut string).unwrap(); 55 eprint!("{}", string); 56 57 let mut status = 0; 58 assert_eq!(pid, unsafe { waitpid(pid, &mut status, 0) }); 59 60 eprintln!("exit status: {:?}", status); 61 assert_eq!(0, status); 62 } 63 } 64 } 65