From 79fb85323cf4cf14d9b85f487b65fc147030cf4b Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Fri, 30 Aug 2024 14:20:29 +0200 Subject: [PATCH] fix: apply sign extension when decoding int (#732) Closes #730 --- src/buf/buf_impl.rs | 10 ++++++++-- tests/test_buf.rs | 13 +++++++++++++ 2 files changed, 21 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. 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() {