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