[njs] Fixed Array.prototype.reverse() when array is changed while iterating.
Dmitry Volyntsev
xeioex at nginx.com
Fri Jan 14 14:57:29 UTC 2022
details: https://hg.nginx.org/njs/rev/7467158d9f37
branches:
changeset: 1807:7467158d9f37
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Jan 14 14:40:27 2022 +0000
description:
Fixed Array.prototype.reverse() when array is changed while iterating.
Previously, the flat array may be converted to a slow one as a
side-effect of a custom getter invocation for a proto array object.
The function erroneously assumed that the this array remains flat
while iterating.
The fix is to eliminate the micro-optimization which uses direct
pointers.
The problem is similar to the previous commits.
diffstat:
src/njs_array.c | 47 -----------------------------------------------
src/test/njs_unit_test.c | 12 ++++++++++++
2 files changed, 12 insertions(+), 47 deletions(-)
diffs (86 lines):
diff -r dfbde7620ced -r 7467158d9f37 src/njs_array.c
--- a/src/njs_array.c Thu Jan 13 18:30:31 2022 +0000
+++ b/src/njs_array.c Fri Jan 14 14:40:27 2022 +0000
@@ -1367,7 +1367,6 @@ njs_array_prototype_reverse(njs_vm_t *vm
int64_t length, l, h;
njs_int_t ret, lret, hret;
njs_value_t value, lvalue, hvalue, *this;
- njs_array_t *array;
this = njs_argument(args, 0);
@@ -1386,52 +1385,6 @@ njs_array_prototype_reverse(njs_vm_t *vm
return NJS_OK;
}
- if (njs_is_fast_array(this)) {
- array = njs_array(this);
-
- for (l = 0, h = length - 1; l < h; l++, h--) {
- if (njs_fast_path(njs_is_valid(&array->start[l]))) {
- lvalue = array->start[l];
- lret = NJS_OK;
-
- } else {
- lret = njs_value_property_i64(vm, this, l, &lvalue);
- if (njs_slow_path(lret == NJS_ERROR)) {
- return NJS_ERROR;
- }
- }
-
- if (njs_fast_path(njs_is_valid(&array->start[h]))) {
- hvalue = array->start[h];
- hret = NJS_OK;
-
- } else {
- hret = njs_value_property_i64(vm, this, h, &hvalue);
- if (njs_slow_path(hret == NJS_ERROR)) {
- return NJS_ERROR;
- }
- }
-
- if (lret == NJS_OK) {
- array->start[h] = lvalue;
-
- if (hret == NJS_OK) {
- array->start[l] = hvalue;
-
- } else {
- array->start[l] = njs_value_invalid;
- }
-
- } else if (hret == NJS_OK) {
- array->start[l] = hvalue;
- array->start[h] = njs_value_invalid;
- }
- }
-
- njs_set_array(&vm->retval, array);
- return NJS_OK;
- }
-
for (l = 0, h = length - 1; l < h; l++, h--) {
lret = njs_value_property_i64(vm, this, l, &lvalue);
if (njs_slow_path(lret == NJS_ERROR)) {
diff -r dfbde7620ced -r 7467158d9f37 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Thu Jan 13 18:30:31 2022 +0000
+++ b/src/test/njs_unit_test.c Fri Jan 14 14:40:27 2022 +0000
@@ -4883,6 +4883,18 @@ static njs_unit_test_t njs_test[] =
{ njs_str("[,,,3,2,1].reverse()"),
njs_str("1,2,3,,,") },
+ { njs_str("var a = [,,2,1];"
+ "Object.defineProperty(a.__proto__, 0, {"
+ " get: () => {"
+ " a.length = 10**6;"
+ " return 4;"
+ " },"
+ " set: (setval) => { Object.defineProperty(a, 0, { value: setval }); },"
+ "});"
+ "a.reverse();"
+ "a.slice(0, 4)"),
+ njs_str("1,2,,4") },
+
{ njs_str("var o = {1:true, 2:'', length:-2}; Array.prototype.reverse.call(o) === o"),
njs_str("true") },
More information about the nginx-devel
mailing list