Skip to content

Commit 09ecbd8

Browse files
authored
Merge pull request #53 from tweedegolf/item-too-big
Item too big
2 parents 839fc1a + 1d0983f commit 09ecbd8

File tree

6 files changed

+90
-8
lines changed

6 files changed

+90
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
## Unreleased
66

7+
- Added check for too big items that won't ever fit in flash so it returns a good clear error.
8+
79
# 2.0.1 06-05-24
810

911
- Implemented the `get_len` function for all built-in key types

build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("cargo::rustc-check-cfg=cfg(fuzzing_repro)");
3+
}

src/item.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,19 +178,19 @@ impl ItemHeader {
178178
}
179179

180180
/// Get the address of the start of the data for this item
181-
pub fn data_address<S: NorFlash>(address: u32) -> u32 {
181+
pub const fn data_address<S: NorFlash>(address: u32) -> u32 {
182182
address + round_up_to_alignment::<S>(Self::LENGTH as u32)
183183
}
184184

185185
/// Get the location of the next item in flash
186-
pub fn next_item_address<S: NorFlash>(&self, address: u32) -> u32 {
186+
pub const fn next_item_address<S: NorFlash>(&self, address: u32) -> u32 {
187187
let data_address = ItemHeader::data_address::<S>(address);
188188
data_address + round_up_to_alignment::<S>(self.length as u32)
189189
}
190190

191191
/// Calculates the amount of bytes available for data.
192192
/// Essentially, it's the given amount minus the header and minus some alignment padding.
193-
pub fn available_data_bytes<S: NorFlash>(total_available: u32) -> Option<u32> {
193+
pub const fn available_data_bytes<S: NorFlash>(total_available: u32) -> Option<u32> {
194194
let data_start = Self::data_address::<S>(0);
195195
let data_end = round_down_to_alignment::<S>(total_available);
196196

src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ const fn calculate_page_index<S: NorFlash>(flash_range: Range<u32>, address: u32
148148
(address - flash_range.start) as usize / S::ERASE_SIZE
149149
}
150150

151+
const fn calculate_page_size<S: NorFlash>() -> usize {
152+
// Page minus the two page status words
153+
S::ERASE_SIZE - S::WORD_SIZE * 2
154+
}
155+
151156
/// The marker being used for page states
152157
const MARKER: u8 = 0;
153158

@@ -366,7 +371,6 @@ pub enum Error<S> {
366371
backtrace: std::backtrace::Backtrace,
367372
},
368373
/// The item cannot be stored anymore because the storage is full.
369-
/// If you get this error some data may be lost.
370374
FullStorage,
371375
/// It's been detected that the memory is likely corrupted.
372376
/// You may want to erase the memory to recover.
@@ -381,6 +385,11 @@ pub enum Error<S> {
381385
BufferTooSmall(usize),
382386
/// A serialization error (from the key or value)
383387
SerializationError(SerializationError),
388+
/// The item does not fit in flash, ever.
389+
/// This is different from [Error::FullStorage] because this item is too big to fit even in empty flash.
390+
///
391+
/// See the readme for more info about the constraints on item sizes.
392+
ItemTooBig,
384393
}
385394

386395
impl<S> From<SerializationError> for Error<S> {
@@ -416,6 +425,7 @@ where
416425
"A provided buffer was to small to be used. Needed was {needed}"
417426
),
418427
Error::SerializationError(value) => write!(f, "Map value error: {value}"),
428+
Error::ItemTooBig => write!(f, "The item is too big to fit in the flash"),
419429
}
420430
}
421431
}

src/map.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,15 @@ async fn store_item_inner<'d, K: Key, S: NorFlash>(
425425
.serialize_into(&mut data_buffer[key_len..])
426426
.map_err(Error::SerializationError)?;
427427

428+
if item_data_length > u16::MAX as usize
429+
|| item_data_length
430+
> calculate_page_size::<S>()
431+
.saturating_sub(ItemHeader::data_address::<S>(0) as usize)
432+
{
433+
cache.unmark_dirty();
434+
return Err(Error::ItemTooBig);
435+
}
436+
428437
let free_spot_address = find_next_free_item_spot(
429438
flash,
430439
flash_range.clone(),
@@ -1347,4 +1356,34 @@ mod tests {
13471356
.is_none());
13481357
}
13491358
}
1359+
1360+
#[test]
1361+
async fn store_too_big_item() {
1362+
let mut flash = MockFlashBig::new(mock_flash::WriteCountCheck::Twice, None, true);
1363+
const FLASH_RANGE: Range<u32> = 0x000..0x1000;
1364+
1365+
store_item(
1366+
&mut flash,
1367+
FLASH_RANGE,
1368+
&mut cache::NoCache::new(),
1369+
&mut [0; 1024],
1370+
0u8,
1371+
&[0; 1024 - 4 * 2 - 8 - 1],
1372+
)
1373+
.await
1374+
.unwrap();
1375+
1376+
assert_eq!(
1377+
store_item(
1378+
&mut flash,
1379+
FLASH_RANGE,
1380+
&mut cache::NoCache::new(),
1381+
&mut [0; 1024],
1382+
0u8,
1383+
&[0; 1024 - 4 * 2 - 8 - 1 + 1],
1384+
)
1385+
.await,
1386+
Err(Error::ItemTooBig)
1387+
);
1388+
}
13501389
}

src/queue.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ async fn push_inner<S: NorFlash>(
108108
}
109109

110110
// Data must fit in a single page
111-
if data.len()
112-
> ItemHeader::available_data_bytes::<S>((S::ERASE_SIZE - S::WORD_SIZE * 2) as u32).unwrap()
113-
as usize
111+
if data.len() > u16::MAX as usize
112+
|| data.len()
113+
> calculate_page_size::<S>().saturating_sub(ItemHeader::data_address::<S>(0) as usize)
114114
{
115115
cache.unmark_dirty();
116-
return Err(Error::BufferTooBig);
116+
return Err(Error::ItemTooBig);
117117
}
118118

119119
let current_page = find_youngest_page(flash, flash_range.clone(), cache).await?;
@@ -1300,4 +1300,32 @@ mod tests {
13001300
0
13011301
);
13021302
}
1303+
1304+
#[test]
1305+
async fn store_too_big_item() {
1306+
let mut flash = MockFlashBig::new(WriteCountCheck::Twice, None, true);
1307+
const FLASH_RANGE: Range<u32> = 0x000..0x1000;
1308+
1309+
push(
1310+
&mut flash,
1311+
FLASH_RANGE,
1312+
&mut cache::NoCache::new(),
1313+
&[0; 1024 - 4 * 2 - 8],
1314+
false,
1315+
)
1316+
.await
1317+
.unwrap();
1318+
1319+
assert_eq!(
1320+
push(
1321+
&mut flash,
1322+
FLASH_RANGE,
1323+
&mut cache::NoCache::new(),
1324+
&[0; 1024 - 4 * 2 - 8 + 1],
1325+
false,
1326+
)
1327+
.await,
1328+
Err(Error::ItemTooBig)
1329+
);
1330+
}
13031331
}

0 commit comments

Comments
 (0)