/src/h2/fuzz/fuzz_targets/fuzz_e2e.rs
Line | Count | Source |
1 | | #![no_main] |
2 | | use libfuzzer_sys::fuzz_target; |
3 | | |
4 | | use futures::future; |
5 | | use futures::stream::FuturesUnordered; |
6 | | use futures::Stream; |
7 | | use http::{Method, Request}; |
8 | | use std::future::Future; |
9 | | use std::io; |
10 | | use std::pin::Pin; |
11 | | use std::task::{Context, Poll}; |
12 | | use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; |
13 | | |
14 | | struct MockIo<'a> { |
15 | | input: &'a [u8], |
16 | | } |
17 | | |
18 | | impl<'a> MockIo<'a> { |
19 | 6.84M | fn next_byte(&mut self) -> Option<u8> { |
20 | 6.84M | if let Some(&c) = self.input.first() { |
21 | 6.81M | self.input = &self.input[1..]; |
22 | 6.81M | Some(c) |
23 | | } else { |
24 | 32.1k | None |
25 | | } |
26 | 6.84M | } |
27 | | |
28 | 3.42M | fn next_u32(&mut self) -> u32 { |
29 | 3.42M | (self.next_byte().unwrap_or(0) as u32) << 8 | self.next_byte().unwrap_or(0) as u32 |
30 | 3.42M | } |
31 | | } |
32 | | |
33 | | impl<'a> AsyncRead for MockIo<'a> { |
34 | 2.86M | fn poll_read( |
35 | 2.86M | mut self: Pin<&mut Self>, |
36 | 2.86M | cx: &mut Context<'_>, |
37 | 2.86M | buf: &mut ReadBuf, |
38 | 2.86M | ) -> Poll<io::Result<()>> { |
39 | | |
40 | | |
41 | 2.86M | let mut len = self.next_u32() as usize; |
42 | 2.86M | if self.input.is_empty() { |
43 | 5.56k | Poll::Ready(Ok(())) |
44 | 2.86M | } else if len == 0 { |
45 | 2.84M | cx.waker().clone().wake(); |
46 | 2.84M | Poll::Pending |
47 | | } else { |
48 | 18.5k | if len > self.input.len() { |
49 | 10.9k | len = self.input.len(); |
50 | 10.9k | } |
51 | | |
52 | 18.5k | if len > buf.remaining() { |
53 | 590 | len = buf.remaining(); |
54 | 17.9k | } |
55 | 18.5k | buf.put_slice(&self.input[..len]); |
56 | 18.5k | self.input = &self.input[len..]; |
57 | 18.5k | Poll::Ready(Ok(())) |
58 | | } |
59 | 2.86M | } |
60 | | } |
61 | | |
62 | | impl<'a> AsyncWrite for MockIo<'a> { |
63 | 557k | fn poll_write( |
64 | 557k | mut self: Pin<&mut Self>, |
65 | 557k | cx: &mut Context<'_>, |
66 | 557k | buf: &[u8], |
67 | 557k | ) -> Poll<io::Result<usize>> { |
68 | 557k | let len = std::cmp::min(self.next_u32() as usize, buf.len()); |
69 | 557k | if len == 0 { |
70 | 534k | if self.input.is_empty() { |
71 | 10.4k | Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())) |
72 | | } else { |
73 | 523k | cx.waker().clone().wake(); |
74 | 523k | Poll::Pending |
75 | | } |
76 | | } else { |
77 | 23.4k | Poll::Ready(Ok(len)) |
78 | | } |
79 | 557k | } |
80 | | |
81 | 2.35M | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { |
82 | 2.35M | Poll::Ready(Ok(())) |
83 | 2.35M | } |
84 | 1.05k | fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { |
85 | 1.05k | Poll::Ready(Ok(())) |
86 | 1.05k | } |
87 | | } |
88 | | |
89 | 12.4k | async fn run(script: &[u8]) -> Result<(), h2::Error> { |
90 | 12.4k | let io = MockIo { input: script }; |
91 | 12.4k | let (mut h2, mut connection) = h2::client::handshake(io).await?; |
92 | 12.4k | let mut futs = FuturesUnordered::new(); |
93 | 2.85M | let future = future::poll_fn(|cx| { |
94 | 2.85M | if let Poll::Ready(()) = Pin::new(&mut connection).poll(cx)? { |
95 | 842 | return Poll::Ready(Ok::<_, h2::Error>(())); |
96 | 2.84M | } |
97 | 3.26M | while futs.len() < 128 { |
98 | 422k | if !h2.poll_ready(cx)?.is_ready() { |
99 | 1.90k | break; |
100 | 420k | } |
101 | 420k | let request = Request::builder() |
102 | 420k | .method(Method::POST) |
103 | 420k | .uri("https://example.com/") |
104 | 420k | .body(()) |
105 | 420k | .unwrap(); |
106 | 420k | let (resp, mut send) = h2.send_request(request, false)?; |
107 | 420k | send.send_data(vec![0u8; 32769].into(), true).unwrap(); |
108 | 420k | drop(send); |
109 | 420k | futs.push(resp); |
110 | | } |
111 | | loop { |
112 | 2.87M | match Pin::new(&mut futs).poll_next(cx) { |
113 | 2.84M | Poll::Pending | Poll::Ready(None) => break, |
114 | 33.0k | r @ Poll::Ready(Some(Ok(_))) | r @ Poll::Ready(Some(Err(_))) => { |
115 | 33.0k | eprintln!("{:?}", r); |
116 | 33.0k | } |
117 | | } |
118 | | } |
119 | 2.84M | Poll::Pending |
120 | 2.85M | }); |
121 | 12.4k | future.await?; |
122 | 842 | Ok(()) |
123 | 12.4k | } |
124 | | |
125 | | fuzz_target!(|data: &[u8]| { |
126 | | let rt = tokio::runtime::Runtime::new().unwrap(); |
127 | | let _res = rt.block_on(run(data)); |
128 | | }); |
129 | | |