Skip to content

Commit 4e8d634

Browse files
authored
Force value conversion in case of TypedArray filter method (#4794)
During the execution of the TypedArray filter method it is possible to have a different sized output TypedArray than the input one. When copying the data to the output array the values must be correctly converted to the output TypedArray's value range. Fixes: #4793 JerryScript-DCO-1.0-Signed-off-by: Peter Gal [email protected]
1 parent dae234f commit 4e8d634

File tree

2 files changed

+69
-16
lines changed

2 files changed

+69
-16
lines changed

jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,7 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this objec
412412
return ecma_op_create_typedarray_with_type_and_length (info_p->id, 0);
413413
}
414414

415-
JMEM_DEFINE_LOCAL_ARRAY (pass_value_list_p, info_p->length * info_p->element_size, lit_utf8_byte_t);
416-
417-
lit_utf8_byte_t *pass_value_p = pass_value_list_p;
415+
ecma_collection_t *collected_p = ecma_new_collection ();
418416
uint32_t byte_pos = 0;
419417

420418
for (uint32_t index = 0; index < info_p->length; index++)
@@ -429,50 +427,63 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this objec
429427
ecma_value_t call_value = ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3);
430428

431429
ecma_fast_free_value (current_index);
432-
ecma_fast_free_value (get_value);
433430

434431
if (ECMA_IS_VALUE_ERROR (call_value))
435432
{
433+
ecma_fast_free_value (get_value);
436434
goto cleanup;
437435
}
438436

439437
if (ecma_arraybuffer_is_detached (info_p->array_buffer_p))
440438
{
441439
ecma_free_value (call_value);
440+
ecma_fast_free_value (get_value);
442441
ecma_raise_type_error (ECMA_ERR_MSG (ecma_error_arraybuffer_is_detached));
443442
goto cleanup;
444443
}
445444

446445
if (ecma_op_to_boolean (call_value))
447446
{
448-
memcpy (pass_value_p, info_p->buffer_p + byte_pos, info_p->element_size);
449-
pass_value_p += info_p->element_size;
447+
ecma_collection_push_back (collected_p, get_value);
448+
}
449+
else
450+
{
451+
ecma_fast_free_value (get_value);
450452
}
451453

452454
byte_pos += info_p->element_size;
453-
454-
ecma_free_value (call_value);
455+
ecma_fast_free_value (call_value);
455456
}
456457

457-
uint32_t pass_num = (uint32_t) ((pass_value_p - pass_value_list_p) >> info_p->shift);
458-
459-
ecma_value_t collected = ecma_make_number_value (pass_num);
458+
ecma_value_t collected = ecma_make_number_value (collected_p->item_count);
460459
ret_value = ecma_typedarray_species_create (this_arg, &collected, 1);
461460
ecma_free_value (collected);
462461

463462
if (!ECMA_IS_VALUE_ERROR (ret_value))
464463
{
465464
ecma_object_t *obj_p = ecma_get_object_from_value (ret_value);
465+
ecma_typedarray_info_t target_info = ecma_typedarray_get_info (obj_p);
466466

467-
JERRY_ASSERT (ecma_typedarray_get_offset (obj_p) == 0);
467+
JERRY_ASSERT (target_info.offset == 0);
468468

469-
memcpy (ecma_typedarray_get_buffer (obj_p),
470-
pass_value_list_p,
471-
(size_t) (pass_value_p - pass_value_list_p));
469+
ecma_typedarray_setter_fn_t target_typedarray_setter_cb = ecma_get_typedarray_setter_fn (target_info.id);
470+
uint32_t target_byte_index = 0;
471+
for (uint32_t idx = 0; idx < collected_p->item_count; idx++)
472+
{
473+
ecma_value_t set_element = target_typedarray_setter_cb (target_info.buffer_p + target_byte_index,
474+
collected_p->buffer_p[idx]);
475+
476+
if (ECMA_IS_VALUE_ERROR (set_element))
477+
{
478+
goto cleanup;
479+
}
480+
481+
target_byte_index += target_info.element_size;
482+
}
472483
}
473484

474485
cleanup:
475-
JMEM_FINALIZE_LOCAL_ARRAY (pass_value_list_p);
486+
ecma_collection_free (collected_p);
476487

477488
return ret_value;
478489
} /* ecma_builtin_typedarray_prototype_filter */
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Make sure that TypedArray filter correctly copies the data (avoid overflow).
16+
// Test creates a smaller region for "output" TypedArray.
17+
// Last number is intentionally a "big" float.
18+
var big_array = new Float64Array([0.523565555, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 333333232134.1]);
19+
big_array.constructor = Float32Array;
20+
21+
var result_float32_array = big_array.filter(x => x % 2 == 0);
22+
assert(result_float32_array instanceof Float32Array);
23+
assert(result_float32_array.length === 5);
24+
25+
// Create an even smaller result TypedArray.
26+
big_array.constructor = Uint8Array;
27+
var result_uint8_array = big_array.filter(x => x % 3 == 0);
28+
assert(result_uint8_array instanceof Uint8Array);
29+
assert(result_uint8_array.length === 3);
30+
31+
// Trigger a filter error when at the last element
32+
try {
33+
big_array.filter(function(x, idx) {
34+
if (idx > 10) {
35+
throw new Error("Error test magic");
36+
}
37+
return x % 4 == 0;
38+
});
39+
} catch (ex) {
40+
assert(ex instanceof Error);
41+
assert(ex.message === "Error test magic");
42+
}

0 commit comments

Comments
 (0)