embedded_hal_fuzz/
i2c.rs

1//! To make use of this module you can simply pass
2//! this in as a value from the fuzz_target macro e.g.
3//!
4//! # Example
5//!
6//! ```rust
7//! use libfuzzer_sys::fuzz_target;
8//! use embedded_hal_fuzz::i2c::ArbitraryI2c;
9//! use embedded_hal::i2c::{I2c, SevenBitAddress, TenBitAddress};
10//!
11//! fuzz_target!(|i2c: ArbitraryI2c<SevenBitAddress>| {
12//!   let mut i2c = i2c;
13//!   let mut read = vec![0;10];
14//!   let _ = i2c.read(1, &mut read);
15//! });
16//! ```
17
18use arbitrary::Arbitrary;
19use embedded_hal::i2c::{
20    self, ErrorKind, I2c, NoAcknowledgeSource, Operation, SevenBitAddress, TenBitAddress,
21};
22use std::marker::PhantomData;
23
24#[derive(Debug)]
25pub struct Error {
26    kind: ErrorKind,
27}
28
29impl Default for Error {
30    fn default() -> Self {
31        Error {
32            kind: ErrorKind::Other,
33        }
34    }
35}
36
37impl i2c::Error for Error {
38    fn kind(&self) -> ErrorKind {
39        self.kind
40    }
41}
42
43impl<'a> Arbitrary<'a> for Error {
44    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
45        use ErrorKind::*;
46        use NoAcknowledgeSource::*;
47        Ok(Error {
48            kind: *u.choose(&[
49                Bus,
50                ArbitrationLoss,
51                NoAcknowledge(Address),
52                NoAcknowledge(Data),
53                NoAcknowledge(Unknown),
54                Overrun,
55                Other,
56            ])?,
57        })
58    }
59}
60
61/// Creates a fuzzed i2c driver, this type is intended to be constructed
62/// the arbitrary crate e.g.
63/// ```rust
64/// use arbitrary::{Arbitrary, Unstructured};
65/// use embedded_hal_fuzz::i2c::ArbitraryI2c;
66/// use embedded_hal::i2c::{SevenBitAddress, TenBitAddress};
67/// let raw_fuzzed_data = &[1u8, 2, 3, 4, 5][..];
68/// let mut unstructured = Unstructured::new(raw_fuzzed_data);
69/// let seven_bit_spi_bus = ArbitraryI2c::<SevenBitAddress>::arbitrary(&mut unstructured);
70/// let ten_bit_spi_bus = ArbitraryI2c::<TenBitAddress>::arbitrary(&mut unstructured);
71/// ```
72#[derive(Debug, Arbitrary)]
73pub struct ArbitraryI2c<T> {
74    read_data: Vec<u8>,
75    maybe_error: Vec<Result<(), Error>>,
76    _p: PhantomData<T>,
77}
78
79impl<T> ArbitraryI2c<T> {
80    fn transaction_impl(&mut self, operations: &mut [Operation<'_>]) -> Result<(), Error> {
81        self.maybe_error.pop().ok_or(Error::default())??;
82        let operation_result: Result<Vec<_>, _> = operations
83            .iter_mut()
84            .map(|x| match x {
85                Operation::Read(read) => {
86                    let result: Result<Vec<_>, Error> = read
87                        .iter_mut()
88                        .map(|x| {
89                            *x = self.read_data.pop().ok_or(Error::default())?;
90                            Ok(())
91                        })
92                        .collect();
93                    result
94                }
95                Operation::Write(_) => Ok(Vec::new()),
96            })
97            .collect();
98        operation_result.map(|_| ())
99    }
100}
101
102impl<T> i2c::ErrorType for ArbitraryI2c<T> {
103    type Error = Error;
104}
105
106impl I2c<SevenBitAddress> for ArbitraryI2c<SevenBitAddress> {
107    fn transaction(
108        &mut self,
109        _address: u8,
110        operations: &mut [Operation<'_>],
111    ) -> Result<(), Self::Error> {
112        self.transaction_impl(operations)
113    }
114}
115
116impl I2c<TenBitAddress> for ArbitraryI2c<TenBitAddress> {
117    fn transaction(
118        &mut self,
119        _address: u16,
120        operations: &mut [Operation<'_>],
121    ) -> Result<(), Self::Error> {
122        self.transaction_impl(operations)
123    }
124}