Skip to content

Commit 5e48363

Browse files
authored
Fix prototype chain traversing (#4458)
After the introduction of the Proxy builtin object there was a possibility to traverse the prototype chain with an invalid object. The prototype was freed before it's data/properties were queried resulting in accessing invalid information. By forcing the allocator to always do a gc (`--mem-stres-test=on` build option) it was possible to trigger the issue without complicated tests. New internal method: * `ecma_op_object_get_prototype_of` which always returns the prototype of an object and the return value must be freed (if it is valid). Updated prototype chain traversing in: * `jerry_object_get_property_names` * `ecma_builtin_object_prototype_lookup_getter_setter` * `ecma_op_function_has_instance` * `ecma_op_function_get_super_constructor` * `ecma_op_object_is_prototype_of` * `ecma_op_object_enumerate` Removed method `ecma_proxy_object_prototype_to_cp` JerryScript-DCO-1.0-Signed-off-by: Peter Gal [email protected]
1 parent abedab5 commit 5e48363

File tree

8 files changed

+189
-169
lines changed

8 files changed

+189
-169
lines changed

jerry-core/api/jerry.c

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3884,6 +3884,8 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */
38843884
ecma_object_t *obj_iter_p = obj_p;
38853885
ecma_collection_t *result_p = ecma_new_collection ();
38863886

3887+
ecma_ref_object (obj_iter_p);
3888+
38873889
while (true)
38883890
{
38893891
/* Step 1. Get Object.[[OwnKeys]] */
@@ -3892,6 +3894,7 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */
38923894
#if ENABLED (JERRY_BUILTIN_PROXY)
38933895
if (prop_names_p == NULL)
38943896
{
3897+
ecma_deref_object (obj_iter_p);
38953898
return jerry_throw (ECMA_VALUE_ERROR);
38963899
}
38973900
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
@@ -3942,6 +3945,7 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */
39423945
{
39433946
ecma_collection_free (prop_names_p);
39443947
ecma_collection_free (result_p);
3948+
ecma_deref_object (obj_iter_p);
39453949
return jerry_throw (ECMA_VALUE_ERROR);
39463950
}
39473951
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
@@ -4008,38 +4012,32 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */
40084012
ecma_collection_free (prop_names_p);
40094013

40104014
/* Step 4: Traverse prototype chain */
4011-
jmem_cpointer_t parent_cp = JMEM_CP_NULL;
40124015

4013-
if (filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN)
4016+
if ((filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) != JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN)
40144017
{
4015-
#if ENABLED (JERRY_BUILTIN_PROXY)
4016-
if (ECMA_OBJECT_IS_PROXY (obj_iter_p))
4017-
{
4018-
ecma_value_t parent = ecma_proxy_object_get_prototype_of (obj_iter_p);
4018+
break;
4019+
}
40194020

4020-
if (ECMA_IS_VALUE_ERROR (parent))
4021-
{
4022-
ecma_collection_free (result_p);
4023-
return jerry_throw (ECMA_VALUE_ERROR);
4024-
}
4021+
ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_iter_p);
40254022

4026-
parent_cp = ecma_proxy_object_prototype_to_cp (parent);
4027-
}
4028-
else
4029-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
4030-
{
4031-
parent_cp = ecma_op_ordinary_object_get_prototype_of (obj_iter_p);
4032-
}
4023+
if (proto_p == NULL)
4024+
{
4025+
break;
40334026
}
40344027

4035-
if (parent_cp == JMEM_CP_NULL)
4028+
ecma_deref_object (obj_iter_p);
4029+
4030+
if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR))
40364031
{
4037-
break;
4032+
ecma_collection_free (result_p);
4033+
return jerry_throw (ECMA_VALUE_ERROR);
40384034
}
40394035

4040-
obj_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, parent_cp);
4036+
obj_iter_p = proto_p;
40414037
}
40424038

4039+
ecma_deref_object (obj_iter_p);
4040+
40434041
return ecma_op_new_array_object_from_collection (result_p, false);
40444042
} /* jerry_object_get_property_names */
40454043

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

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,10 @@ ecma_builtin_object_prototype_lookup_getter_setter (ecma_value_t this_arg, /**<
324324
return ECMA_VALUE_ERROR;
325325
}
326326

327-
jmem_cpointer_t obj_cp;
328-
ECMA_SET_NON_NULL_POINTER (obj_cp, obj_p);
329-
330327
ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
331328

329+
ecma_ref_object (obj_p);
330+
332331
/* 3. */
333332
while (true)
334333
{
@@ -339,6 +338,7 @@ ecma_builtin_object_prototype_lookup_getter_setter (ecma_value_t this_arg, /**<
339338
if (ECMA_IS_VALUE_ERROR (get_desc))
340339
{
341340
ret_value = get_desc;
341+
ecma_deref_object (obj_p);
342342
break;
343343
}
344344

@@ -360,35 +360,26 @@ ecma_builtin_object_prototype_lookup_getter_setter (ecma_value_t this_arg, /**<
360360
}
361361

362362
ecma_free_property_descriptor (&desc);
363+
ecma_deref_object (obj_p);
363364
break;
364365
}
365366

366367
/* 3.c */
367-
#if ENABLED (JERRY_BUILTIN_PROXY)
368-
if (ECMA_OBJECT_IS_PROXY (obj_p))
369-
{
370-
ecma_value_t parent = ecma_proxy_object_get_prototype_of (obj_p);
371-
372-
if (ECMA_IS_VALUE_ERROR (parent))
373-
{
374-
ret_value = parent;
375-
break;
376-
}
368+
ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_p);
369+
ecma_deref_object (obj_p);
377370

378-
obj_cp = ecma_proxy_object_prototype_to_cp (parent);
379-
}
380-
else
381-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
371+
if (proto_p == NULL)
382372
{
383-
obj_cp = ecma_op_ordinary_object_get_prototype_of (obj_p);
373+
break;
384374
}
385-
386-
if (obj_cp == JMEM_CP_NULL)
375+
else if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR))
387376
{
377+
ret_value = ECMA_VALUE_ERROR;
388378
break;
389379
}
390380

391-
obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_cp);
381+
/* Advance up on prototype chain. */
382+
obj_p = proto_p;
392383
}
393384

394385
ecma_free_value (to_obj);

jerry-core/ecma/operations/ecma-function-object.c

Lines changed: 18 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -900,44 +900,34 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object *
900900
ecma_value_t result = ECMA_VALUE_FALSE;
901901
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
902902

903+
ecma_ref_object (v_obj_p);
904+
903905
while (true)
904906
{
905-
jmem_cpointer_t v_obj_cp;
906-
#if ENABLED (JERRY_BUILTIN_PROXY)
907-
if (ECMA_OBJECT_IS_PROXY (v_obj_p))
908-
{
909-
ecma_value_t parent = ecma_proxy_object_get_prototype_of (v_obj_p);
910-
911-
if (ECMA_IS_VALUE_ERROR (parent))
912-
{
913-
break;
914-
}
907+
ecma_object_t *current_proto_p = ecma_op_object_get_prototype_of (v_obj_p);
908+
ecma_deref_object (v_obj_p);
915909

916-
v_obj_cp = ecma_proxy_object_prototype_to_cp (parent);
917-
}
918-
else
919-
{
920-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
921-
v_obj_cp = ecma_op_ordinary_object_get_prototype_of (v_obj_p);
922-
#if ENABLED (JERRY_BUILTIN_PROXY)
923-
}
924-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
925-
926-
if (v_obj_cp == JMEM_CP_NULL)
910+
if (current_proto_p == NULL)
927911
{
928912
#if ENABLED (JERRY_BUILTIN_PROXY)
929913
result = ECMA_VALUE_FALSE;
930914
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
931915
break;
932916
}
917+
else if (current_proto_p == ECMA_OBJECT_POINTER_ERROR)
918+
{
919+
break;
920+
}
933921

934-
v_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, v_obj_cp);
935-
936-
if (v_obj_p == prototype_obj_p)
922+
if (current_proto_p == prototype_obj_p)
937923
{
924+
ecma_deref_object (current_proto_p);
938925
result = ECMA_VALUE_TRUE;
939926
break;
940927
}
928+
929+
/* Advance up on prototype chain. */
930+
v_obj_p = current_proto_p;
941931
}
942932

943933
ecma_deref_object (prototype_obj_p);
@@ -957,38 +947,13 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object *
957947
ecma_value_t
958948
ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p) /**< function object */
959949
{
960-
ecma_object_t *super_ctor_p;
950+
ecma_object_t *super_ctor_p = ecma_op_object_get_prototype_of (func_obj_p);
961951

962-
#if ENABLED (JERRY_BUILTIN_PROXY)
963-
if (ECMA_OBJECT_IS_PROXY (func_obj_p))
952+
if (JERRY_UNLIKELY (super_ctor_p == ECMA_OBJECT_POINTER_ERROR))
964953
{
965-
ecma_value_t super_ctor = ecma_proxy_object_get_prototype_of (func_obj_p);
966-
967-
if (ECMA_IS_VALUE_ERROR (super_ctor))
968-
{
969-
return super_ctor;
970-
}
971-
972-
super_ctor_p = ecma_is_value_null (super_ctor) ? NULL : ecma_get_object_from_value (super_ctor);
973-
}
974-
else
975-
{
976-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
977-
jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (func_obj_p);
978-
if (proto_cp == JMEM_CP_NULL)
979-
{
980-
super_ctor_p = NULL;
981-
}
982-
else
983-
{
984-
super_ctor_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
985-
ecma_ref_object (super_ctor_p);
986-
}
987-
#if ENABLED (JERRY_BUILTIN_PROXY)
954+
return ECMA_VALUE_ERROR;
988955
}
989-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
990-
991-
if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p))
956+
else if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p))
992957
{
993958
if (super_ctor_p != NULL)
994959
{

0 commit comments

Comments
 (0)