diff --git a/binrw/src/io/take_seek.rs b/binrw/src/io/take_seek.rs index bcae41a0..083eeaf4 100644 --- a/binrw/src/io/take_seek.rs +++ b/binrw/src/io/take_seek.rs @@ -91,15 +91,18 @@ impl Read for TakeSeek { impl Seek for TakeSeek { fn seek(&mut self, pos: SeekFrom) -> Result { let pos = match pos { - SeekFrom::End(end) => match self.end.checked_add_signed(end) { - Some(pos) => SeekFrom::Start(pos), - None => { - return Err(super::Error::new( - super::ErrorKind::InvalidInput, - "invalid seek to a negative or overflowing position", - )) + SeekFrom::End(end) => { + let inner_end = self.inner.seek(SeekFrom::End(0))?; + match self.end.min(inner_end).checked_add_signed(end) { + Some(pos) => SeekFrom::Start(pos), + None => { + return Err(super::Error::new( + super::ErrorKind::InvalidInput, + "invalid seek to a negative or overflowing position", + )) + } } - }, + } pos => pos, }; self.pos = self.inner.seek(pos)?; diff --git a/binrw/tests/io/take_seek.rs b/binrw/tests/io/take_seek.rs index e5a2e5d8..4fd7a61d 100644 --- a/binrw/tests/io/take_seek.rs +++ b/binrw/tests/io/take_seek.rs @@ -4,6 +4,7 @@ use binrw::io::{Cursor, Read, Seek, SeekFrom, TakeSeekExt}; #[test] fn take_seek() { let data = &mut Cursor::new(b"hello world".to_vec()); + let data_size = u64::try_from(data.get_ref().len()).unwrap(); let mut buf = [0; 5]; let mut take = data.take_seek(6); @@ -99,6 +100,14 @@ fn take_seek() { take.seek(SeekFrom::End(-5)) .expect_err("out-of-range `SeekFrom::End` backward seek should fail"); + take.set_limit(data_size + 1); + take.seek(SeekFrom::End(-1)).unwrap(); + assert_eq!( + take.read(&mut buf).unwrap(), + 1, + "`SeekFrom::End` did not bound to the true end of the stream" + ); + take.seek(SeekFrom::Start(0)).unwrap(); take.set_limit(10); assert_eq!(