From 5196046860565591474540089784e9d8b726f3f6 Mon Sep 17 00:00:00 2001 From: hvwyl <594352301@qq.com> Date: Thu, 17 Jul 2025 20:48:13 +0800 Subject: [PATCH 1/3] Fix "Unhandled exception occurs when a private variable increments" --- jerry-core/parser/js/js-parser-expr.c | 39 ++++++----- jerry-core/vm/vm.c | 84 ++++++++++++++++++----- tests/jerry/private_fields.js | 20 ++++++ tests/jerry/regression-test-issue-5238.js | 20 ++++++ 4 files changed, 128 insertions(+), 35 deletions(-) create mode 100644 tests/jerry/regression-test-issue-5238.js diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index ef9170dce4..1c10ccec78 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -289,29 +289,36 @@ parser_emit_unary_lvalue_opcode (parser_context_t *context_p, /**< context */ { context_p->last_cbc_opcode = PARSER_PUSH_PROP_LITERAL_TO_PUSH_LITERAL (context_p->last_cbc_opcode); } - else + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL)) { - /* Invalid LeftHandSide expression. */ if (opcode == CBC_DELETE_PUSH_RESULT) { - if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL)) - { - parser_raise_error (context_p, PARSER_ERR_DELETE_PRIVATE_FIELD); - } - - if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL) - || context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP)) - { - parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); - parser_emit_cbc (context_p, CBC_POP); - return; - } - + parser_raise_error (context_p, PARSER_ERR_DELETE_PRIVATE_FIELD); + goto Invalid_LeftHandSide; + } + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL_REFERENCE); + /* Manually adjusting stack usage. */ + JERRY_ASSERT (context_p->stack_depth > 0); + context_p->stack_depth--; + } + else if (opcode == CBC_DELETE_PUSH_RESULT) + { +Invalid_LeftHandSide: + /* Invalid LeftHandSide expression. */ + if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL) + || context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR); parser_emit_cbc (context_p, CBC_POP); - parser_emit_cbc (context_p, CBC_PUSH_TRUE); return; } + parser_emit_cbc (context_p, CBC_POP); + parser_emit_cbc (context_p, CBC_PUSH_TRUE); + return; + } + else + { parser_check_invalid_new_target (context_p, opcode); if (opcode == CBC_PRE_INCR || opcode == CBC_PRE_DECR) { diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index b6e1e88fb8..4911f27e97 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2956,27 +2956,44 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_PROP_POST_INCR: case VM_OC_PROP_POST_DECR: { - result = vm_op_get_value (left_value, right_value); - - if (opcode < CBC_PRE_INCR) + if (JERRY_UNLIKELY (byte_code_start_p - 3 >= frame_ctx_p->byte_code_p + && byte_code_start_p[-3] == CBC_EXT_OPCODE + && byte_code_start_p[-2] == CBC_EXT_PUSH_PRIVATE_PROP_LITERAL_REFERENCE)) { - left_value = ECMA_VALUE_UNDEFINED; - right_value = ECMA_VALUE_UNDEFINED; + if (opcode < CBC_PRE_INCR) + { + break; + } + result = right_value; + stack_top_p += 1; + left_value = right_value; + /* Use right_value as the marker for private field */ + right_value = ECMA_VALUE_EMPTY; } - - if (ECMA_IS_VALUE_ERROR (result)) + else { - goto error; - } + result = vm_op_get_value (left_value, right_value); - if (opcode < CBC_PRE_INCR) - { - break; - } + if (opcode < CBC_PRE_INCR) + { + left_value = ECMA_VALUE_UNDEFINED; + right_value = ECMA_VALUE_UNDEFINED; + } - stack_top_p += 2; - left_value = result; - right_value = ECMA_VALUE_UNDEFINED; + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + if (opcode < CBC_PRE_INCR) + { + break; + } + + stack_top_p += 2; + left_value = result; + right_value = ECMA_VALUE_UNDEFINED; + } /* FALLTHRU */ } case VM_OC_PRE_INCR: @@ -3018,7 +3035,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } result = (ecma_value_t) (int_value + int_increase); - break; + goto unary_arithmetic_operation_break; } result_number = (ecma_number_t) ecma_get_integer_from_value (result); } @@ -3068,7 +3085,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { goto error; } - break; + goto unary_arithmetic_operation_break; } #endif /* JERRY_BUILTIN_BIGINT */ @@ -3089,7 +3106,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ POST_INCREASE_DECREASE_PUT_RESULT (result); result = ecma_make_number_value (result_number + increase); - break; + goto unary_arithmetic_operation_break; } if (ecma_is_value_integer_number (result)) @@ -3100,6 +3117,35 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { result = ecma_update_float_number (result, result_number + increase); } +unary_arithmetic_operation_break: + if (JERRY_UNLIKELY (right_value == ECMA_VALUE_EMPTY)) + { + right_value = ECMA_VALUE_UNDEFINED; + + if (opcode_data & VM_OC_PUT_REFERENCE) + { + ecma_value_t property = *(--stack_top_p); + ecma_value_t base = *(--stack_top_p); + ecma_value_t set_value_result = opfunc_private_set (base, property, result); + ecma_free_value (base); + ecma_free_value (property); + + if (ECMA_IS_VALUE_ERROR (set_value_result)) + { + ecma_free_value (result); + result = set_value_result; + goto error; + } + + if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK))) + { + ecma_fast_free_value (result); + goto free_both_values; + } + + opcode_data &= (uint32_t) ~VM_OC_PUT_REFERENCE; + } + } break; } case VM_OC_ASSIGN: diff --git a/tests/jerry/private_fields.js b/tests/jerry/private_fields.js index e477639d48..f00c60fef7 100644 --- a/tests/jerry/private_fields.js +++ b/tests/jerry/private_fields.js @@ -350,3 +350,23 @@ class Q extends Array { var var18 = new Q(); assert(var18.b() == 1); + +class R { + #a = 0; + test() { + ++this.#a; + assert(this.#a == 1); + assert(++this.#a == 2); + --this.#a; + assert(this.#a == 1); + assert(--this.#a == 0); + this.#a++; + assert(this.#a == 1); + assert(this.#a++ == 1); + this.#a--; + assert(this.#a == 1); + assert(this.#a-- == 1); + } +} +var var19 = new R(); +var19.test(); diff --git a/tests/jerry/regression-test-issue-5238.js b/tests/jerry/regression-test-issue-5238.js new file mode 100644 index 0000000000..b324467a78 --- /dev/null +++ b/tests/jerry/regression-test-issue-5238.js @@ -0,0 +1,20 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +class A { + #a = 0; + incr() { + this.#a++; + } +} From 8255d98562e2a9c3104a58d1b079b91681cd4883 Mon Sep 17 00:00:00 2001 From: hvwyl <594352301@qq.com> Date: Thu, 17 Jul 2025 21:06:36 +0800 Subject: [PATCH 2/3] Resolve char array truncation error from NUL terminator --- .../ecma/builtin-objects/ecma-builtin-helpers-date.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c index 280a94c4b8..96de26eaa2 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c @@ -36,14 +36,15 @@ /** * Day names */ -const char day_names_p[7][3] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +const char day_names_p[7][3] = { { 'S', 'u', 'n' }, { 'M', 'o', 'n' }, { 'T', 'u', 'e' }, { 'W', 'e', 'd' }, + { 'T', 'h', 'u' }, { 'F', 'r', 'i' }, { 'S', 'a', 't' } }; /** * Month names */ -const char month_names_p[12][3] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; +const char month_names_p[12][3] = { { 'J', 'a', 'n' }, { 'F', 'e', 'b' }, { 'M', 'a', 'r' }, { 'A', 'p', 'r' }, + { 'M', 'a', 'y' }, { 'J', 'u', 'n' }, { 'J', 'u', 'l' }, { 'A', 'u', 'g' }, + { 'S', 'e', 'p' }, { 'O', 'c', 't' }, { 'N', 'o', 'v' }, { 'D', 'e', 'c' } }; /** * Calculate the elapsed days since Unix Epoch From 80c6af2fd88f145b10ce655b421acbd90549ecbb Mon Sep 17 00:00:00 2001 From: hvwyl <594352301@qq.com> Date: Thu, 17 Jul 2025 21:36:56 +0800 Subject: [PATCH 3/3] Resolve floating-point comparison warning with Clang --- tests/unit-math/test-math.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit-math/test-math.c b/tests/unit-math/test-math.c index aa25a85671..679535a856 100644 --- a/tests/unit-math/test-math.c +++ b/tests/unit-math/test-math.c @@ -93,7 +93,18 @@ int main (void) { #define INF INFINITY + +#if defined(__clang__) +#pragma clang diagnostic push +/* Suppress Clang's -Wliteral-range warning */ +#pragma clang diagnostic ignored "-Wliteral-range" +#endif /* defined(__clang__) */ + #include "test-math.inc.h" +#if defined(__clang__) +#pragma clang diagnostic pop +#endif /* defined(__clang__) */ + return passed ? 0 : 1; } /* main */