Skip to content

Commit 4c48b05

Browse files
committed
Clear streaming decoder buffers on drop
1 parent 27962f7 commit 4c48b05

2 files changed

Lines changed: 105 additions & 28 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
adjacent framed payload bytes unread.
1919
- Extended stream fuzz coverage to compare fragmented `DecoderReader` sources
2020
against slice decoding when payload-boundary semantics match.
21+
- Hardened streaming decoders to clear pending input on drop and clear decoded
22+
output queue bytes before they are discarded.
2123

2224
## 0.4.1 - 2026-05-14
2325

src/lib.rs

Lines changed: 103 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,7 @@ pub mod runtime {
254254
write!(
255255
formatter,
256256
"active={} candidate={} candidate_required_cpu_features=",
257-
self.active,
258-
self.candidate,
257+
self.active, self.candidate,
259258
)?;
260259
write_feature_list(formatter, self.candidate_required_cpu_features())?;
261260
write!(
@@ -645,7 +644,7 @@ pub mod stream {
645644
where
646645
A: Alphabet,
647646
{
648-
inner: W,
647+
inner: Option<W>,
649648
engine: Engine<A, PAD>,
650649
pending: [u8; 4],
651650
pending_len: usize,
@@ -660,7 +659,7 @@ pub mod stream {
660659
#[must_use]
661660
pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
662661
Self {
663-
inner,
662+
inner: Some(inner),
664663
engine,
665664
pending: [0; 4],
666665
pending_len: 0,
@@ -670,21 +669,56 @@ pub mod stream {
670669

671670
/// Returns a shared reference to the wrapped writer.
672671
#[must_use]
673-
pub const fn get_ref(&self) -> &W {
674-
&self.inner
672+
pub fn get_ref(&self) -> &W {
673+
self.inner_ref()
675674
}
676675

677676
/// Returns a mutable reference to the wrapped writer.
678677
pub fn get_mut(&mut self) -> &mut W {
679-
&mut self.inner
678+
self.inner_mut()
680679
}
681680

682681
/// Consumes the decoder without flushing pending input.
683682
///
684683
/// Prefer [`Self::finish`] when the decoded output must be complete.
685684
#[must_use]
686-
pub fn into_inner(self) -> W {
687-
self.inner
685+
pub fn into_inner(mut self) -> W {
686+
self.take_inner()
687+
}
688+
689+
fn inner_ref(&self) -> &W {
690+
match &self.inner {
691+
Some(inner) => inner,
692+
None => unreachable!("stream decoder inner writer was already taken"),
693+
}
694+
}
695+
696+
fn inner_mut(&mut self) -> &mut W {
697+
match &mut self.inner {
698+
Some(inner) => inner,
699+
None => unreachable!("stream decoder inner writer was already taken"),
700+
}
701+
}
702+
703+
fn take_inner(&mut self) -> W {
704+
match self.inner.take() {
705+
Some(inner) => inner,
706+
None => unreachable!("stream decoder inner writer was already taken"),
707+
}
708+
}
709+
710+
fn clear_pending(&mut self) {
711+
self.pending.fill(0);
712+
self.pending_len = 0;
713+
}
714+
}
715+
716+
impl<W, A, const PAD: bool> Drop for Decoder<W, A, PAD>
717+
where
718+
A: Alphabet,
719+
{
720+
fn drop(&mut self) {
721+
self.clear_pending();
688722
}
689723
}
690724

@@ -696,8 +730,8 @@ pub mod stream {
696730
/// Validates final pending input, flushes the wrapped writer, and returns it.
697731
pub fn finish(mut self) -> io::Result<W> {
698732
self.write_pending_final()?;
699-
self.inner.flush()?;
700-
Ok(self.inner)
733+
self.inner_mut().flush()?;
734+
Ok(self.take_inner())
701735
}
702736

703737
fn write_pending_final(&mut self) -> io::Result<()> {
@@ -710,8 +744,8 @@ pub mod stream {
710744
.engine
711745
.decode_slice(&self.pending[..self.pending_len], &mut decoded)
712746
.map_err(decode_error_to_io)?;
713-
self.inner.write_all(&decoded[..written])?;
714-
self.pending_len = 0;
747+
self.inner_mut().write_all(&decoded[..written])?;
748+
self.clear_pending();
715749
Ok(())
716750
}
717751

@@ -721,7 +755,7 @@ pub mod stream {
721755
.engine
722756
.decode_slice(&input, &mut decoded)
723757
.map_err(decode_error_to_io)?;
724-
self.inner.write_all(&decoded[..written])?;
758+
self.inner_mut().write_all(&decoded[..written])?;
725759
if written < 3 {
726760
self.finished = true;
727761
}
@@ -756,7 +790,7 @@ pub mod stream {
756790
quad[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
757791
quad[self.pending_len..].copy_from_slice(&input[..needed]);
758792
self.write_full_quad(quad)?;
759-
self.pending_len = 0;
793+
self.clear_pending();
760794
consumed += needed;
761795
if self.finished && consumed < input.len() {
762796
return Err(trailing_input_after_padding_error());
@@ -788,7 +822,7 @@ pub mod stream {
788822
}
789823

790824
fn flush(&mut self) -> io::Result<()> {
791-
self.inner.flush()
825+
self.inner_mut().flush()
792826
}
793827
}
794828

@@ -813,7 +847,7 @@ pub mod stream {
813847
where
814848
A: Alphabet,
815849
{
816-
inner: R,
850+
inner: Option<R>,
817851
engine: Engine<A, PAD>,
818852
pending: [u8; 4],
819853
pending_len: usize,
@@ -830,7 +864,7 @@ pub mod stream {
830864
#[must_use]
831865
pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
832866
Self {
833-
inner,
867+
inner: Some(inner),
834868
engine,
835869
pending: [0; 4],
836870
pending_len: 0,
@@ -842,19 +876,57 @@ pub mod stream {
842876

843877
/// Returns a shared reference to the wrapped reader.
844878
#[must_use]
845-
pub const fn get_ref(&self) -> &R {
846-
&self.inner
879+
pub fn get_ref(&self) -> &R {
880+
self.inner_ref()
847881
}
848882

849883
/// Returns a mutable reference to the wrapped reader.
850884
pub fn get_mut(&mut self) -> &mut R {
851-
&mut self.inner
885+
self.inner_mut()
852886
}
853887

854888
/// Consumes the decoder reader and returns the wrapped reader.
855889
#[must_use]
856-
pub fn into_inner(self) -> R {
857-
self.inner
890+
pub fn into_inner(mut self) -> R {
891+
self.take_inner()
892+
}
893+
894+
fn inner_ref(&self) -> &R {
895+
match &self.inner {
896+
Some(inner) => inner,
897+
None => unreachable!("stream decoder reader inner reader was already taken"),
898+
}
899+
}
900+
901+
fn inner_mut(&mut self) -> &mut R {
902+
match &mut self.inner {
903+
Some(inner) => inner,
904+
None => unreachable!("stream decoder reader inner reader was already taken"),
905+
}
906+
}
907+
908+
fn take_inner(&mut self) -> R {
909+
match self.inner.take() {
910+
Some(inner) => inner,
911+
None => unreachable!("stream decoder reader inner reader was already taken"),
912+
}
913+
}
914+
915+
fn clear_pending(&mut self) {
916+
self.pending.fill(0);
917+
self.pending_len = 0;
918+
}
919+
}
920+
921+
impl<R, A, const PAD: bool> Drop for DecoderReader<R, A, PAD>
922+
where
923+
A: Alphabet,
924+
{
925+
fn drop(&mut self) {
926+
self.clear_pending();
927+
for byte in &mut self.output {
928+
*byte = 0;
929+
}
858930
}
859931
}
860932

@@ -874,10 +946,12 @@ pub mod stream {
874946

875947
let mut written = 0;
876948
while written < output.len() {
877-
let Some(byte) = self.output.pop_front() else {
949+
let Some(byte) = self.output.front_mut() else {
878950
break;
879951
};
880-
output[written] = byte;
952+
output[written] = *byte;
953+
*byte = 0;
954+
let _ = self.output.pop_front();
881955
written += 1;
882956
}
883957

@@ -897,7 +971,8 @@ pub mod stream {
897971
}
898972

899973
let mut input = [0u8; 4];
900-
let read = self.inner.read(&mut input[..4 - self.pending_len])?;
974+
let available = 4 - self.pending_len;
975+
let read = self.inner_mut().read(&mut input[..available])?;
901976
if read == 0 {
902977
self.finished = true;
903978
self.push_final_pending()?;
@@ -911,7 +986,7 @@ pub mod stream {
911986
}
912987

913988
let quad = self.pending;
914-
self.pending_len = 0;
989+
self.clear_pending();
915990
self.push_decoded(&quad)?;
916991
if self.terminal_seen {
917992
self.finished = true;
@@ -927,7 +1002,7 @@ pub mod stream {
9271002
let mut pending = [0u8; 4];
9281003
pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
9291004
let pending_len = self.pending_len;
930-
self.pending_len = 0;
1005+
self.clear_pending();
9311006
self.push_decoded(&pending[..pending_len])
9321007
}
9331008

0 commit comments

Comments
 (0)