From dad21d43986a9f51a535cca9747b3f1198738f18 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 10 Feb 2021 22:56:17 +0100 Subject: [PATCH] swf: Make avm2 Reader operate directly with byte slices --- core/src/avm1/activation.rs | 18 +---- core/src/avm2/activation.rs | 146 ++++++++++++++++++++---------------- swf/src/avm1/read.rs | 7 ++ swf/src/avm2/read.rs | 28 ++++--- 4 files changed, 103 insertions(+), 96 deletions(-) diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index 4d43ef138..8b532f580 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -1460,7 +1460,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { ) -> Result, Error<'gc>> { let val = self.context.avm1.pop(); if val.as_bool(self.current_swf_version()) { - self.seek(jump_offset, reader, data)?; + reader.seek(data.as_ref(), jump_offset); } Ok(FrameControl::Continue) } @@ -1543,7 +1543,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { reader: &mut Reader<'b>, data: &'b SwfSlice, ) -> Result, Error<'gc>> { - self.seek(jump_offset, reader, data)?; + reader.seek(data.as_ref(), jump_offset); Ok(FrameControl::Continue) } @@ -3008,18 +3008,4 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(FrameControl::Continue) } } - - fn seek<'b>( - &self, - jump_offset: i16, - reader: &mut Reader<'b>, - data: &'b SwfSlice, - ) -> Result<(), Error<'gc>> { - let slice = data.movie.data(); - let mut pos = reader.get_ref().as_ptr() as usize - slice.as_ptr() as usize; - pos = (pos as isize + isize::from(jump_offset)) as usize; - pos = pos.min(slice.len()); - *reader.get_mut() = &slice[pos as usize..]; - Ok(()) - } } diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 5ac0042ed..416a92ec6 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -15,7 +15,6 @@ use crate::avm2::{value, Avm2, Error}; use crate::context::UpdateContext; use gc_arena::{Gc, GcCell, MutationContext}; use smallvec::SmallVec; -use std::io::Cursor; use swf::avm2::read::Reader; use swf::avm2::types::{ Class as AbcClass, Index, Method as AbcMethod, Multiname as AbcMultiname, @@ -507,10 +506,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let body: Result<_, Error> = method .body() .ok_or_else(|| "Cannot execute non-native method without body".into()); - let mut read = Reader::new(Cursor::new(body?.code.as_ref())); + let body = body?; + let mut reader = Reader::new(&body.code); loop { - let result = self.do_next_opcode(method, &mut read); + let result = self.do_next_opcode(method, &mut reader, &body.code); match result { Ok(FrameControl::Return(value)) => break Ok(value), Ok(FrameControl::Continue) => {} @@ -520,10 +520,11 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { } /// Run a single action from a given action reader. - fn do_next_opcode( + fn do_next_opcode<'b>( &mut self, method: Gc<'gc, BytecodeMethod<'gc>>, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { if self.context.update_start.elapsed() >= self.context.max_execution_duration { return Err( @@ -635,21 +636,21 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Op::SubtractI => self.op_subtract_i(), Op::Swap => self.op_swap(), Op::URShift => self.op_urshift(), - Op::Jump { offset } => self.op_jump(offset, reader), - Op::IfTrue { offset } => self.op_if_true(offset, reader), - Op::IfFalse { offset } => self.op_if_false(offset, reader), - Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader), - Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader), - Op::IfEq { offset } => self.op_if_eq(offset, reader), - Op::IfNe { offset } => self.op_if_ne(offset, reader), - Op::IfGe { offset } => self.op_if_ge(offset, reader), - Op::IfGt { offset } => self.op_if_gt(offset, reader), - Op::IfLe { offset } => self.op_if_le(offset, reader), - Op::IfLt { offset } => self.op_if_lt(offset, reader), - Op::IfNge { offset } => self.op_if_nge(offset, reader), - Op::IfNgt { offset } => self.op_if_ngt(offset, reader), - Op::IfNle { offset } => self.op_if_nle(offset, reader), - Op::IfNlt { offset } => self.op_if_nlt(offset, reader), + Op::Jump { offset } => self.op_jump(offset, reader, full_data), + Op::IfTrue { offset } => self.op_if_true(offset, reader, full_data), + Op::IfFalse { offset } => self.op_if_false(offset, reader, full_data), + Op::IfStrictEq { offset } => self.op_if_strict_eq(offset, reader, full_data), + Op::IfStrictNe { offset } => self.op_if_strict_ne(offset, reader, full_data), + Op::IfEq { offset } => self.op_if_eq(offset, reader, full_data), + Op::IfNe { offset } => self.op_if_ne(offset, reader, full_data), + Op::IfGe { offset } => self.op_if_ge(offset, reader, full_data), + Op::IfGt { offset } => self.op_if_gt(offset, reader, full_data), + Op::IfLe { offset } => self.op_if_le(offset, reader, full_data), + Op::IfLt { offset } => self.op_if_lt(offset, reader, full_data), + Op::IfNge { offset } => self.op_if_nge(offset, reader, full_data), + Op::IfNgt { offset } => self.op_if_ngt(offset, reader, full_data), + Op::IfNle { offset } => self.op_if_nle(offset, reader, full_data), + Op::IfNlt { offset } => self.op_if_nlt(offset, reader, full_data), Op::StrictEquals => self.op_strict_equals(), Op::Equals => self.op_equals(), Op::GreaterEquals => self.op_greater_equals(), @@ -1834,219 +1835,234 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(FrameControl::Continue) } - fn op_jump( + fn op_jump<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); Ok(FrameControl::Continue) } - fn op_if_true( + fn op_if_true<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value = self.context.avm2.pop().coerce_to_boolean(); if value { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_false( + fn op_if_false<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value = self.context.avm2.pop().coerce_to_boolean(); if !value { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_strict_eq( + fn op_if_strict_eq<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1 == value2 { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_strict_ne( + fn op_if_strict_ne<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1 != value2 { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_eq( + fn op_if_eq<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_eq(&value2, self)? { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_ne( + fn op_if_ne<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if !value1.abstract_eq(&value2, self)? { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_ge( + fn op_if_ge<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_lt(&value2, self)? == Some(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_gt( + fn op_if_gt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value2.abstract_lt(&value1, self)? == Some(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_le( + fn op_if_le<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value2.abstract_lt(&value1, self)? == Some(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_lt( + fn op_if_lt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_lt(&value2, self)? == Some(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_nge( + fn op_if_nge<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value1.abstract_lt(&value2, self)?.unwrap_or(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_ngt( + fn op_if_ngt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if !value2.abstract_lt(&value1, self)?.unwrap_or(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_nle( + fn op_if_nle<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if value2.abstract_lt(&value1, self)?.unwrap_or(true) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) } - fn op_if_nlt( + fn op_if_nlt<'b>( &mut self, offset: i32, - reader: &mut Reader>, + reader: &mut Reader<'b>, + full_data: &'b [u8], ) -> Result, Error> { let value2 = self.context.avm2.pop(); let value1 = self.context.avm2.pop(); if !value1.abstract_lt(&value2, self)?.unwrap_or(false) { - reader.seek(offset as i64)?; + reader.seek(full_data, offset); } Ok(FrameControl::Continue) diff --git a/swf/src/avm1/read.rs b/swf/src/avm1/read.rs index 68ab53d67..54e0ff4cd 100644 --- a/swf/src/avm1/read.rs +++ b/swf/src/avm1/read.rs @@ -29,6 +29,13 @@ impl<'a> Reader<'a> { } } + pub fn seek(&mut self, data: &'a [u8], jump_offset: i16) { + let mut pos = self.input.as_ptr() as usize - data.as_ptr() as usize; + pos = (pos as isize + isize::from(jump_offset)) as usize; + pos = pos.min(data.len()); + self.input = &data[pos as usize..]; + } + #[inline] pub fn encoding(&self) -> &'static Encoding { SwfStr::encoding_for_version(self.version) diff --git a/swf/src/avm2/read.rs b/swf/src/avm2/read.rs index 65aa1b34f..fa21f7387 100644 --- a/swf/src/avm2/read.rs +++ b/swf/src/avm2/read.rs @@ -2,25 +2,23 @@ use crate::avm2::types::*; use crate::error::{Error, Result}; use crate::read::SwfReadExt; use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{self, Read, Seek, SeekFrom}; +use std::io::{self, Read}; -pub struct Reader { - input: R, +pub struct Reader<'a> { + input: &'a [u8], } -impl Reader -where - R: Read + Seek, -{ - #[inline] - pub fn seek(&mut self, relative_offset: i64) -> std::io::Result { - self.input.seek(SeekFrom::Current(relative_offset as i64)) +impl<'a> Reader<'a> { + pub fn new(input: &'a [u8]) -> Self { + Self { input } } -} -impl Reader { - pub fn new(input: R) -> Reader { - Reader { input } + #[inline] + pub fn seek(&mut self, data: &'a [u8], relative_offset: i32) { + let mut pos = self.input.as_ptr() as usize - data.as_ptr() as usize; + pos = (pos as isize + relative_offset as isize) as usize; + pos = pos.min(data.len()); + self.input = &data[pos as usize..]; } pub fn read(&mut self) -> Result { @@ -861,7 +859,7 @@ impl Reader { } } -impl<'a, R: 'a + Read> SwfReadExt for Reader { +impl<'a> SwfReadExt for Reader<'a> { #[inline] fn read_u8(&mut self) -> io::Result { self.input.read_u8()