From 43284a0a5a709c7c299b1d2c15136e24f9b71031 Mon Sep 17 00:00:00 2001 From: Teddy Tennant Date: Wed, 8 Jul 2026 16:59:20 -0400 Subject: [PATCH] fix: sign-extend n-byte integers in try_get_int/try_get_int_le `Buf::try_get_int` and `Buf::try_get_int_le` read the requested bytes into the low bytes of a zeroed `[u8; 8]`, so for `nbytes < 8` the high bytes stayed zero and no sign extension happened. A negative value such as the 3-byte `0xffffff` was returned as `16777215` instead of `-1`, unlike the panicking `get_int`/`get_int_le` which sign-extend via `sign_extend`. Make the fallible getters mirror their panicking counterparts by sign-extending the result of `try_get_uint`/`try_get_uint_le`. `try_get_int_ne` delegates to these and is fixed transitively. Error and panic behavior is unchanged. --- src/buf/buf_impl.rs | 4 ++-- tests/test_buf.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs index 6508567b4..2497a78ff 100644 --- a/src/buf/buf_impl.rs +++ b/src/buf/buf_impl.rs @@ -2084,7 +2084,7 @@ pub trait Buf { /// /// This function panics if `nbytes` is greater than 8. fn try_get_int(&mut self, nbytes: usize) -> Result { - buf_try_get_impl!(be => self, i64, nbytes); + Ok(sign_extend(self.try_get_uint(nbytes)?, nbytes)) } /// Gets a signed n-byte integer from `self` in little-endian byte order. @@ -2116,7 +2116,7 @@ pub trait Buf { /// /// This function panics if `nbytes` is greater than 8. fn try_get_int_le(&mut self, nbytes: usize) -> Result { - buf_try_get_impl!(le => self, i64, nbytes); + Ok(sign_extend(self.try_get_uint_le(nbytes)?, nbytes)) } /// Gets a signed n-byte integer from `self` in native-endian byte order. diff --git a/tests/test_buf.rs b/tests/test_buf.rs index 1520df897..4dbfbeab2 100644 --- a/tests/test_buf.rs +++ b/tests/test_buf.rs @@ -459,3 +459,35 @@ fn copy_to_bytes_mut() { let bytes_mut2 = BytesMut::from(ret); assert_eq!(bytes_mut2.as_ptr(), ptr); } + +#[test] +fn try_get_int_sign_extends() { + use ::bytes::TryGetError; + // 3-byte big-endian 0xffffff == -1; must match get_int + let mut a = &[0xff, 0xff, 0xff][..]; + assert_eq!(a.try_get_int(3), Ok(-1)); + assert_eq!(a.remaining(), 0); + let mut ctrl = &[0xff, 0xff, 0xff][..]; + assert_eq!(ctrl.get_int(3), -1); + // little-endian variant + let mut le = &[0xff, 0xff, 0xff][..]; + assert_eq!(le.try_get_int_le(3), Ok(-1)); + // native-endian delegates + let mut ne = &[0xff, 0xff, 0xff][..]; + assert_eq!(ne.try_get_int_ne(3), Ok(-1)); + // positive value unchanged + let mut pos = &[0x01, 0x02, 0x03][..]; + assert_eq!(pos.try_get_int(3), Ok(0x010203)); + // full width + let mut full = &[0xff; 8][..]; + assert_eq!(full.try_get_int(8), Ok(-1)); + // insufficient data still errors with the documented shape + let mut short = &[0x01, 0x02, 0x03][..]; + assert_eq!( + short.try_get_int(4), + Err(TryGetError { + requested: 4, + available: 3 + }) + ); +}