From: Valentin Bartenev Date: Wed, 8 May 2019 16:09:10 +0000 (+0300) Subject: Fixed arrays expansion. X-Git-Tag: 0.3.2~13 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=b0f23dbc4d4713f65470272768ef79b7cb47db78;p=njs.git Fixed arrays expansion. There were two problems with njs_array_expand(): 1. It checked that the requred size with the appended elements wasn't bigger then the array size and then did nothing. If there were elements removed from the beggining (by shift() operation), then "size <= array->size" can be true even if there wasn't enought free space after the array. 2. After allocating more space to prepend elements, it set array->size without counting those elements. Probably, the original idea was to decrement array->size while removing elements from the beginning, but it wasn't done right. Even if so, the new version of the function looks cleaner. This closes #152 and closes #153 issues on Github. --- diff --git a/njs/njs_array.c b/njs/njs_array.c index 75ab47bd..514035ec 100644 --- a/njs/njs_array.c +++ b/njs/njs_array.c @@ -214,15 +214,19 @@ njs_ret_t njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, uint32_t append) { + uint32_t free_before, free_after; uint64_t size; njs_value_t *start, *old; - size = (uint64_t) append + array->length; + free_before = array->start - array->data; + free_after = array->size - array->length - free_before; - if (nxt_fast_path(size <= array->size && prepend == 0)) { + if (nxt_fast_path(free_before >= prepend && free_after >= append)) { return NXT_OK; } + size = (uint64_t) prepend + array->length + append; + if (size < 16) { size *= 2; @@ -230,12 +234,12 @@ njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, size += size / 2; } - if (nxt_slow_path((prepend + size) > NJS_ARRAY_MAX_LENGTH)) { + if (nxt_slow_path(size > NJS_ARRAY_MAX_LENGTH)) { goto memory_error; } start = nxt_mp_align(vm->mem_pool, sizeof(njs_value_t), - (prepend + size) * sizeof(njs_value_t)); + size * sizeof(njs_value_t)); if (nxt_slow_path(start == NULL)) { goto memory_error; } @@ -728,11 +732,9 @@ njs_array_prototype_unshift(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, n = nargs - 1; if (n != 0) { - if ((intptr_t) n > (array->start - array->data)) { - ret = njs_array_expand(vm, array, n, 0); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } + ret = njs_array_expand(vm, array, n, 0); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; } array->length += n; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index e4167cf1..91822550 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -3730,6 +3730,9 @@ static njs_unit_test_t njs_test[] = "len +' '+ a +' '+ a.shift()"), nxt_string("5 3,4,5,1,2 3") }, + { nxt_string("var a=[0], n = 64; while(--n) {a.push(n); a.shift()}; a"), + nxt_string("1") }, + { nxt_string("var a = []; a.splice()"), nxt_string("") },