avm2: Fix edge cases in RegExp constructor

This commit is contained in:
Adrian Wielgosik 2023-03-27 20:50:55 +02:00 committed by Aaron Hill
parent fc4b51b20f
commit 4e84632609
4 changed files with 97 additions and 19 deletions

View File

@ -1,6 +1,7 @@
//! `RegExp` impl
use crate::avm2::class::Class;
use crate::avm2::error::type_error;
use crate::avm2::method::{Method, NativeMethodImpl, ParamConfig};
use crate::avm2::object::{regexp_allocator, ArrayObject, FunctionObject, Object, TObject};
use crate::avm2::regexp::RegExpFlags;
@ -27,16 +28,34 @@ pub fn instance_init<'gc>(
activation.super_init(this, &[])?;
if let Some(mut regexp) = this.as_regexp_mut(activation.context.gc_context) {
regexp.set_source(
args.get(0)
let source: AvmString<'gc> = match args.get(0) {
Some(Value::Undefined) => "".into(),
Some(Value::Object(Object::RegExpObject(o))) => {
if !matches!(args.get(1), Some(Value::Undefined)) {
return Err(Error::AvmError(type_error(
activation,
"Error #1100: Cannot supply flags when constructing one RegExp from another.",
1100,
)?));
}
let other = o.as_regexp().unwrap();
regexp.set_source(other.source());
regexp.set_flags(other.flags());
return Ok(Value::Undefined);
}
arg => arg
.unwrap_or(&Value::String("".into()))
.coerce_to_string(activation)?,
);
};
let flag_chars = args
.get(1)
.unwrap_or(&Value::String("".into()))
.coerce_to_string(activation)?;
regexp.set_source(source);
let flag_chars = match args.get(1) {
Some(Value::Undefined) => "".into(),
arg => arg
.unwrap_or(&Value::String("".into()))
.coerce_to_string(activation)?,
};
let mut flags = RegExpFlags::empty();
for c in &flag_chars {
@ -299,16 +318,8 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> GcCell<'gc, Cl
instance_init,
"<RegExp instance initializer>",
vec![
ParamConfig::optional(
"re",
Multiname::new(activation.avm2().public_namespace, "String"),
"",
),
ParamConfig::optional(
"flags",
Multiname::new(activation.avm2().public_namespace, "String"),
"",
),
ParamConfig::optional("re", Multiname::any(mc), Value::Undefined),
ParamConfig::optional("flags", Multiname::any(mc), Value::Undefined),
],
false,
mc,

View File

@ -14,8 +14,10 @@ trace("ignoreCase", re.ignoreCase);
trace("multiline", re.multiline);
trace("");
function test(source:String, flags:String) {
trace("// new RegExp(\"" + source + "\", \"" + flags + "\");");
function test(source:*, flags:*) {
var sourceStr = (typeof source === "string") ? "\"" + source + "\"" : source;
var flagsStr = (typeof flags === "string") ? "\"" + flags + "\"" : flags;
trace("// new RegExp(" + sourceStr + ", " + flagsStr + ");");
var re = new RegExp(source, flags);
trace(re);
trace(re.source == source);
@ -38,3 +40,19 @@ test("all flags", "sxgim");
test("invalid flags", "|%?-/.あa");
test("uppercase flags", "SXGIM");
test("duplicate flags", "ssgg");
test(undefined, undefined);
test(null, null);
test(/#((.*))$/m, undefined);
test(/empty flags/, undefined);
test(/dotall embedded flags/s, undefined);
try {
test(/empty string separate flag/s, "");
} catch(e) {
trace(e);
}
try {
test(/dotall separate flags/s, "s");
} catch(e) {
trace(e);
}

View File

@ -97,3 +97,52 @@ global true
ignoreCase false
multiline false
// new RegExp(undefined, undefined);
//
false
dotall false
extended false
global false
ignoreCase false
multiline false
// new RegExp(null, null);
/null/
false
dotall false
extended false
global false
ignoreCase false
multiline false
// new RegExp(/#((.*))$/m, undefined);
/#((.*))$/m
false
dotall false
extended false
global false
ignoreCase false
multiline true
// new RegExp(/empty flags/, undefined);
/empty flags/
false
dotall false
extended false
global false
ignoreCase false
multiline false
// new RegExp(/dotall embedded flags/s, undefined);
/dotall embedded flags/s
false
dotall true
extended false
global false
ignoreCase false
multiline false
// new RegExp(/empty string separate flag/s, "");
TypeError: Error #1100: Cannot supply flags when constructing one RegExp from another.
// new RegExp(/dotall separate flags/s, "s");
TypeError: Error #1100: Cannot supply flags when constructing one RegExp from another.