1// SPDX-License-Identifier: Apache-2.0
2
3use std::fs::File;
4use std::io::Read;
5use std::io::Write;
6use std::os::raw::c_int;
7use std::os::unix::io::{FromRawFd, RawFd};
8
9use ciborium::{de::from_reader, value::Value};
10use rand::Rng;
11
12const ITERATIONS: usize = 128 * 1024;
13
14#[allow(non_camel_case_types)]
15type pid_t = i32;
16
17extern "C" {
18 fn close(fd: RawFd) -> c_int;
19 fn fork() -> pid_t;
20 fn pipe(pipefd: &mut [RawFd; 2]) -> c_int;
21 fn waitpid(pid: pid_t, wstatus: *mut c_int, options: c_int) -> pid_t;
22}
23
24#[test]
25fn 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