From: Dmitry Volyntsev Date: Fri, 14 Jan 2022 14:40:27 +0000 (+0000) Subject: Fixed Array.prototype.reverse() when array is changed while iterating. X-Git-Tag: 0.7.2~9 X-Git-Url: http://www.kaiwu.me/postgresql/commit/static/gitweb.js?a=commitdiff_plain;h=2901281ee5023567534a1c947123eea3650dbabe;p=njs.git 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. --- diff --git a/src/njs_array.c b/src/njs_array.c index 112f9152..61e0d29e 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -1367,7 +1367,6 @@ njs_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, 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, njs_value_t *args, njs_uint_t nargs, 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 --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 9f59d700..3cf81b58 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -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") },