Skip to content

Commit 5196046

Browse files
committed
Fix "Unhandled exception occurs when a private variable increments"
1 parent 355ab24 commit 5196046

File tree

4 files changed

+128
-35
lines changed

4 files changed

+128
-35
lines changed

jerry-core/parser/js/js-parser-expr.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -289,29 +289,36 @@ parser_emit_unary_lvalue_opcode (parser_context_t *context_p, /**< context */
289289
{
290290
context_p->last_cbc_opcode = PARSER_PUSH_PROP_LITERAL_TO_PUSH_LITERAL (context_p->last_cbc_opcode);
291291
}
292-
else
292+
else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL))
293293
{
294-
/* Invalid LeftHandSide expression. */
295294
if (opcode == CBC_DELETE_PUSH_RESULT)
296295
{
297-
if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL))
298-
{
299-
parser_raise_error (context_p, PARSER_ERR_DELETE_PRIVATE_FIELD);
300-
}
301-
302-
if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL)
303-
|| context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP))
304-
{
305-
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
306-
parser_emit_cbc (context_p, CBC_POP);
307-
return;
308-
}
309-
296+
parser_raise_error (context_p, PARSER_ERR_DELETE_PRIVATE_FIELD);
297+
goto Invalid_LeftHandSide;
298+
}
299+
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL_REFERENCE);
300+
/* Manually adjusting stack usage. */
301+
JERRY_ASSERT (context_p->stack_depth > 0);
302+
context_p->stack_depth--;
303+
}
304+
else if (opcode == CBC_DELETE_PUSH_RESULT)
305+
{
306+
Invalid_LeftHandSide:
307+
/* Invalid LeftHandSide expression. */
308+
if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL)
309+
|| context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP))
310+
{
311+
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
310312
parser_emit_cbc (context_p, CBC_POP);
311-
parser_emit_cbc (context_p, CBC_PUSH_TRUE);
312313
return;
313314
}
314315

316+
parser_emit_cbc (context_p, CBC_POP);
317+
parser_emit_cbc (context_p, CBC_PUSH_TRUE);
318+
return;
319+
}
320+
else
321+
{
315322
parser_check_invalid_new_target (context_p, opcode);
316323
if (opcode == CBC_PRE_INCR || opcode == CBC_PRE_DECR)
317324
{

jerry-core/vm/vm.c

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2956,27 +2956,44 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
29562956
case VM_OC_PROP_POST_INCR:
29572957
case VM_OC_PROP_POST_DECR:
29582958
{
2959-
result = vm_op_get_value (left_value, right_value);
2960-
2961-
if (opcode < CBC_PRE_INCR)
2959+
if (JERRY_UNLIKELY (byte_code_start_p - 3 >= frame_ctx_p->byte_code_p
2960+
&& byte_code_start_p[-3] == CBC_EXT_OPCODE
2961+
&& byte_code_start_p[-2] == CBC_EXT_PUSH_PRIVATE_PROP_LITERAL_REFERENCE))
29622962
{
2963-
left_value = ECMA_VALUE_UNDEFINED;
2964-
right_value = ECMA_VALUE_UNDEFINED;
2963+
if (opcode < CBC_PRE_INCR)
2964+
{
2965+
break;
2966+
}
2967+
result = right_value;
2968+
stack_top_p += 1;
2969+
left_value = right_value;
2970+
/* Use right_value as the marker for private field */
2971+
right_value = ECMA_VALUE_EMPTY;
29652972
}
2966-
2967-
if (ECMA_IS_VALUE_ERROR (result))
2973+
else
29682974
{
2969-
goto error;
2970-
}
2975+
result = vm_op_get_value (left_value, right_value);
29712976

2972-
if (opcode < CBC_PRE_INCR)
2973-
{
2974-
break;
2975-
}
2977+
if (opcode < CBC_PRE_INCR)
2978+
{
2979+
left_value = ECMA_VALUE_UNDEFINED;
2980+
right_value = ECMA_VALUE_UNDEFINED;
2981+
}
29762982

2977-
stack_top_p += 2;
2978-
left_value = result;
2979-
right_value = ECMA_VALUE_UNDEFINED;
2983+
if (ECMA_IS_VALUE_ERROR (result))
2984+
{
2985+
goto error;
2986+
}
2987+
2988+
if (opcode < CBC_PRE_INCR)
2989+
{
2990+
break;
2991+
}
2992+
2993+
stack_top_p += 2;
2994+
left_value = result;
2995+
right_value = ECMA_VALUE_UNDEFINED;
2996+
}
29802997
/* FALLTHRU */
29812998
}
29822999
case VM_OC_PRE_INCR:
@@ -3018,7 +3035,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
30183035
}
30193036

30203037
result = (ecma_value_t) (int_value + int_increase);
3021-
break;
3038+
goto unary_arithmetic_operation_break;
30223039
}
30233040
result_number = (ecma_number_t) ecma_get_integer_from_value (result);
30243041
}
@@ -3068,7 +3085,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
30683085
{
30693086
goto error;
30703087
}
3071-
break;
3088+
goto unary_arithmetic_operation_break;
30723089
}
30733090
#endif /* JERRY_BUILTIN_BIGINT */
30743091

@@ -3089,7 +3106,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
30893106
POST_INCREASE_DECREASE_PUT_RESULT (result);
30903107

30913108
result = ecma_make_number_value (result_number + increase);
3092-
break;
3109+
goto unary_arithmetic_operation_break;
30933110
}
30943111

30953112
if (ecma_is_value_integer_number (result))
@@ -3100,6 +3117,35 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
31003117
{
31013118
result = ecma_update_float_number (result, result_number + increase);
31023119
}
3120+
unary_arithmetic_operation_break:
3121+
if (JERRY_UNLIKELY (right_value == ECMA_VALUE_EMPTY))
3122+
{
3123+
right_value = ECMA_VALUE_UNDEFINED;
3124+
3125+
if (opcode_data & VM_OC_PUT_REFERENCE)
3126+
{
3127+
ecma_value_t property = *(--stack_top_p);
3128+
ecma_value_t base = *(--stack_top_p);
3129+
ecma_value_t set_value_result = opfunc_private_set (base, property, result);
3130+
ecma_free_value (base);
3131+
ecma_free_value (property);
3132+
3133+
if (ECMA_IS_VALUE_ERROR (set_value_result))
3134+
{
3135+
ecma_free_value (result);
3136+
result = set_value_result;
3137+
goto error;
3138+
}
3139+
3140+
if (!(opcode_data & (VM_OC_PUT_STACK | VM_OC_PUT_BLOCK)))
3141+
{
3142+
ecma_fast_free_value (result);
3143+
goto free_both_values;
3144+
}
3145+
3146+
opcode_data &= (uint32_t) ~VM_OC_PUT_REFERENCE;
3147+
}
3148+
}
31033149
break;
31043150
}
31053151
case VM_OC_ASSIGN:

tests/jerry/private_fields.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,23 @@ class Q extends Array {
350350

351351
var var18 = new Q();
352352
assert(var18.b() == 1);
353+
354+
class R {
355+
#a = 0;
356+
test() {
357+
++this.#a;
358+
assert(this.#a == 1);
359+
assert(++this.#a == 2);
360+
--this.#a;
361+
assert(this.#a == 1);
362+
assert(--this.#a == 0);
363+
this.#a++;
364+
assert(this.#a == 1);
365+
assert(this.#a++ == 1);
366+
this.#a--;
367+
assert(this.#a == 1);
368+
assert(this.#a-- == 1);
369+
}
370+
}
371+
var var19 = new R();
372+
var19.test();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
class A {
16+
#a = 0;
17+
incr() {
18+
this.#a++;
19+
}
20+
}

0 commit comments

Comments
 (0)