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