From 76c87734e793fc1a78fb8325bdb3b55f676de3ed Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Mon, 19 Aug 2024 14:19:41 +0200 Subject: [PATCH 1/2] fix: apply sign extension when decoding int --- src/buf/buf_impl.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/buf/buf_impl.rs b/src/buf/buf_impl.rs index c44d4fb38..9ef464075 100644 --- a/src/buf/buf_impl.rs +++ b/src/buf/buf_impl.rs @@ -66,6 +66,12 @@ macro_rules! buf_get_impl { }}; } +// https://en.wikipedia.org/wiki/Sign_extension +fn sign_extend(val: u64, nbytes: usize) -> i64 { + let shift = (8 - nbytes) * 8; + (val << shift) as i64 >> shift +} + /// Read bytes from a buffer. /// /// A buffer stores bytes in memory such that read operations are infallible. @@ -923,7 +929,7 @@ pub trait Buf { /// This function panics if there is not enough remaining data in `self`, or /// if `nbytes` is greater than 8. fn get_int(&mut self, nbytes: usize) -> i64 { - buf_get_impl!(be => self, i64, nbytes); + sign_extend(self.get_uint(nbytes), nbytes) } /// Gets a signed n-byte integer from `self` in little-endian byte order. @@ -944,7 +950,7 @@ pub trait Buf { /// This function panics if there is not enough remaining data in `self`, or /// if `nbytes` is greater than 8. fn get_int_le(&mut self, nbytes: usize) -> i64 { - buf_get_impl!(le => self, i64, nbytes); + sign_extend(self.get_uint_le(nbytes), nbytes) } /// Gets a signed n-byte integer from `self` in native-endian byte order. From 0895f62fc436013fb20f239719287e984ab620e4 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Mon, 19 Aug 2024 15:08:14 +0200 Subject: [PATCH 2/2] test: add regression test for #730 --- tests/test_buf.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_buf.rs b/tests/test_buf.rs index 3940f9247..5aadea43e 100644 --- a/tests/test_buf.rs +++ b/tests/test_buf.rs @@ -36,6 +36,19 @@ fn test_get_u16() { assert_eq!(0x5421, buf.get_u16_le()); } +#[test] +fn test_get_int() { + let mut buf = &b"\xd6zomg"[..]; + assert_eq!(-42, buf.get_int(1)); + let mut buf = &b"\xd6zomg"[..]; + assert_eq!(-42, buf.get_int_le(1)); + + let mut buf = &b"\xfe\x1d\xc0zomg"[..]; + assert_eq!(0xffffffffffc01dfeu64 as i64, buf.get_int_le(3)); + let mut buf = &b"\xfe\x1d\xc0zomg"[..]; + assert_eq!(0xfffffffffffe1dc0u64 as i64, buf.get_int(3)); +} + #[test] #[should_panic] fn test_get_u16_buffer_underflow() {