embedded_hal_fuzz/
spi.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//! ```rust
4//! use libfuzzer_sys::fuzz_target;
5//! use embedded_hal_fuzz::spi::ArbitrarySpiBus;
6//! use embedded_hal::spi::SpiBus;
7//! use arbitrary::Arbitrary;
8//!
9//! fuzz_target!(|spi: ArbitrarySpiBus<u16>| {
10//!   let mut spi = spi;
11//!   let mut read = vec![0;10];
12//!   let _ = spi.read(&mut read);
13//! });
14//! ```
15use arbitrary::Arbitrary;
16use embedded_hal::spi::{self, ErrorKind, ErrorType, SpiBus};
17
18#[derive(Debug)]
19pub struct Error {
20    kind: ErrorKind,
21}
22
23impl<'a> Arbitrary<'a> for Error {
24    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
25        use ErrorKind::*;
26        Ok(Error {
27            kind: *u.choose(&[Overrun, ModeFault, FrameFormat, ChipSelectFault, Other][..])?,
28        })
29    }
30}
31
32impl spi::Error for Error {
33    fn kind(&self) -> ErrorKind {
34        self.kind
35    }
36}
37
38impl<Word> ErrorType for ArbitrarySpiBus<Word> {
39    type Error = Error;
40}
41
42#[derive(Debug, Arbitrary)]
43enum Action {
44    TryRead,
45    ReturnError(Error),
46}
47
48/// Creates a fuzzed SpiBus, this type is intended to be constructed
49/// the arbitrary crate e.g.
50/// ```rust
51/// use arbitrary::{Arbitrary, Unstructured};
52/// use embedded_hal_fuzz::spi::ArbitrarySpiBus;
53/// let raw_fuzzed_data = &[1u8, 2, 3, 4, 5][..];
54/// let mut unstructured = Unstructured::new(raw_fuzzed_data);
55/// let spi_bus = ArbitrarySpiBus::<u8>::arbitrary(&mut unstructured);
56/// ```
57#[derive(Debug, Arbitrary)]
58pub struct ArbitrarySpiBus<Word> {
59    read_words: Vec<Word>,
60    actions: Vec<Action>,
61}
62
63impl<Word: Copy + 'static> SpiBus<Word> for ArbitrarySpiBus<Word> {
64    fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
65        match self.actions.pop() {
66            Some(Action::TryRead) => {
67                for word in words.iter_mut() {
68                    *word = self.read_words.pop().ok_or(Error {
69                        kind: ErrorKind::Other,
70                    })?;
71                }
72                Ok(())
73            }
74            Some(Action::ReturnError(error)) => Err(error),
75            None => Err(Error {
76                kind: ErrorKind::Other,
77            }),
78        }
79    }
80    fn write(&mut self, _words: &[Word]) -> Result<(), Self::Error> {
81        match self.actions.pop() {
82            Some(Action::ReturnError(error)) => Err(error),
83            _ => Ok(()),
84        }
85    }
86
87    fn transfer(&mut self, read: &mut [Word], _write: &[Word]) -> Result<(), Self::Error> {
88        self.read(read)
89    }
90    fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
91        self.read(words)
92    }
93
94    fn flush(&mut self) -> Result<(), Self::Error> {
95        match self.actions.pop() {
96            Some(Action::ReturnError(error)) => Err(error),
97            _ => Ok(()),
98        }
99    }
100}