From b6ed00435dc48be944f2373a34b07b7a11fd6900 Mon Sep 17 00:00:00 2001 From: GuTS805 Date: Sun, 9 Aug 2026 21:01:23 +0530 Subject: [PATCH] codec: fix broken length_delimited builder doc examples (#8350) The Builder::new, new_codec, and new_read doc examples combined length_adjustment(0) with num_skip(0). This leaves the length header bytes in the buffer without accounting for them, so decoding returns a frame that includes the raw header at the front and is short at the back, corrupting the following frame. Drop num_skip(0) so the default (skip the header) behavior applies, and turn all three examples into executable doctests that perform a real encode/decode round-trip and assert on the payload, so this class of bug is caught automatically going forward. Fixes: #8348 --- tokio-util/src/codec/length_delimited.rs | 38 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/tokio-util/src/codec/length_delimited.rs b/tokio-util/src/codec/length_delimited.rs index abc6461b5..e114426c2 100644 --- a/tokio-util/src/codec/length_delimited.rs +++ b/tokio-util/src/codec/length_delimited.rs @@ -679,18 +679,21 @@ impl Builder { /// # Examples /// /// ``` - /// # use tokio::io::AsyncRead; /// use tokio_util::codec::LengthDelimitedCodec; + /// use tokio_stream::StreamExt; /// - /// # fn bind_read(io: T) { - /// LengthDelimitedCodec::builder() + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn main() { + /// let io: &[u8] = b"\x00\x0bhello world"; + /// let mut reader = LengthDelimitedCodec::builder() /// .length_field_offset(0) /// .length_field_type::() /// .length_adjustment(0) - /// .num_skip(0) /// .new_read(io); + /// + /// let frame = reader.next().await.unwrap().unwrap(); + /// assert_eq!(&frame[..], b"hello world"); /// # } - /// # pub fn main() {} /// ``` pub fn new() -> Builder { Builder { @@ -953,14 +956,20 @@ impl Builder { /// # Examples /// /// ``` - /// use tokio_util::codec::LengthDelimitedCodec; + /// use bytes::{Bytes, BytesMut}; + /// use tokio_util::codec::{Decoder, Encoder, LengthDelimitedCodec}; + /// /// # pub fn main() { - /// LengthDelimitedCodec::builder() + /// let mut codec = LengthDelimitedCodec::builder() /// .length_field_offset(0) /// .length_field_type::() /// .length_adjustment(0) - /// .num_skip(0) /// .new_codec(); + /// + /// let mut buf = BytesMut::new(); + /// codec.encode(Bytes::from_static(b"hello world"), &mut buf).unwrap(); + /// let frame = codec.decode(&mut buf).unwrap().unwrap(); + /// assert_eq!(&frame[..], b"hello world"); /// # } /// ``` pub fn new_codec(&self) -> LengthDelimitedCodec { @@ -979,18 +988,21 @@ impl Builder { /// # Examples /// /// ``` - /// # use tokio::io::AsyncRead; /// use tokio_util::codec::LengthDelimitedCodec; + /// use tokio_stream::StreamExt; /// - /// # fn bind_read(io: T) { - /// LengthDelimitedCodec::builder() + /// # #[tokio::main(flavor = "current_thread")] + /// # async fn main() { + /// let io: &[u8] = b"\x00\x0bhello world"; + /// let mut reader = LengthDelimitedCodec::builder() /// .length_field_offset(0) /// .length_field_type::() /// .length_adjustment(0) - /// .num_skip(0) /// .new_read(io); + /// + /// let frame = reader.next().await.unwrap().unwrap(); + /// assert_eq!(&frame[..], b"hello world"); /// # } - /// # pub fn main() {} /// ``` pub fn new_read(&self, upstream: T) -> FramedRead where