Coverage Report

Created: 2026-02-11 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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.74M
    fn next_byte(&mut self) -> Option<u8> {
20
6.74M
        if let Some(&c) = self.input.first() {
21
6.71M
            self.input = &self.input[1..];
22
6.71M
            Some(c)
23
        } else {
24
33.4k
            None
25
        }
26
6.74M
    }
27
28
3.37M
    fn next_u32(&mut self) -> u32 {
29
3.37M
        (self.next_byte().unwrap_or(0) as u32) << 8 | self.next_byte().unwrap_or(0) as u32
30
3.37M
    }
31
}
32
33
impl<'a> AsyncRead for MockIo<'a> {
34
1.85M
    fn poll_read(
35
1.85M
        mut self: Pin<&mut Self>,
36
1.85M
        cx: &mut Context<'_>,
37
1.85M
        buf: &mut ReadBuf,
38
1.85M
    ) -> Poll<io::Result<()>> {
39
40
41
1.85M
        let mut len = self.next_u32() as usize;
42
1.85M
        if self.input.is_empty() {
43
5.77k
            Poll::Ready(Ok(()))
44
1.84M
        } else if len == 0 {
45
1.82M
            cx.waker().clone().wake();
46
1.82M
            Poll::Pending
47
        } else {
48
19.2k
            if len > self.input.len() {
49
11.4k
                len = self.input.len();
50
11.4k
            }
51
52
19.2k
            if len > buf.remaining() {
53
491
                len = buf.remaining();
54
18.7k
            }
55
19.2k
            buf.put_slice(&self.input[..len]);
56
19.2k
            self.input = &self.input[len..];
57
19.2k
            Poll::Ready(Ok(()))
58
        }
59
1.85M
    }
60
}
61
62
impl<'a> AsyncWrite for MockIo<'a> {
63
1.52M
    fn poll_write(
64
1.52M
        mut self: Pin<&mut Self>,
65
1.52M
        cx: &mut Context<'_>,
66
1.52M
        buf: &[u8],
67
1.52M
    ) -> Poll<io::Result<usize>> {
68
1.52M
        let len = std::cmp::min(self.next_u32() as usize, buf.len());
69
1.52M
        if len == 0 {
70
1.49M
            if self.input.is_empty() {
71
10.8k
                Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
72
            } else {
73
1.48M
                cx.waker().clone().wake();
74
1.48M
                Poll::Pending
75
            }
76
        } else {
77
26.3k
            Poll::Ready(Ok(len))
78
        }
79
1.52M
    }
80
81
945k
    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
82
945k
        Poll::Ready(Ok(()))
83
945k
    }
84
1.14k
    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
85
1.14k
        Poll::Ready(Ok(()))
86
1.14k
    }
87
}
88
89
13.0k
async fn run(script: &[u8]) -> Result<(), h2::Error> {
90
13.0k
    let io = MockIo { input: script };
91
13.0k
    let (mut h2, mut connection) = h2::client::handshake(io).await?;
92
13.0k
    let mut futs = FuturesUnordered::new();
93
1.86M
    let future = future::poll_fn(|cx| {
94
1.86M
        if let Poll::Ready(()) = Pin::new(&mut connection).poll(cx)? {
95
883
            return Poll::Ready(Ok::<_, h2::Error>(()));
96
1.85M
        }
97
2.30M
        while futs.len() < 128 {
98
454k
            if !h2.poll_ready(cx)?.is_ready() {
99
1.87k
                break;
100
452k
            }
101
452k
            let request = Request::builder()
102
452k
                .method(Method::POST)
103
452k
                .uri("https://example.com/")
104
452k
                .body(())
105
452k
                .unwrap();
106
452k
            let (resp, mut send) = h2.send_request(request, false)?;
107
452k
            send.send_data(vec![0u8; 32769].into(), true).unwrap();
108
452k
            drop(send);
109
452k
            futs.push(resp);
110
        }
111
        loop {
112
1.89M
            match Pin::new(&mut futs).poll_next(cx) {
113
1.85M
                Poll::Pending | Poll::Ready(None) => break,
114
38.3k
                r @ Poll::Ready(Some(Ok(_))) | r @ Poll::Ready(Some(Err(_))) => {
115
38.3k
                    eprintln!("{:?}", r);
116
38.3k
                }
117
            }
118
        }
119
1.85M
        Poll::Pending
120
1.86M
    });
121
13.0k
    future.await?;
122
883
    Ok(())
123
13.0k
}
124
125
fuzz_target!(|data: &[u8]| {
126
    let rt = tokio::runtime::Runtime::new().unwrap();
127
    let _res = rt.block_on(run(data));
128
});
129