1use crate::message::ReaderOptions;
2use crate::message::ReaderSegments;
3use crate::private::units::BYTES_PER_WORD;
4use crate::{Error, ErrorKind, Result};
5
6use super::SEGMENTS_COUNT_LIMIT;
7
8const U32_LEN_IN_BYTES: usize = core::mem::size_of::<u32>();
9
10pub struct NoAllocSegmentTableInfo {
12 pub segments_count: usize,
14
15 pub segment_table_length_bytes: usize,
17
18 pub total_segments_length_bytes: usize,
20}
21
22fn read_segment_table(slice: &[u8], options: ReaderOptions) -> Result<NoAllocSegmentTableInfo> {
23 let mut remaining = slice;
24
25 verify_alignment(remaining.as_ptr())?;
26
27 let segments_count = u32_to_segments_count(read_u32_le(&mut remaining)?)?;
28
29 if segments_count >= SEGMENTS_COUNT_LIMIT {
30 return Err(Error::from_kind(ErrorKind::InvalidNumberOfSegments(
31 segments_count,
32 )));
33 }
34
35 let mut total_segments_length_bytes = 0_usize;
36
37 for _ in 0..segments_count {
38 let segment_length_in_bytes = u32_to_segment_length_bytes(read_u32_le(&mut remaining)?)?;
39
40 total_segments_length_bytes = total_segments_length_bytes
41 .checked_add(segment_length_in_bytes)
42 .ok_or_else(|| Error::from_kind(ErrorKind::MessageSizeOverflow))?;
43 }
44
45 if let Some(limit) = options.traversal_limit_in_words {
49 let total_segments_length_words = total_segments_length_bytes / 8;
50 if total_segments_length_words > limit {
51 return Err(Error::from_kind(ErrorKind::MessageTooLarge(
52 total_segments_length_words,
53 )));
54 }
55 }
56
57 if segments_count % 2 == 0 {
60 let _padding = read_u32_le(&mut remaining)?;
61 }
62
63 let expected_data_offset = calculate_data_offset(segments_count)
64 .ok_or_else(|| Error::from_kind(ErrorKind::MessageSizeOverflow))?;
65
66 let consumed_bytes = slice.len() - remaining.len();
67
68 assert_eq!(
69 expected_data_offset, consumed_bytes,
70 "Expected header size and actual header size must match, otherwise we have a bug in this code"
71 );
72
73 if remaining.len() < total_segments_length_bytes {
77 return Err(Error::from_kind(ErrorKind::MessageEndsPrematurely(
78 total_segments_length_bytes / BYTES_PER_WORD,
79 remaining.len() / BYTES_PER_WORD,
80 )));
81 }
82
83 Ok(NoAllocSegmentTableInfo {
84 segments_count,
85 segment_table_length_bytes: expected_data_offset,
86 total_segments_length_bytes,
87 })
88}
89
90pub type NoAllocSliceSegments<'b> = NoAllocBufferSegments<&'b [u8]>;
92
93enum NoAllocBufferSegmentType {
94 SingleSegment(usize),
98
99 MultipleSegments,
102}
103
104pub struct NoAllocBufferSegments<T> {
115 buffer: T,
116 segment_type: NoAllocBufferSegmentType,
117}
118
119impl<T> NoAllocBufferSegments<T> {
120 pub fn from_segment_table_info(buffer: T, info: NoAllocSegmentTableInfo) -> Self {
125 if info.segments_count == 1 {
126 Self {
127 buffer,
128 segment_type: NoAllocBufferSegmentType::SingleSegment(
129 info.total_segments_length_bytes,
130 ),
131 }
132 } else {
133 Self {
134 buffer,
135 segment_type: NoAllocBufferSegmentType::MultipleSegments,
136 }
137 }
138 }
139}
140
141impl<'b> NoAllocBufferSegments<&'b [u8]> {
142 pub fn from_slice(slice: &mut &'b [u8], options: ReaderOptions) -> Result<Self> {
149 let segment_table_info = read_segment_table(slice, options)?;
150
151 let message_length = segment_table_info.segment_table_length_bytes
152 + segment_table_info.total_segments_length_bytes;
153
154 let message = &slice[..message_length];
155 *slice = &slice[message_length..];
156
157 Ok(Self::from_segment_table_info(message, segment_table_info))
158 }
159}
160
161impl<T: AsRef<[u8]>> NoAllocBufferSegments<T> {
162 pub fn from_buffer(buffer: T, options: ReaderOptions) -> Result<Self> {
168 let segment_table_info = read_segment_table(buffer.as_ref(), options)?;
169 Ok(Self::from_segment_table_info(buffer, segment_table_info))
170 }
171}
172
173impl<T: AsRef<[u8]>> ReaderSegments for NoAllocBufferSegments<T> {
174 fn get_segment(&self, idx: u32) -> Option<&[u8]> {
175 let idx: usize = idx.try_into().unwrap();
180
181 match self.segment_type {
182 NoAllocBufferSegmentType::SingleSegment(length_bytes) => {
183 if idx == 0 {
184 Some(&self.buffer.as_ref()[8..8 + length_bytes])
185 } else {
186 None
187 }
188 }
189 NoAllocBufferSegmentType::MultipleSegments => {
190 let mut buf = self.buffer.as_ref();
191
192 let segments_count = u32_to_segments_count(read_u32_le(&mut buf).unwrap()).unwrap();
193
194 if idx >= segments_count {
195 return None;
196 }
197
198 let mut segment_offset = calculate_data_offset(segments_count).unwrap();
199
200 for _ in 0..idx {
201 segment_offset = segment_offset
202 .checked_add(
203 u32_to_segment_length_bytes(read_u32_le(&mut buf).unwrap()).unwrap(),
204 )
205 .unwrap();
206 }
207
208 let segment_length =
209 u32_to_segment_length_bytes(read_u32_le(&mut buf).unwrap()).unwrap();
210
211 Some(&self.buffer.as_ref()[segment_offset..(segment_offset + segment_length)])
212 }
213 }
214 }
215
216 fn len(&self) -> usize {
217 match self.segment_type {
221 NoAllocBufferSegmentType::SingleSegment { .. } => 1,
222 NoAllocBufferSegmentType::MultipleSegments => {
223 u32_to_segments_count(read_u32_le(&mut self.buffer.as_ref()).unwrap()).unwrap()
224 }
225 }
226 }
227}
228
229fn verify_alignment(ptr: *const u8) -> Result<()> {
237 if cfg!(feature = "unaligned") {
238 return Ok(());
239 }
240
241 if ptr.align_offset(BYTES_PER_WORD) == 0 {
242 Ok(())
243 } else {
244 Err(Error::from_kind(
245 ErrorKind::MessageNotAlignedBy8BytesBoundary,
246 ))
247 }
248}
249
250fn read_u32_le(slice: &mut &[u8]) -> Result<u32> {
253 if slice.len() < U32_LEN_IN_BYTES {
254 return Err(Error::from_kind(ErrorKind::MessageEndsPrematurely(
255 U32_LEN_IN_BYTES,
256 slice.len(),
257 )));
258 }
259
260 let u32_buf: [u8; U32_LEN_IN_BYTES] = slice[..U32_LEN_IN_BYTES].try_into().unwrap();
263 *slice = &slice[U32_LEN_IN_BYTES..];
264
265 Ok(u32::from_le_bytes(u32_buf))
266}
267
268fn u32_to_segments_count(val: u32) -> Result<usize> {
270 let result: Option<usize> = val.try_into().ok();
272
273 let result = result.and_then(|v: usize| v.checked_add(1));
277
278 result.ok_or_else(|| Error::from_kind(ErrorKind::FourByteLengthTooBigForUSize))
279}
280
281fn u32_to_segment_length_bytes(val: u32) -> Result<usize> {
283 let length_in_words: Option<usize> = val.try_into().ok();
285
286 let length_in_bytes = length_in_words.and_then(|l| l.checked_mul(BYTES_PER_WORD));
287
288 length_in_bytes.ok_or_else(|| Error::from_kind(ErrorKind::FourByteSegmentLengthTooBigForUSize))
289}
290
291fn calculate_data_offset(segments_count: usize) -> Option<usize> {
298 if segments_count == 0 {
307 return None;
308 }
309
310 let mut data_offset = 0_usize;
311
312 {
313 let segments_count_len = U32_LEN_IN_BYTES;
315 data_offset = data_offset.checked_add(segments_count_len)?;
316 }
317
318 {
319 let segments_lengt_len = segments_count.checked_mul(U32_LEN_IN_BYTES)?;
321 data_offset = data_offset.checked_add(segments_lengt_len)?;
322 }
323
324 let padding_len = match data_offset % BYTES_PER_WORD {
328 0 => 0,
329 4 => 4,
330 _ => unreachable!(
331 "Mis-alignment by anything other than 4 should be impossible, this is a bug"
332 ),
333 };
334
335 data_offset = data_offset.checked_add(padding_len)?;
336
337 assert_eq!(
339 data_offset % BYTES_PER_WORD,
340 0,
341 "data_offset after adding panic must be aligned by 8. \
342 If it's not, it's a bug"
343 );
344
345 Some(data_offset)
346}
347
348#[cfg(test)]
349mod tests {
350 #[cfg(feature = "alloc")]
351 use quickcheck::{quickcheck, TestResult};
352
353 use super::calculate_data_offset;
354 #[cfg(feature = "alloc")]
355 use crate::{
356 message::{ReaderOptions, ReaderSegments},
357 serialize, word, Word,
358 };
359
360 #[cfg(feature = "alloc")]
361 use crate::OutputSegments;
362
363 use super::{
364 read_u32_le, u32_to_segment_length_bytes, u32_to_segments_count, verify_alignment,
365 };
366 #[cfg(feature = "alloc")]
367 use super::{NoAllocBufferSegmentType, NoAllocBufferSegments, NoAllocSliceSegments};
368
369 #[repr(align(8))]
370 struct Aligned([u8; 8]);
371
372 #[cfg(feature = "unaligned")]
373 #[test]
374 fn test_verify_alignment_unaligned_mode() {
375 assert_eq!(core::mem::size_of::<Aligned>(), 8);
380
381 let aligned = Aligned([0; 8]);
382
383 for idx in 0..8 {
385 verify_alignment(unsafe { aligned.0.as_ptr().add(idx) }).unwrap();
386 }
387 }
388
389 #[cfg(not(feature = "unaligned"))]
390 #[test]
391 fn test_verify_alignment() {
392 assert_eq!(core::mem::size_of::<Aligned>(), 8);
394
395 let aligned = Aligned([0; 8]);
396
397 verify_alignment(aligned.0.as_ptr()).unwrap();
398 for idx in 1..8 {
399 verify_alignment(unsafe { aligned.0.as_ptr().add(idx) }).unwrap_err();
400 }
401 }
402
403 #[test]
404 fn test_read_u32_le() {
405 let buffer = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
406 let mut buffer_remaining = &buffer[..];
407
408 assert_eq!(read_u32_le(&mut buffer_remaining).unwrap(), 0x04030201);
409 assert_eq!(buffer_remaining, &buffer[4..]);
410 }
411
412 #[test]
413 fn test_read_u32_le_truncated() {
414 let buffer = [0x01, 0x02, 0x03];
415 let mut buffer_remaining = &buffer[..];
416
417 read_u32_le(&mut buffer_remaining).unwrap_err();
418 assert_eq!(buffer_remaining, &buffer[..]);
419 }
420
421 #[test]
422 fn test_u32_to_segments_count() {
423 assert_eq!(u32_to_segments_count(0).unwrap(), 1);
424 assert_eq!(u32_to_segments_count(10).unwrap(), 11);
425 }
427
428 #[test]
429 fn test_u32_to_segment_length_bytes() {
430 assert_eq!(u32_to_segment_length_bytes(0).unwrap(), 0);
431 assert_eq!(u32_to_segment_length_bytes(123).unwrap(), 123 * 8);
432 }
433
434 #[test]
435 fn test_calculate_data_offset_no_padding() {
436 assert_eq!(calculate_data_offset(0), None);
437
438 assert_eq!(calculate_data_offset(1), Some(8));
439
440 assert_eq!(calculate_data_offset(2), Some(16));
441 assert_eq!(calculate_data_offset(3), Some(16));
442
443 assert_eq!(calculate_data_offset(100), Some(408));
444 assert_eq!(calculate_data_offset(101), Some(408));
445 }
446
447 #[cfg(feature = "alloc")]
448 quickcheck! {
449 #[cfg_attr(miri, ignore)] fn test_no_alloc_buffer_segments_single_segment_optimization(
451 segment_0 : alloc::vec::Vec<Word>) -> TestResult
452 {
453 let words = &segment_0[..];
454 let bytes = Word::words_to_bytes(words);
455 let output_segments = OutputSegments::SingleSegment([bytes]);
456 let mut msg = vec![];
457
458 serialize::write_message_segments(&mut msg, &output_segments).unwrap();
459
460 let no_alloc_segments =
461 NoAllocSliceSegments::from_slice(&mut msg.as_slice(), ReaderOptions::new()).unwrap();
462
463 assert!(matches!(
464 no_alloc_segments,
465 NoAllocBufferSegments { buffer: _,
466 segment_type : NoAllocBufferSegmentType::SingleSegment { .. },
467 }
468 ));
469
470 assert_eq!(no_alloc_segments.len(), 1);
471 assert_eq!(no_alloc_segments.get_segment(0), Some(bytes));
472 assert_eq!(no_alloc_segments.get_segment(1), None);
473 TestResult::from_bool(true)
474 }
475
476 #[cfg_attr(miri, ignore)] fn test_no_alloc_buffer_segments_multiple_segments(segments_vec: alloc::vec::Vec<alloc::vec::Vec<Word>>) -> TestResult {
478 if segments_vec.is_empty() { return TestResult::discard() };
479
480 let segments: alloc::vec::Vec<_> = segments_vec.iter().map(|s|
481 Word::words_to_bytes(s.as_slice())).collect();
482
483 let output_segments = OutputSegments::MultiSegment(segments.clone());
484
485 let mut msg = vec![];
486
487 serialize::write_message_segments(&mut msg, &output_segments).unwrap();
488
489 let no_alloc_segments =
490 NoAllocSliceSegments::from_slice(&mut msg.as_slice(), ReaderOptions::new()).unwrap();
491
492 assert_eq!(no_alloc_segments.len(), segments.len());
493 for (i, segment) in segments.iter().enumerate() {
494 assert_eq!(no_alloc_segments.get_segment(i as u32), Some(*segment));
495 }
496
497 assert_eq!(
498 no_alloc_segments.get_segment(no_alloc_segments.len() as u32),
499 None
500 );
501 TestResult::from_bool(true)
502 }
503 }
504
505 #[cfg(feature = "alloc")]
506 #[test]
507 fn test_no_alloc_buffer_segments_message_postfix() {
508 let output_segments = OutputSegments::SingleSegment([&[1, 2, 3, 4, 5, 6, 7, 8]]);
509 let mut buf = Word::allocate_zeroed_vec(2);
510 serialize::write_message_segments(Word::words_to_bytes_mut(&mut buf), &output_segments)
511 .unwrap();
512 buf.push(word(11, 12, 13, 14, 15, 16, 0, 0));
513
514 let remaining = &mut Word::words_to_bytes(&buf);
515 NoAllocSliceSegments::from_slice(remaining, ReaderOptions::new()).unwrap();
516
517 assert_eq!(*remaining, &[11, 12, 13, 14, 15, 16, 0, 0]);
519 }
520
521 #[cfg(feature = "alloc")]
522 #[test]
523 fn test_no_alloc_buffer_segments_message_invalid() {
524 let mut buf = vec![];
525
526 buf.extend([0, 2, 0, 0]); buf.extend([0; 513 * 8]);
528 assert!(NoAllocSliceSegments::from_slice(&mut &buf[..], ReaderOptions::new()).is_err());
529 buf.clear();
530
531 buf.extend([0, 0, 0, 0]); assert!(NoAllocSliceSegments::from_slice(&mut &buf[..], ReaderOptions::new()).is_err());
533 buf.clear();
534
535 buf.extend([0, 0, 0, 0]); buf.extend([0; 3]);
537 assert!(NoAllocSliceSegments::from_slice(&mut &buf[..], ReaderOptions::new()).is_err());
538 buf.clear();
539
540 buf.extend([255, 255, 255, 255]); assert!(NoAllocSliceSegments::from_slice(&mut &buf[..], ReaderOptions::new()).is_err());
542 buf.clear();
543 }
544
545 #[cfg(feature = "alloc")]
546 quickcheck! {
547 #[cfg_attr(miri, ignore)] fn test_no_alloc_buffer_segments_message_truncated(segments_vec: alloc::vec::Vec<alloc::vec::Vec<Word>>) -> TestResult {
549 if segments_vec.is_empty() { return TestResult::discard() }
550
551 let segments: alloc::vec::Vec<_> = segments_vec.iter()
552 .map(|s| Word::words_to_bytes(s.as_slice())).collect();
553
554 let output_segments = OutputSegments::MultiSegment(segments.clone());
555
556 let mut msg = vec![];
557
558 serialize::write_message_segments(&mut msg, &output_segments).unwrap();
559
560 msg.pop().unwrap();
562
563 let no_alloc_segments =
564 NoAllocSliceSegments::from_slice(&mut msg.as_slice(), ReaderOptions::new());
565
566 assert!(no_alloc_segments.is_err());
567 TestResult::from_bool(true)
568 }
569
570 #[cfg_attr(miri, ignore)] fn test_no_alloc_buffer_segments_message_options_limit(
572 segments_vec: alloc::vec::Vec<alloc::vec::Vec<Word>>) -> TestResult
573 {
574 let mut word_count = 0;
575 let segments: alloc::vec::Vec<_> = segments_vec.iter()
576 .map(|s| {
577 let ws = Word::words_to_bytes(s.as_slice());
578 word_count += s.len();
579 ws
580 }).collect();
581 if word_count == 0 { return TestResult::discard() };
582
583 let output_segments = OutputSegments::MultiSegment(segments.clone());
584
585 let mut msg = vec![];
586
587 serialize::write_message_segments(&mut msg, &output_segments).unwrap();
588
589 let mut options = ReaderOptions::new();
590 options.traversal_limit_in_words(Some(word_count));
591
592 let _no_alloc_segments =
593 NoAllocSliceSegments::from_slice(&mut msg.as_slice(), options).unwrap();
594
595 let mut options = ReaderOptions::new();
596 options.traversal_limit_in_words(Some(word_count - 1));
597
598 let no_alloc_segments = NoAllocSliceSegments::from_slice(&mut msg.as_slice(), options);
599
600 assert!(no_alloc_segments.is_err());
601 TestResult::from_bool(true)
602 }
603
604 #[cfg_attr(miri, ignore)] fn test_no_alloc_buffer_segments_bad_alignment(segment_0: alloc::vec::Vec<Word>) -> TestResult {
606 if segment_0.is_empty() { return TestResult::discard(); }
607 let output_segments = OutputSegments::SingleSegment([Word::words_to_bytes(&segment_0)]);
608
609 let mut msg = vec![];
610
611 serialize::write_message_segments(&mut msg, &output_segments).unwrap();
612 msg.insert(0_usize, 0_u8);
614
615 let no_alloc_segments = NoAllocSliceSegments::from_slice(&mut &msg[1..], ReaderOptions::new());
616
617 if cfg!(feature = "unaligned") {
618 no_alloc_segments.unwrap();
620 } else {
621 assert!(no_alloc_segments.is_err());
622 }
623 TestResult::from_bool(true)
624 }
625 }
626}