/src/h2/fuzz/fuzz_targets/fuzz_e2e.rs
Line | Count | Source (jump to first uncovered line) |
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 | 4.22M | fn next_byte(&mut self) -> Option<u8> { |
20 | 4.22M | if let Some(&c) = self.input.first() { |
21 | 4.19M | self.input = &self.input[1..]; |
22 | 4.19M | Some(c) |
23 | | } else { |
24 | 29.1k | None |
25 | | } |
26 | 4.22M | } |
27 | | |
28 | 2.11M | fn next_u32(&mut self) -> u32 { |
29 | 2.11M | (self.next_byte().unwrap_or(0) as u32) << 8 | self.next_byte().unwrap_or(0) as u32 |
30 | 2.11M | } |
31 | | } |
32 | | |
33 | | impl<'a> AsyncRead for MockIo<'a> { |
34 | 1.02M | fn poll_read( |
35 | 1.02M | mut self: Pin<&mut Self>, |
36 | 1.02M | cx: &mut Context<'_>, |
37 | 1.02M | buf: &mut ReadBuf, |
38 | 1.02M | ) -> Poll<io::Result<()>> { |
39 | 1.02M | |
40 | 1.02M | |
41 | 1.02M | let mut len = self.next_u32() as usize; |
42 | 1.02M | if self.input.is_empty() { |
43 | 4.96k | Poll::Ready(Ok(())) |
44 | 1.02M | } else if len == 0 { |
45 | 1.00M | cx.waker().clone().wake(); |
46 | 1.00M | Poll::Pending |
47 | | } else { |
48 | 17.3k | if len > self.input.len() { |
49 | 10.1k | len = self.input.len(); |
50 | 10.1k | } |
51 | | |
52 | 17.3k | if len > buf.remaining() { |
53 | 765 | len = buf.remaining(); |
54 | 16.5k | } |
55 | 17.3k | buf.put_slice(&self.input[..len]); |
56 | 17.3k | self.input = &self.input[len..]; |
57 | 17.3k | Poll::Ready(Ok(())) |
58 | | } |
59 | 1.02M | } |
60 | | } |
61 | | |
62 | | impl<'a> AsyncWrite for MockIo<'a> { |
63 | 1.08M | fn poll_write( |
64 | 1.08M | mut self: Pin<&mut Self>, |
65 | 1.08M | cx: &mut Context<'_>, |
66 | 1.08M | buf: &[u8], |
67 | 1.08M | ) -> Poll<io::Result<usize>> { |
68 | 1.08M | let len = std::cmp::min(self.next_u32() as usize, buf.len()); |
69 | 1.08M | if len == 0 { |
70 | 1.06M | if self.input.is_empty() { |
71 | 9.57k | Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())) |
72 | | } else { |
73 | 1.05M | cx.waker().clone().wake(); |
74 | 1.05M | Poll::Pending |
75 | | } |
76 | | } else { |
77 | 22.8k | Poll::Ready(Ok(len)) |
78 | | } |
79 | 1.08M | } |
80 | | |
81 | 24.9k | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { |
82 | 24.9k | Poll::Ready(Ok(())) |
83 | 24.9k | } |
84 | 895 | fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> { |
85 | 895 | Poll::Ready(Ok(())) |
86 | 895 | } |
87 | | } |
88 | | |
89 | 11.6k | async fn run(script: &[u8]) -> Result<(), h2::Error> { |
90 | 11.6k | let io = MockIo { input: script }; |
91 | 57.1k | let (mut h2, mut connection) = h2::client::handshake(io).await?; |
92 | 11.6k | let mut futs = FuturesUnordered::new(); |
93 | 1.02M | let future = future::poll_fn(|cx| { |
94 | 1.02M | if let Poll::Ready(()) = Pin::new(&mut connection).poll(cx)? { |
95 | 689 | return Poll::Ready(Ok::<_, h2::Error>(())); |
96 | 1.01M | } |
97 | 1.42M | while futs.len() < 128 { |
98 | 425k | if !h2.poll_ready(cx)?.is_ready() { |
99 | 11.5k | break; |
100 | 413k | } |
101 | 413k | let request = Request::builder() |
102 | 413k | .method(Method::POST) |
103 | 413k | .uri("https://example.com/") |
104 | 413k | .body(()) |
105 | 413k | .unwrap(); |
106 | 413k | let (resp, mut send) = h2.send_request(request, false)?; |
107 | 413k | send.send_data(vec![0u8; 32769].into(), true).unwrap(); |
108 | 413k | drop(send); |
109 | 413k | futs.push(resp); |
110 | | } |
111 | | loop { |
112 | 1.04M | match Pin::new(&mut futs).poll_next(cx) { |
113 | 1.01M | Poll::Pending | Poll::Ready(None) => break, |
114 | 29.4k | r @ Poll::Ready(Some(Ok(_))) | r @ Poll::Ready(Some(Err(_))) => { |
115 | 29.4k | eprintln!("{:?}", r); |
116 | 29.4k | } |
117 | | } |
118 | | } |
119 | 1.01M | Poll::Pending |
120 | 1.02M | }); |
121 | 1.01M | future.await?; |
122 | 689 | Ok(()) |
123 | 11.6k | } |
124 | | |
125 | | fuzz_target!(|data: &[u8]| { |
126 | | let rt = tokio::runtime::Runtime::new().unwrap(); |
127 | | let _res = rt.block_on(run(data)); |
128 | | }); |
129 | | |