avm2: Some domain memory is available by default and error when range invalid
This commit is contained in:
parent
5a0cdf60bc
commit
f437539f73
|
@ -11,7 +11,7 @@ use crate::avm2::scope::Scope;
|
|||
use crate::avm2::script::Script;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::{value, Avm2, Error};
|
||||
use crate::avm2::{value, Avm2, Error, Domain};
|
||||
use crate::context::UpdateContext;
|
||||
use crate::swf::extensions::ReadSwfExt;
|
||||
use gc_arena::{Gc, GcCell, MutationContext};
|
||||
|
@ -21,6 +21,7 @@ use swf::avm2::types::{
|
|||
Class as AbcClass, Index, Method as AbcMethod, Multiname as AbcMultiname,
|
||||
Namespace as AbcNamespace, Op,
|
||||
};
|
||||
use crate::avm2::bytearray::ByteArrayStorage;
|
||||
|
||||
/// Represents a particular register set.
|
||||
///
|
||||
|
@ -2470,34 +2471,50 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
}
|
||||
|
||||
/// Implements `Op::Coerce`
|
||||
fn op_coerce(&mut self, _method: Gc<'gc, BytecodeMethod<'gc>>, _index: Index<AbcMultiname>) -> Result<FrameControl<'gc>, Error> {
|
||||
fn op_coerce(
|
||||
&mut self,
|
||||
_method: Gc<'gc, BytecodeMethod<'gc>>,
|
||||
_index: Index<AbcMultiname>,
|
||||
) -> Result<FrameControl<'gc>, Error> {
|
||||
//TODO: should check if x is a subclass of the given type when object and typeerror if not, see "instr.cpp::coerceImpl (287)"
|
||||
//TODO: update tests with typeof + description
|
||||
|
||||
let val = self.context.avm2.pop();
|
||||
|
||||
let x = match val {
|
||||
Value::Null | Value::Undefined => {
|
||||
Value::Null
|
||||
},
|
||||
Value::Number(_) | Value::String(_) | Value::Unsigned(_) | Value::Integer(_) | Value::Bool(_) => Value::Object(val.coerce_to_object(self)?),
|
||||
Value::Object(_) => {
|
||||
val
|
||||
}
|
||||
Value::Null | Value::Undefined => Value::Null,
|
||||
Value::Number(_)
|
||||
| Value::String(_)
|
||||
| Value::Unsigned(_)
|
||||
| Value::Integer(_)
|
||||
| Value::Bool(_) => Value::Object(val.coerce_to_object(self)?),
|
||||
Value::Object(_) => val,
|
||||
};
|
||||
|
||||
self.context.avm2.push(x);
|
||||
Ok(FrameControl::Continue)
|
||||
}
|
||||
|
||||
fn domain_memory(&self) -> Result<GcCell<'gc, ByteArrayStorage>, Error> {
|
||||
self.scope().map(|s| s.read().globals()).and_then(|g| g.as_application_domain()).map(|d| d.domain_memory())
|
||||
.ok_or_else(|| "No domain memory assigned".into())
|
||||
}
|
||||
|
||||
/// Implements `Op::Si8`
|
||||
fn op_si8(&mut self) -> Result<FrameControl<'gc>, Error> {
|
||||
let address = self.context.avm2.pop();
|
||||
let val = self.context.avm2.pop();
|
||||
let address = self.context.avm2.pop().coerce_to_i32(self)?;
|
||||
let val = self.context.avm2.pop().coerce_to_i32(self)?;
|
||||
|
||||
let dm = self.scope().unwrap().read().globals().as_application_domain().unwrap().domain_memory().expect("Not domain memory?");
|
||||
let mut ba = dm.as_bytearray_mut(self.context.gc_context).unwrap();
|
||||
ba.write_bytes_at(&[val.coerce_to_i32(self)? as u8], address.coerce_to_i32(self)? as usize);
|
||||
let dm = self.domain_memory().expect("Not domain memory?");
|
||||
|
||||
if address < 0 || address as usize >= dm.read().len() {
|
||||
return Err("RangeError: The specified range is invalid".into());
|
||||
}
|
||||
|
||||
dm.write(self.context.gc_context).write_bytes_at(
|
||||
&[(val & 0xFF) as u8],
|
||||
address as usize,
|
||||
);
|
||||
|
||||
Ok(FrameControl::Continue)
|
||||
}
|
||||
|
@ -2506,11 +2523,15 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
fn op_li8(&mut self) -> Result<FrameControl<'gc>, Error> {
|
||||
let address = self.context.avm2.pop().coerce_to_u32(self)? as usize;
|
||||
|
||||
let dm = self.scope().unwrap().read().globals().as_application_domain().unwrap().domain_memory().expect("Not domain memory?");
|
||||
let mut ba = dm.as_bytearray_mut(self.context.gc_context).unwrap();
|
||||
let x = ba.bytes().iter().nth(address).copied().unwrap();
|
||||
let dm = self.domain_memory().expect("Not domain memory?");
|
||||
let val = dm.read().get(address);
|
||||
drop(dm);
|
||||
|
||||
self.context.avm2.push(Value::Integer(x as i32));
|
||||
if let Some(val) = val {
|
||||
self.context.avm2.push(Value::Integer(val as i32));
|
||||
} else {
|
||||
return Err("RangeError: The specified range is invalid".into());
|
||||
}
|
||||
|
||||
Ok(FrameControl::Continue)
|
||||
}
|
||||
|
|
|
@ -37,6 +37,15 @@ impl ByteArrayStorage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new ByteArrayStorage with given initial data and endianness
|
||||
pub fn with_initial(bytes: Vec<u8>, endian: Endian) -> Self {
|
||||
Self {
|
||||
bytes,
|
||||
position: 0,
|
||||
endian
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a byte at next position in the bytearray
|
||||
pub fn write_byte(&mut self, byte: u8) {
|
||||
let bytes_len = self.bytes.len();
|
||||
|
@ -329,6 +338,10 @@ impl ByteArrayStorage {
|
|||
pub fn set_endian(&mut self, new_endian: Endian) {
|
||||
self.endian = new_endian;
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.bytes.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for ByteArrayStorage {
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::names::{Multiname, QName};
|
||||
use crate::avm2::object::TObject;
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::object::TObject;
|
||||
use crate::avm2::script::Script;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
use std::collections::HashMap;
|
||||
use crate::avm2::bytearray::{ByteArrayStorage, Endian};
|
||||
|
||||
/// Represents a set of scripts and movies that share traits across different
|
||||
/// script-global scopes.
|
||||
|
@ -26,7 +27,7 @@ struct DomainData<'gc> {
|
|||
parent: Option<Domain<'gc>>,
|
||||
|
||||
/// The bytearray used for storing domain memory
|
||||
pub domain_memory: Option<Object<'gc>>
|
||||
pub domain_memory: GcCell<'gc, ByteArrayStorage>,
|
||||
}
|
||||
|
||||
impl<'gc> Domain<'gc> {
|
||||
|
@ -40,7 +41,7 @@ impl<'gc> Domain<'gc> {
|
|||
DomainData {
|
||||
defs: HashMap::new(),
|
||||
parent: None,
|
||||
domain_memory: None,
|
||||
domain_memory: GcCell::allocate(mc, ByteArrayStorage::with_initial(vec![0; 100], Endian::Little)),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ impl<'gc> Domain<'gc> {
|
|||
DomainData {
|
||||
defs: HashMap::new(),
|
||||
parent: Some(parent),
|
||||
domain_memory: None
|
||||
domain_memory: GcCell::allocate(mc, ByteArrayStorage::with_initial(vec![0; 100], Endian::Little)),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -153,11 +154,11 @@ impl<'gc> Domain<'gc> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn domain_memory(&self) -> Option<Object<'gc>> {
|
||||
pub fn domain_memory(&self) -> GcCell<'gc, ByteArrayStorage> {
|
||||
self.0.read().domain_memory
|
||||
}
|
||||
|
||||
pub fn set_domain_memory(&self, mc: MutationContext<'gc, '_>, domain_memory: Object<'gc>) {
|
||||
self.0.write(mc).domain_memory = Some(domain_memory)
|
||||
pub fn set_domain_memory(&self, mc: MutationContext<'gc, '_>, domain_memory: GcCell<'gc, ByteArrayStorage>) {
|
||||
self.0.write(mc).domain_memory = domain_memory
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,10 +125,9 @@ pub fn set_domain_memory<'gc>(
|
|||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(d) = args.get(0) {
|
||||
let o = d.coerce_to_object(activation)?;
|
||||
//TODO: same domain as the one in avm2?
|
||||
if let Some(appdomain) = this.and_then(|this| this.as_application_domain()) {
|
||||
appdomain.set_domain_memory(activation.context.gc_context, o);
|
||||
// let o = d.coerce_to_object(activation)?.as;
|
||||
// appdomain.set_domain_memory(activation.context.gc_context, o);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,11 +140,11 @@ pub fn domain_memory<'gc>(
|
|||
this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(appdomain) = this.and_then(|this| this.as_application_domain()) {
|
||||
if let Some(o) = appdomain.domain_memory() {
|
||||
return Ok(o.into());
|
||||
}
|
||||
}
|
||||
// if let Some(appdomain) = this.and_then(|this| this.as_application_domain()) {
|
||||
// if let Some(o) = appdomain.domain_memory() {
|
||||
// return Ok(o.into());
|
||||
// }
|
||||
// }
|
||||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
// li8()
|
||||
10
|
||||
// li8(0) after si8(65, 0)
|
||||
65
|
||||
// domain
|
||||
// li8(0) after si8(255, 0)
|
||||
255
|
||||
// domain
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue