feat!: protocol v2 wire format and module restructure
The wire protocol is re-specified as DongLoRa Protocol v2 (see PROTOCOL.md). Every type_id, tag-correlation rule, and field layout is incompatible with 0.1.0. * Add PROTOCOL.md as the normative spec for the v2 wire format. * Replace framing.rs with a streaming FrameDecoder that emits (type_id, tag, payload) triples on each COBS-delimited, CRC-checked frame. * Split the single-file lib.rs into dedicated modules: frame, commands, events, errors, modulation, info, crc, chip_id. Re-exports preserve convenience imports at the crate root. * Replace RadioConfig / Bandwidth with a Modulation enum covering LoRa, FSK/GFSK, LR-FHSS, and FLRC, each with its own typed parameter struct. * Add TxFlags, RxOrigin, SetConfigResult, OkPayload to model v2 response shapes, and RadioChipId for GET_INFO. * Rewrite fuzz corpus: replace the 4 cobs_* / command_roundtrip targets with decoder_feed, frame_roundtrip, lora_config_roundtrip, and parse_device_message; drop parse_radio_config. * Expand proptest and mutation-killer coverage for the new wire shape. * Rewrite canonical-byte test vectors against the v2 spec.
This commit is contained in:
29 files changed
+7115
-2285
No files matched your search
@@ -1,41 +0,0 @@
|
||||
//! Chunk-boundary invariance: the same input stream fed into two
|
||||
//! decoders — one in arbitrary chunks, one all-at-once — must produce
|
||||
//! the same command sequence.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use donglora_protocol::Command;
|
||||
use donglora_protocol::framing::CobsDecoder;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fn drain(stream: &[u8], chunk_sched: &[u8]) -> Vec<Command> {
|
||||
let mut out: Vec<Command> = Vec::new();
|
||||
let mut decoder = CobsDecoder::new();
|
||||
let mut cursor = 0;
|
||||
let mut idx = 0;
|
||||
while cursor < stream.len() {
|
||||
let split = if idx < chunk_sched.len() {
|
||||
((chunk_sched[idx] as usize) % 64) + 1
|
||||
} else {
|
||||
16
|
||||
};
|
||||
idx += 1;
|
||||
let end = (cursor + split).min(stream.len());
|
||||
decoder.feed(&stream[cursor..end], |c| out.push(c));
|
||||
cursor = end;
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let split = 32.min(data.len());
|
||||
let (sched, stream) = data.split_at(split);
|
||||
|
||||
let whole: Vec<Command> = {
|
||||
let mut v = Vec::new();
|
||||
CobsDecoder::new().feed(stream, |c| v.push(c));
|
||||
v
|
||||
};
|
||||
let chunked = drain(stream, sched);
|
||||
assert_eq!(whole, chunked);
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
//! `CobsDecoder::feed` must never panic or yield an oversized payload
|
||||
//! when fed arbitrary bytes in arbitrary chunks.
|
||||
//!
|
||||
//! The input is split into chunks driven by a leading length-prefix
|
||||
//! stream so the fuzzer can exercise boundary handling.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use donglora_protocol::MAX_PAYLOAD;
|
||||
use donglora_protocol::framing::CobsDecoder;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let mut decoder = CobsDecoder::new();
|
||||
let mut cursor = 0;
|
||||
|
||||
// Use the first byte (if any) as a pseudo-chunk-schedule: low nibble
|
||||
// picks a split size 1..=16, high nibble is skipped. Subsequent
|
||||
// leading bytes drive subsequent splits.
|
||||
let mut sched_idx = 0;
|
||||
while cursor < data.len() {
|
||||
let split = if sched_idx < data.len() {
|
||||
((data[sched_idx] & 0x0F) as usize) + 1
|
||||
} else {
|
||||
16
|
||||
};
|
||||
sched_idx = sched_idx.saturating_add(1);
|
||||
let end = (cursor + split).min(data.len());
|
||||
decoder.feed(&data[cursor..end], |cmd| {
|
||||
if let donglora_protocol::Command::Transmit { payload, .. } = cmd {
|
||||
assert!(payload.len() <= MAX_PAYLOAD);
|
||||
}
|
||||
});
|
||||
cursor = end;
|
||||
}
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
//! Feed arbitrary bytes to `CobsDecoder::feed` using an arbitrary
|
||||
//! chunking strategy driven by the fuzz input, and confirm:
|
||||
//! - the decoder never panics,
|
||||
//! - every emitted command respects the bounded payload,
|
||||
//! - the total number of commands never exceeds the number of 0x00
|
||||
//! sentinels in the stream.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use donglora_protocol::framing::CobsDecoder;
|
||||
use donglora_protocol::{Command, MAX_PAYLOAD};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
// Split the input: first 32 bytes (if available) drive chunk sizes,
|
||||
// the rest is the stream.
|
||||
let split = 32.min(data.len());
|
||||
let (sched, stream) = data.split_at(split);
|
||||
|
||||
let mut decoder = CobsDecoder::new();
|
||||
let mut cursor = 0;
|
||||
let mut sched_idx = 0;
|
||||
let mut count = 0;
|
||||
while cursor < stream.len() {
|
||||
let split_size = if sched_idx < sched.len() {
|
||||
((sched[sched_idx] as usize) % 64) + 1
|
||||
} else {
|
||||
16
|
||||
};
|
||||
sched_idx += 1;
|
||||
let end = (cursor + split_size).min(stream.len());
|
||||
decoder.feed(&stream[cursor..end], |cmd| {
|
||||
count += 1;
|
||||
if let Command::Transmit { payload, .. } = cmd {
|
||||
assert!(payload.len() <= MAX_PAYLOAD);
|
||||
}
|
||||
});
|
||||
cursor = end;
|
||||
}
|
||||
let sentinel_count = stream.iter().filter(|&&b| b == 0).count();
|
||||
assert!(count <= sentinel_count);
|
||||
});
|
||||
@@ -1,126 +0,0 @@
|
||||
//! Structure-aware COBS roundtrip: build an arbitrary `Response`, encode
|
||||
//! it through `cobs_encode_response`, decode the framed bytes via
|
||||
//! `ucobs::decode`, and confirm the decoded payload matches the raw
|
||||
//! `write_to` output.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use donglora_protocol::framing::{MAX_FRAME, cobs_encode_response};
|
||||
use donglora_protocol::{Bandwidth, ErrorCode, RadioConfig, Response};
|
||||
use heapless::Vec as HVec;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
enum ArbResponse {
|
||||
Pong,
|
||||
Config(ArbConfig),
|
||||
RxPacket {
|
||||
rssi: i16,
|
||||
snr: i16,
|
||||
payload: Vec<u8>,
|
||||
},
|
||||
TxDone,
|
||||
Ok,
|
||||
Error(ArbError),
|
||||
MacAddress([u8; 6]),
|
||||
}
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
struct ArbConfig {
|
||||
freq_hz: u32,
|
||||
bw: u8,
|
||||
sf: u8,
|
||||
cr: u8,
|
||||
sync_word: u16,
|
||||
tx_power_dbm: i8,
|
||||
preamble_len: u16,
|
||||
cad: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Arbitrary, Clone, Copy)]
|
||||
enum ArbError {
|
||||
InvalidConfig,
|
||||
RadioBusy,
|
||||
TxTimeout,
|
||||
NotConfigured,
|
||||
NoDisplay,
|
||||
}
|
||||
|
||||
fn into_error(a: ArbError) -> ErrorCode {
|
||||
match a {
|
||||
ArbError::InvalidConfig => ErrorCode::InvalidConfig,
|
||||
ArbError::RadioBusy => ErrorCode::RadioBusy,
|
||||
ArbError::TxTimeout => ErrorCode::TxTimeout,
|
||||
ArbError::NotConfigured => ErrorCode::NotConfigured,
|
||||
ArbError::NoDisplay => ErrorCode::NoDisplay,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_config(c: &ArbConfig) -> RadioConfig {
|
||||
let bw = match c.bw % 10 {
|
||||
0 => Bandwidth::Khz7,
|
||||
1 => Bandwidth::Khz10,
|
||||
2 => Bandwidth::Khz15,
|
||||
3 => Bandwidth::Khz20,
|
||||
4 => Bandwidth::Khz31,
|
||||
5 => Bandwidth::Khz41,
|
||||
6 => Bandwidth::Khz62,
|
||||
7 => Bandwidth::Khz125,
|
||||
8 => Bandwidth::Khz250,
|
||||
_ => Bandwidth::Khz500,
|
||||
};
|
||||
RadioConfig {
|
||||
freq_hz: c.freq_hz,
|
||||
bw,
|
||||
sf: c.sf,
|
||||
cr: c.cr,
|
||||
sync_word: c.sync_word,
|
||||
tx_power_dbm: c.tx_power_dbm,
|
||||
preamble_len: c.preamble_len,
|
||||
cad: c.cad,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_response(a: ArbResponse) -> Response {
|
||||
match a {
|
||||
ArbResponse::Pong => Response::Pong,
|
||||
ArbResponse::Config(c) => Response::Config(into_config(&c)),
|
||||
ArbResponse::RxPacket { rssi, snr, payload } => {
|
||||
let mut p = HVec::<u8, { donglora_protocol::MAX_PAYLOAD }>::new();
|
||||
let take = payload.len().min(donglora_protocol::MAX_PAYLOAD);
|
||||
let _ = p.extend_from_slice(&payload[..take]);
|
||||
Response::RxPacket {
|
||||
rssi,
|
||||
snr,
|
||||
payload: p,
|
||||
}
|
||||
}
|
||||
ArbResponse::TxDone => Response::TxDone,
|
||||
ArbResponse::Ok => Response::Ok,
|
||||
ArbResponse::Error(e) => Response::Error(into_error(e)),
|
||||
ArbResponse::MacAddress(m) => Response::MacAddress(m),
|
||||
}
|
||||
}
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let mut u = Unstructured::new(data);
|
||||
let Ok(arb) = ArbResponse::arbitrary(&mut u) else {
|
||||
return;
|
||||
};
|
||||
let resp = into_response(arb);
|
||||
|
||||
let mut raw = [0u8; MAX_FRAME];
|
||||
let raw_n = resp.clone().write_to(&mut raw);
|
||||
|
||||
let mut write = [0u8; MAX_FRAME];
|
||||
let mut encode = [0u8; MAX_FRAME];
|
||||
let Some(framed) = cobs_encode_response(resp, &mut write, &mut encode) else {
|
||||
return;
|
||||
};
|
||||
|
||||
assert_eq!(*framed.last().unwrap(), 0x00);
|
||||
let mut decoded = [0u8; MAX_FRAME];
|
||||
let n = ucobs::decode(&framed[..framed.len() - 1], &mut decoded).unwrap();
|
||||
assert_eq!(&decoded[..n], &raw[..raw_n]);
|
||||
});
|
||||
@@ -1,157 +0,0 @@
|
||||
//! Structure-aware Command roundtrip: construct an arbitrary Command,
|
||||
//! hand-encode it using the same wire layout the library parses, and
|
||||
//! confirm `Command::from_bytes` recovers the original value exactly.
|
||||
//!
|
||||
//! The library itself is asymmetric (firmware only decodes commands),
|
||||
//! so this fuzz target carries a matching encoder.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use donglora_protocol::{Bandwidth, Command, MAX_PAYLOAD, RADIO_CONFIG_SIZE, RadioConfig};
|
||||
use heapless::Vec as HVec;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
enum ArbCommand {
|
||||
Ping,
|
||||
GetConfig,
|
||||
SetConfig(ArbConfig),
|
||||
StartRx,
|
||||
StopRx,
|
||||
Transmit {
|
||||
config: Option<ArbConfig>,
|
||||
payload: Vec<u8>,
|
||||
},
|
||||
DisplayOn,
|
||||
DisplayOff,
|
||||
GetMac,
|
||||
}
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
struct ArbConfig {
|
||||
freq_hz: u32,
|
||||
bw: u8,
|
||||
sf: u8,
|
||||
cr: u8,
|
||||
sync_word: u16,
|
||||
tx_power_dbm: i8,
|
||||
preamble_len: u16,
|
||||
cad: u8,
|
||||
}
|
||||
|
||||
fn into_config(c: &ArbConfig) -> RadioConfig {
|
||||
let bw = match c.bw % 10 {
|
||||
0 => Bandwidth::Khz7,
|
||||
1 => Bandwidth::Khz10,
|
||||
2 => Bandwidth::Khz15,
|
||||
3 => Bandwidth::Khz20,
|
||||
4 => Bandwidth::Khz31,
|
||||
5 => Bandwidth::Khz41,
|
||||
6 => Bandwidth::Khz62,
|
||||
7 => Bandwidth::Khz125,
|
||||
8 => Bandwidth::Khz250,
|
||||
_ => Bandwidth::Khz500,
|
||||
};
|
||||
RadioConfig {
|
||||
freq_hz: c.freq_hz,
|
||||
bw,
|
||||
sf: c.sf,
|
||||
cr: c.cr,
|
||||
sync_word: c.sync_word,
|
||||
tx_power_dbm: c.tx_power_dbm,
|
||||
preamble_len: c.preamble_len,
|
||||
cad: c.cad,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_command(a: &ArbCommand) -> Command {
|
||||
match a {
|
||||
ArbCommand::Ping => Command::Ping,
|
||||
ArbCommand::GetConfig => Command::GetConfig,
|
||||
ArbCommand::SetConfig(c) => Command::SetConfig(into_config(c)),
|
||||
ArbCommand::StartRx => Command::StartRx,
|
||||
ArbCommand::StopRx => Command::StopRx,
|
||||
ArbCommand::Transmit { config, payload } => {
|
||||
let cfg = config.as_ref().map(into_config);
|
||||
let mut p: HVec<u8, MAX_PAYLOAD> = HVec::new();
|
||||
let take = payload.len().min(MAX_PAYLOAD);
|
||||
let _ = p.extend_from_slice(&payload[..take]);
|
||||
Command::Transmit {
|
||||
config: cfg,
|
||||
payload: p,
|
||||
}
|
||||
}
|
||||
ArbCommand::DisplayOn => Command::DisplayOn,
|
||||
ArbCommand::DisplayOff => Command::DisplayOff,
|
||||
ArbCommand::GetMac => Command::GetMac,
|
||||
}
|
||||
}
|
||||
|
||||
fn encode(cmd: &Command, out: &mut [u8]) -> usize {
|
||||
match cmd {
|
||||
Command::Ping => {
|
||||
out[0] = 0;
|
||||
1
|
||||
}
|
||||
Command::GetConfig => {
|
||||
out[0] = 1;
|
||||
1
|
||||
}
|
||||
Command::SetConfig(cfg) => {
|
||||
out[0] = 2;
|
||||
cfg.write_to(&mut out[1..]);
|
||||
1 + RADIO_CONFIG_SIZE
|
||||
}
|
||||
Command::StartRx => {
|
||||
out[0] = 3;
|
||||
1
|
||||
}
|
||||
Command::StopRx => {
|
||||
out[0] = 4;
|
||||
1
|
||||
}
|
||||
Command::Transmit { config, payload } => {
|
||||
out[0] = 5;
|
||||
let mut pos = 1;
|
||||
if let Some(cfg) = config {
|
||||
out[pos] = 1;
|
||||
pos += 1;
|
||||
cfg.write_to(&mut out[pos..]);
|
||||
pos += RADIO_CONFIG_SIZE;
|
||||
} else {
|
||||
out[pos] = 0;
|
||||
pos += 1;
|
||||
}
|
||||
out[pos..pos + 2].copy_from_slice(&(payload.len() as u16).to_le_bytes());
|
||||
pos += 2;
|
||||
out[pos..pos + payload.len()].copy_from_slice(payload);
|
||||
pos + payload.len()
|
||||
}
|
||||
Command::DisplayOn => {
|
||||
out[0] = 6;
|
||||
1
|
||||
}
|
||||
Command::DisplayOff => {
|
||||
out[0] = 7;
|
||||
1
|
||||
}
|
||||
Command::GetMac => {
|
||||
out[0] = 8;
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let mut u = Unstructured::new(data);
|
||||
let Ok(arb) = ArbCommand::arbitrary(&mut u) else {
|
||||
return;
|
||||
};
|
||||
let cmd = into_command(&arb);
|
||||
|
||||
let mut buf = [0u8; 1024];
|
||||
let n = encode(&cmd, &mut buf);
|
||||
let parsed = Command::from_bytes(&buf[..n]).expect("encoded command must parse");
|
||||
assert_eq!(parsed, cmd);
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
//! `FrameDecoder::feed` must never panic on arbitrary input, and any
|
||||
//! yielded payload slice must fit the documented bounds.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use donglora_protocol::{FrameDecoder, FrameResult, MAX_PAYLOAD_FIELD};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let mut decoder = FrameDecoder::new();
|
||||
decoder.feed(data, |res| {
|
||||
if let FrameResult::Ok { payload, .. } = res {
|
||||
assert!(payload.len() <= MAX_PAYLOAD_FIELD);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
//! An arbitrary well-formed `(type_id, tag, payload)` must survive a
|
||||
//! frame encode → decode round trip byte-for-byte.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use arbitrary::Arbitrary;
|
||||
use donglora_protocol::{FrameDecoder, FrameResult, MAX_PAYLOAD_FIELD, MAX_WIRE_FRAME, encode_frame};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
struct Input<'a> {
|
||||
type_id: u8,
|
||||
tag: u16,
|
||||
payload: &'a [u8],
|
||||
}
|
||||
|
||||
fuzz_target!(|input: Input| {
|
||||
if input.payload.len() > MAX_PAYLOAD_FIELD {
|
||||
return;
|
||||
}
|
||||
let mut wire = [0u8; MAX_WIRE_FRAME];
|
||||
let Ok(n) = encode_frame(input.type_id, input.tag, input.payload, &mut wire) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut decoder = FrameDecoder::new();
|
||||
let mut matched = false;
|
||||
decoder.feed(&wire[..n], |res| {
|
||||
if let FrameResult::Ok {
|
||||
type_id,
|
||||
tag,
|
||||
payload,
|
||||
} = res
|
||||
{
|
||||
assert_eq!(type_id, input.type_id);
|
||||
assert_eq!(tag, input.tag);
|
||||
assert_eq!(payload, input.payload);
|
||||
matched = true;
|
||||
} else {
|
||||
panic!("encode→decode produced a frame error: {:?}", res);
|
||||
}
|
||||
});
|
||||
assert!(matched, "encoded frame did not decode");
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
//! `LoRaConfig` round-trips through its wire encoding for every
|
||||
//! construction derived via `Arbitrary`.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use arbitrary::Arbitrary;
|
||||
use donglora_protocol::{LoRaBandwidth, LoRaCodingRate, LoRaConfig, LoRaHeaderMode};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
struct Input {
|
||||
freq_hz: u32,
|
||||
sf: u8,
|
||||
bw_raw: u8,
|
||||
cr_raw: u8,
|
||||
preamble_len: u16,
|
||||
sync_word: u16,
|
||||
tx_power_dbm: i8,
|
||||
header_raw: u8,
|
||||
payload_crc: bool,
|
||||
iq_invert: bool,
|
||||
}
|
||||
|
||||
fuzz_target!(|input: Input| {
|
||||
let Some(bw) = LoRaBandwidth::from_u8(input.bw_raw & 0x0F) else {
|
||||
return;
|
||||
};
|
||||
let Some(cr) = LoRaCodingRate::from_u8(input.cr_raw & 0x03) else {
|
||||
return;
|
||||
};
|
||||
let Some(header_mode) = LoRaHeaderMode::from_u8(input.header_raw & 0x01) else {
|
||||
return;
|
||||
};
|
||||
let cfg = LoRaConfig {
|
||||
freq_hz: input.freq_hz,
|
||||
sf: input.sf,
|
||||
bw,
|
||||
cr,
|
||||
preamble_len: input.preamble_len,
|
||||
sync_word: input.sync_word,
|
||||
tx_power_dbm: input.tx_power_dbm,
|
||||
header_mode,
|
||||
payload_crc: input.payload_crc,
|
||||
iq_invert: input.iq_invert,
|
||||
};
|
||||
|
||||
let mut buf = [0u8; 32];
|
||||
let n = cfg.encode(&mut buf).unwrap();
|
||||
assert_eq!(LoRaConfig::decode(&buf[..n]).unwrap(), cfg);
|
||||
});
|
||||
@@ -1,14 +1,20 @@
|
||||
//! `Command::from_bytes` must never panic on arbitrary input.
|
||||
//!
|
||||
//! Any accepted command must also respect the heapless payload bound.
|
||||
//! `Command::parse` must never panic on arbitrary `(type_id, payload)`
|
||||
//! input. Accepted commands must respect the OTA payload bound.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use donglora_protocol::{Command, MAX_PAYLOAD};
|
||||
use arbitrary::Arbitrary;
|
||||
use donglora_protocol::{Command, MAX_OTA_PAYLOAD};
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if let Some(Command::Transmit { payload, .. }) = Command::from_bytes(data) {
|
||||
assert!(payload.len() <= MAX_PAYLOAD);
|
||||
#[derive(Debug, Arbitrary)]
|
||||
struct Input<'a> {
|
||||
type_id: u8,
|
||||
payload: &'a [u8],
|
||||
}
|
||||
|
||||
fuzz_target!(|input: Input| {
|
||||
if let Ok(Command::Tx { data, .. }) = Command::parse(input.type_id, input.payload) {
|
||||
assert!(data.len() <= MAX_OTA_PAYLOAD);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
//! `DeviceMessage::parse` must never panic on arbitrary input.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use arbitrary::Arbitrary;
|
||||
use donglora_protocol::DeviceMessage;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
#[derive(Debug, Arbitrary)]
|
||||
struct Input<'a> {
|
||||
type_id: u8,
|
||||
payload: &'a [u8],
|
||||
originating_cmd: Option<u8>,
|
||||
}
|
||||
|
||||
fuzz_target!(|input: Input| {
|
||||
let _ = DeviceMessage::parse(input.type_id, input.payload, input.originating_cmd);
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
//! `RadioConfig::from_bytes` must never panic on arbitrary input.
|
||||
|
||||
#![no_main]
|
||||
|
||||
use donglora_protocol::RadioConfig;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let _ = RadioConfig::from_bytes(data);
|
||||
});
|
||||
Reference in new issue
Block a user