avm1: Fix string methods handling of negative args (fix #4437)

* Improve string.substr handling of negative args
* Add tests for more substr() combinations
This commit is contained in:
Adrian Wielgosik 2021-05-30 21:04:17 +02:00 committed by GitHub
parent b4dd64a568
commit 34d54dbc05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 298 additions and 69 deletions

View File

@ -345,13 +345,19 @@ fn substr<'gc>(
let this_val = Value::from(this); let this_val = Value::from(this);
let this = this_val.coerce_to_string(activation)?; let this = this_val.coerce_to_string(activation)?;
let this_len = this.encode_utf16().count(); let this_len = this.encode_utf16().count();
let start_index_raw = args.get(0).unwrap().coerce_to_i32(activation)?; let start_index = string_wrapping_index(
let start_index = string_wrapping_index(start_index_raw, this_len); args.get(0)
.unwrap_or(&Value::Undefined)
.coerce_to_i32(activation)?,
this_len,
);
let len = match args.get(1) { let len = match args.get(1) {
None | Some(Value::Undefined) => this_len, None | Some(Value::Undefined) => this_len as i32,
Some(n) => string_index_substr(start_index_raw, n.coerce_to_i32(activation)?, this_len), Some(n) => n.coerce_to_i32(activation)?,
}; };
let end_index = string_wrapping_index((start_index as i32) + len, this_len);
let len = end_index.saturating_sub(start_index);
let ret = string_utils::utf16_iter_to_string(this.encode_utf16().skip(start_index).take(len)); let ret = string_utils::utf16_iter_to_string(this.encode_utf16().skip(start_index).take(len));
Ok(AvmString::new(activation.context.gc_context, ret).into()) Ok(AvmString::new(activation.context.gc_context, ret).into())
@ -441,15 +447,10 @@ fn to_upper_case<'gc>(
/// Normalizes an index parameter used in `String` functions such as `substring`. /// Normalizes an index parameter used in `String` functions such as `substring`.
/// The returned index will be within the range of `[0, len]`. /// The returned index will be within the range of `[0, len]`.
fn string_index(i: i32, len: usize) -> usize { fn string_index(i: i32, len: usize) -> usize {
if i > 0 { if i < 0 {
let i = i as usize;
if i < len {
i
} else {
len
}
} else {
0 0
} else {
(i as usize).min(len)
} }
} }
@ -457,41 +458,10 @@ fn string_index(i: i32, len: usize) -> usize {
/// Negative values will count backwards from `len`. /// Negative values will count backwards from `len`.
/// The returned index will be within the range of `[0, len]`. /// The returned index will be within the range of `[0, len]`.
fn string_wrapping_index(i: i32, len: usize) -> usize { fn string_wrapping_index(i: i32, len: usize) -> usize {
if i >= 0 { if i < 0 {
let i = i as usize; let offset = i as isize;
if i < len { len.saturating_sub((-offset) as usize)
i
} else { } else {
len (i as usize).min(len)
}
} else {
let i = (-i) as usize;
if i <= len {
len - i
} else {
len
}
}
}
/// Normalizes an index parameter used in substr.
/// If start + length is not less than zero, the parameter is zero,
/// otherwise negative values will count backwards from `len`.
/// The returned index will be within the range of `[0, len]`.
fn string_index_substr(s: i32, e: i32, len: usize) -> usize {
if e >= 0 {
string_index(e, len)
} else {
let t = s + e;
if t >= 0 {
0
} else {
let e = (-e) as usize;
if e <= len {
len - e
} else {
len
}
}
} }
} }

View File

@ -182,8 +182,8 @@ swf_tests! {
(slash_syntax, "avm1/slash_syntax", 2), (slash_syntax, "avm1/slash_syntax", 2),
(strictequals_swf6, "avm1/strictequals_swf6", 1), (strictequals_swf6, "avm1/strictequals_swf6", 1),
(string_methods, "avm1/string_methods", 1), (string_methods, "avm1/string_methods", 1),
(string_methods_negative_args, "avm1/string_methods_negative_args", 1),
(string_ops_swf6, "avm1/string_ops_swf6", 1), (string_ops_swf6, "avm1/string_ops_swf6", 1),
(substr_negative, "avm1/substr_negative", 1),
(path_string, "avm1/path_string", 1), (path_string, "avm1/path_string", 1),
(global_is_bare, "avm1/global_is_bare", 1), (global_is_bare, "avm1/global_is_bare", 1),
(primitive_type_globals, "avm1/primitive_type_globals", 1), (primitive_type_globals, "avm1/primitive_type_globals", 1),

View File

@ -0,0 +1,39 @@
// Compile with:
// mtasc -main -header 200:150:30 Test.as -swf test.swf
class Test {
static function main(current) {
trace("// var str = hello world");
var str = "hello world";
trace("// str.substr(0, -1)");
trace(str.substr(0,-1));
trace("// str.substr(0, -4)");
trace(str.substr(0,-4));
trace("// str.substr(8, -4)");
trace(str.substr(8,-4));
trace("// str.substr(3, -3)");
trace(str.substr(3,-3));
trace("// str.substr(3, -4)");
trace(str.substr(3,-4));
trace("// str.substr(3, -5)");
trace(str.substr(3,-5));
trace("// str.substr(4, -4)");
trace(str.substr(4,-4));
trace("// str.substr(4, -5)");
trace(str.substr(4,-5));
trace("// str.substr(null, -1)");
trace(str.substr(null,-1));
trace("// str.substr(undefined, -1)");
trace(str.substr(undefined,-1));
var text = "abcd";
for (var i = -5; i < 5; i += 1) {
trace("// text.substr(" + i + ")");
trace(text.substr(i));
for (var j = -5; j < 5; j += 1) {
trace("// text.substr(" + i + "," + j + ")");
trace(text.substr(i, j));
}
}
}
}

View File

@ -0,0 +1,241 @@
// var str = hello world
// str.substr(0, -1)
hello worl
// str.substr(0, -4)
hello w
// str.substr(8, -4)
// str.substr(3, -3)
// str.substr(3, -4)
lo worl
// str.substr(3, -5)
lo wor
// str.substr(4, -4)
// str.substr(4, -5)
o worl
// str.substr(null, -1)
hello worl
// str.substr(undefined, -1)
hello worl
// text.substr(-5)
abcd
// text.substr(-5,-5)
// text.substr(-5,-4)
// text.substr(-5,-3)
a
// text.substr(-5,-2)
ab
// text.substr(-5,-1)
abc
// text.substr(-5,0)
// text.substr(-5,1)
a
// text.substr(-5,2)
ab
// text.substr(-5,3)
abc
// text.substr(-5,4)
abcd
// text.substr(-4)
abcd
// text.substr(-4,-5)
// text.substr(-4,-4)
// text.substr(-4,-3)
a
// text.substr(-4,-2)
ab
// text.substr(-4,-1)
abc
// text.substr(-4,0)
// text.substr(-4,1)
a
// text.substr(-4,2)
ab
// text.substr(-4,3)
abc
// text.substr(-4,4)
abcd
// text.substr(-3)
bcd
// text.substr(-3,-5)
// text.substr(-3,-4)
// text.substr(-3,-3)
b
// text.substr(-3,-2)
bc
// text.substr(-3,-1)
// text.substr(-3,0)
// text.substr(-3,1)
b
// text.substr(-3,2)
bc
// text.substr(-3,3)
bcd
// text.substr(-3,4)
bcd
// text.substr(-2)
cd
// text.substr(-2,-5)
// text.substr(-2,-4)
// text.substr(-2,-3)
c
// text.substr(-2,-2)
// text.substr(-2,-1)
// text.substr(-2,0)
// text.substr(-2,1)
c
// text.substr(-2,2)
cd
// text.substr(-2,3)
cd
// text.substr(-2,4)
cd
// text.substr(-1)
d
// text.substr(-1,-5)
// text.substr(-1,-4)
// text.substr(-1,-3)
// text.substr(-1,-2)
// text.substr(-1,-1)
// text.substr(-1,0)
// text.substr(-1,1)
d
// text.substr(-1,2)
d
// text.substr(-1,3)
d
// text.substr(-1,4)
d
// text.substr(0)
abcd
// text.substr(0,-5)
// text.substr(0,-4)
// text.substr(0,-3)
a
// text.substr(0,-2)
ab
// text.substr(0,-1)
abc
// text.substr(0,0)
// text.substr(0,1)
a
// text.substr(0,2)
ab
// text.substr(0,3)
abc
// text.substr(0,4)
abcd
// text.substr(1)
bcd
// text.substr(1,-5)
// text.substr(1,-4)
// text.substr(1,-3)
b
// text.substr(1,-2)
bc
// text.substr(1,-1)
// text.substr(1,0)
// text.substr(1,1)
b
// text.substr(1,2)
bc
// text.substr(1,3)
bcd
// text.substr(1,4)
bcd
// text.substr(2)
cd
// text.substr(2,-5)
// text.substr(2,-4)
// text.substr(2,-3)
c
// text.substr(2,-2)
// text.substr(2,-1)
// text.substr(2,0)
// text.substr(2,1)
c
// text.substr(2,2)
cd
// text.substr(2,3)
cd
// text.substr(2,4)
cd
// text.substr(3)
d
// text.substr(3,-5)
// text.substr(3,-4)
// text.substr(3,-3)
// text.substr(3,-2)
// text.substr(3,-1)
// text.substr(3,0)
// text.substr(3,1)
d
// text.substr(3,2)
d
// text.substr(3,3)
d
// text.substr(3,4)
d
// text.substr(4)
// text.substr(4,-5)
// text.substr(4,-4)
// text.substr(4,-3)
// text.substr(4,-2)
// text.substr(4,-1)
// text.substr(4,0)
// text.substr(4,1)
// text.substr(4,2)
// text.substr(4,3)
// text.substr(4,4)

View File

@ -1,21 +0,0 @@
// var str = hello world
// str.substr(0, -1)
hello worl
// str.substr(0, -4)
hello w
// str.substr(8, -4)
// str.substr(3, -3)
// str.substr(3, -4)
lo worl
// str.substr(3, -5)
lo wor
// str.substr(4, -4)
// str.substr(4, -5)
o worl
// str.substr(null, -1)
hello worl
// str.substr(undefined, -1)
hello worl