Initial oss-fuzz integration. (#529)
Signed-off-by: davkor <david@adalogics.com>
This commit is contained in:
@@ -12,4 +12,4 @@ env_logger = { version = "0.5.3", default-features = false }
|
||||
futures = { version = "0.3", default-features = false, features = ["std"] }
|
||||
honggfuzz = "0.5"
|
||||
http = "0.2"
|
||||
tokio = "1"
|
||||
tokio = { version = "1", features = [ "full" ] }
|
||||
|
||||
@@ -1,132 +1,128 @@
|
||||
use futures::future;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::Stream;
|
||||
use http::{Method, Request};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
struct MockIo<'a> {
|
||||
input: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> MockIo<'a> {
|
||||
fn next_byte(&mut self) -> Option<u8> {
|
||||
if let Some(&c) = self.input.first() {
|
||||
self.input = &self.input[1..];
|
||||
Some(c)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
(self.next_byte().unwrap_or(0) as u32) << 8 | self.next_byte().unwrap_or(0) as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsyncRead for MockIo<'a> {
|
||||
unsafe fn prepare_uninitialized_buffer(&self, _buf: &mut [std::mem::MaybeUninit<u8>]) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let mut len = self.next_u32() as usize;
|
||||
if self.input.is_empty() {
|
||||
Poll::Ready(Ok(0))
|
||||
} else if len == 0 {
|
||||
cx.waker().clone().wake();
|
||||
Poll::Pending
|
||||
} else {
|
||||
if len > self.input.len() {
|
||||
len = self.input.len();
|
||||
}
|
||||
|
||||
if len > buf.len() {
|
||||
len = buf.len();
|
||||
}
|
||||
buf[0..len].copy_from_slice(&self.input[0..len]);
|
||||
self.input = &self.input[len..];
|
||||
Poll::Ready(Ok(len))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsyncWrite for MockIo<'a> {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let len = std::cmp::min(self.next_u32() as usize, buf.len());
|
||||
if len == 0 {
|
||||
if self.input.is_empty() {
|
||||
Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
|
||||
} else {
|
||||
cx.waker().clone().wake();
|
||||
Poll::Pending
|
||||
}
|
||||
} else {
|
||||
Poll::Ready(Ok(len))
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(script: &[u8]) -> Result<(), h2::Error> {
|
||||
let io = MockIo { input: script };
|
||||
let (mut h2, mut connection) = h2::client::handshake(io).await?;
|
||||
let mut futs = FuturesUnordered::new();
|
||||
let future = future::poll_fn(|cx| {
|
||||
if let Poll::Ready(()) = Pin::new(&mut connection).poll(cx)? {
|
||||
return Poll::Ready(Ok::<_, h2::Error>(()));
|
||||
}
|
||||
while futs.len() < 128 {
|
||||
if !h2.poll_ready(cx)?.is_ready() {
|
||||
break;
|
||||
}
|
||||
let request = Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("https://example.com/")
|
||||
.body(())
|
||||
.unwrap();
|
||||
let (resp, mut send) = h2.send_request(request, false)?;
|
||||
send.send_data(vec![0u8; 32769].into(), true).unwrap();
|
||||
drop(send);
|
||||
futs.push(resp);
|
||||
}
|
||||
loop {
|
||||
match Pin::new(&mut futs).poll_next(cx) {
|
||||
Poll::Pending | Poll::Ready(None) => break,
|
||||
r @ Poll::Ready(Some(Ok(_))) | r @ Poll::Ready(Some(Err(_))) => {
|
||||
eprintln!("{:?}", r);
|
||||
}
|
||||
}
|
||||
}
|
||||
Poll::Pending
|
||||
});
|
||||
future.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
loop {
|
||||
honggfuzz::fuzz!(|data: &[u8]| {
|
||||
eprintln!("{:?}", rt.block_on(run(data)));
|
||||
});
|
||||
}
|
||||
}
|
||||
use futures::future;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::Stream;
|
||||
use http::{Method, Request};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
|
||||
struct MockIo<'a> {
|
||||
input: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> MockIo<'a> {
|
||||
fn next_byte(&mut self) -> Option<u8> {
|
||||
if let Some(&c) = self.input.first() {
|
||||
self.input = &self.input[1..];
|
||||
Some(c)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
(self.next_byte().unwrap_or(0) as u32) << 8 | self.next_byte().unwrap_or(0) as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsyncRead for MockIo<'a> {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf,
|
||||
) -> Poll<io::Result<()>> {
|
||||
let mut len = self.next_u32() as usize;
|
||||
if self.input.is_empty() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if len == 0 {
|
||||
cx.waker().clone().wake();
|
||||
Poll::Pending
|
||||
} else {
|
||||
if len > self.input.len() {
|
||||
len = self.input.len();
|
||||
}
|
||||
|
||||
if len > buf.remaining() {
|
||||
len = buf.remaining();
|
||||
}
|
||||
buf.put_slice(&self.input[len..]);
|
||||
self.input = &self.input[len..];
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsyncWrite for MockIo<'a> {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let len = std::cmp::min(self.next_u32() as usize, buf.len());
|
||||
if len == 0 {
|
||||
if self.input.is_empty() {
|
||||
Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
|
||||
} else {
|
||||
cx.waker().clone().wake();
|
||||
Poll::Pending
|
||||
}
|
||||
} else {
|
||||
Poll::Ready(Ok(len))
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(script: &[u8]) -> Result<(), h2::Error> {
|
||||
let io = MockIo { input: script };
|
||||
let (mut h2, mut connection) = h2::client::handshake(io).await?;
|
||||
let mut futs = FuturesUnordered::new();
|
||||
let future = future::poll_fn(|cx| {
|
||||
if let Poll::Ready(()) = Pin::new(&mut connection).poll(cx)? {
|
||||
return Poll::Ready(Ok::<_, h2::Error>(()));
|
||||
}
|
||||
while futs.len() < 128 {
|
||||
if !h2.poll_ready(cx)?.is_ready() {
|
||||
break;
|
||||
}
|
||||
let request = Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("https://example.com/")
|
||||
.body(())
|
||||
.unwrap();
|
||||
let (resp, mut send) = h2.send_request(request, false)?;
|
||||
send.send_data(vec![0u8; 32769].into(), true).unwrap();
|
||||
drop(send);
|
||||
futs.push(resp);
|
||||
}
|
||||
loop {
|
||||
match Pin::new(&mut futs).poll_next(cx) {
|
||||
Poll::Pending | Poll::Ready(None) => break,
|
||||
r @ Poll::Ready(Some(Ok(_))) | r @ Poll::Ready(Some(Err(_))) => {
|
||||
eprintln!("{:?}", r);
|
||||
}
|
||||
}
|
||||
}
|
||||
Poll::Pending
|
||||
});
|
||||
future.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
loop {
|
||||
honggfuzz::fuzz!(|data: &[u8]| {
|
||||
eprintln!("{:?}", rt.block_on(run(data)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user