From 95a3a126577aae761a93b06b051b23322d9a6e41 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 16:31:10 +0200 Subject: [PATCH 01/33] Change precedence of $ operator $$foo['bar'] is now interpreted as ${$foo}['bar'] rather than ${$foo['bar']}. --- Zend/zend_compile.c | 11 ++--------- Zend/zend_compile.h | 2 +- Zend/zend_language_parser.y | 13 +++---------- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ea75c1503ae88..37649e7bb22f7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6315,17 +6315,10 @@ void zend_do_include_or_eval(int type, znode *result, znode *op1 TSRMLS_DC) /* { } /* }}} */ -void zend_do_indirect_references(znode *result, const znode *num_references, znode *variable TSRMLS_DC) /* {{{ */ +void zend_do_indirect_reference(znode *result, znode *variable TSRMLS_DC) /* {{{ */ { - int i; + fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R TSRMLS_CC); - zend_do_end_variable_parse(variable, BP_VAR_R, 0 TSRMLS_CC); - for (i=1; iu.constant); i++) { - fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R TSRMLS_CC); - *variable = *result; - } - zend_do_begin_variable_parse(TSRMLS_C); - fetch_simple_variable(result, variable, 1 TSRMLS_CC); /* there is a chance someone is accessing $this */ if (CG(active_op_array)->scope && CG(active_op_array)->this_var == -1) { zend_string *key = STR_INIT("this", sizeof("this")-1, 0); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 5b5397844ffdc..9f17b110d1814 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -457,7 +457,7 @@ void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC); void zend_do_assign_ref(znode *result, znode *lvar, znode *rvar TSRMLS_DC); void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC); void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC); -void zend_do_indirect_references(znode *result, const znode *num_references, znode *variable TSRMLS_DC); +void zend_do_indirect_reference(znode *result, znode *variable TSRMLS_DC); void zend_do_fetch_static_variable(znode *varname, znode *static_assignment, int fetch_type TSRMLS_DC); void zend_do_fetch_global_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 43e20cd9ce5ed..886eff03dbc28 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1130,7 +1130,6 @@ method_or_not: variable_without_objects: reference_variable { $$ = $1; } - | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); } ; static_member: @@ -1158,20 +1157,19 @@ base_variable_with_function_calls: base_variable: reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } - | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } ; reference_variable: reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } - | compound_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } + | simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } ; - -compound_variable: +simple_variable: T_VARIABLE { $$ = $1; } | '$' '{' expr '}' { $$ = $3; } + | '$' simple_variable { zend_do_indirect_reference(&$$, &$2 TSRMLS_CC); } ; dim_offset: @@ -1196,11 +1194,6 @@ variable_name: | '{' expr '}' { $$ = $2; } ; -simple_indirect_reference: - '$' { Z_LVAL($$.u.constant) = 1; } - | simple_indirect_reference '$' { Z_LVAL($$.u.constant)++; } -; - assignment_list: assignment_list ',' assignment_list_element | assignment_list_element From e2be2cee97ade5169d4502c862360f67f5544e6e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 21:11:25 +0200 Subject: [PATCH 02/33] Temporarily disable complex variables in new expressions --- Zend/zend_language_parser.y | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 886eff03dbc28..206c290977ad0 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -930,21 +930,7 @@ class_name_reference: dynamic_class_name_reference: - base_variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } - object_property { zend_do_push_object(&$4 TSRMLS_CC); } dynamic_class_name_variable_properties - { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } - | base_variable { $$ = $1; } -; - - -dynamic_class_name_variable_properties: - dynamic_class_name_variable_properties dynamic_class_name_variable_property - | /* empty */ -; - - -dynamic_class_name_variable_property: - T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } + simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } ; exit_expr: From 46e35e3d5dd6447245a4d80ddde21f4e348c98d5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 21:14:18 +0200 Subject: [PATCH 03/33] Get rid of base_variable_with_function_calls --- Zend/zend_language_parser.y | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 206c290977ad0..1fd580ef582d6 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1082,10 +1082,10 @@ rw_variable: ; variable: - base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } + base_variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $1.EA | ($7.EA ? $7.EA : $6.EA); } - | base_variable_with_function_calls { $$ = $1; } + | base_variable { $$ = $1; } ; variable_properties: @@ -1134,16 +1134,11 @@ array_function_dereference: '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } ; -base_variable_with_function_calls: - base_variable { $$ = $1; } - | array_function_dereference { $$ = $1; } - | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } -; - - base_variable: reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } + | array_function_dereference { $$ = $1; } + | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; reference_variable: From b8b3b355be4ac5c537dd5fc60c929f9f15c5c636 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 22:03:24 +0200 Subject: [PATCH 04/33] Use recursion for property fetches --- Zend/zend_language_parser.y | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1fd580ef582d6..08c3ffe7ebeab 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1082,18 +1082,15 @@ rw_variable: ; variable: - base_variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } - object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties - { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $1.EA | ($7.EA ? $7.EA : $6.EA); } - | base_variable { $$ = $1; } -; - -variable_properties: - variable_properties variable_property { $$.EA = $2.EA; } - | /* empty */ { $$.EA = 0; } + variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } + object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not + { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $6.EA; } + | reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } + | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } + | array_function_dereference { $$ = $1; } + | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; - variable_property: T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } method_or_not { $$.EA = $4.EA; } ; @@ -1134,13 +1131,6 @@ array_function_dereference: '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } ; -base_variable: - reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } - | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } - | array_function_dereference { $$ = $1; } - | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } -; - reference_variable: reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } From a8c1595012a59d5b4e8a8d0b90650f3075f02869 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 22:33:03 +0200 Subject: [PATCH 05/33] LTR static member access --- Zend/tests/bug27669.phpt | 2 +- Zend/zend_compile.c | 74 ++++++++++--------------------------- Zend/zend_compile.h | 2 +- Zend/zend_language_parser.y | 18 +++++---- 4 files changed, 32 insertions(+), 64 deletions(-) diff --git a/Zend/tests/bug27669.phpt b/Zend/tests/bug27669.phpt index 4d513e91aa24b..43591a938614a 100644 --- a/Zend/tests/bug27669.phpt +++ b/Zend/tests/bug27669.phpt @@ -10,7 +10,7 @@ Bug #27669 (PHP 5 didn't support all possibilities for calling static methods dy } } $y[0] = 'hello'; - A::$y[0](); + A::{$y[0]}(); ?> ===DONE=== --EXPECTF-- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 37649e7bb22f7..b6754d202b1fb 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -703,7 +703,7 @@ void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) /* { } /* }}} */ -void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ +void zend_do_fetch_static_member(znode *result, znode *class_name, znode *member_name TSRMLS_DC) /* {{{ */ { znode class_node; zend_llist *fetch_list_ptr; @@ -718,65 +718,29 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* } else { zend_do_fetch_class(&class_node, class_name TSRMLS_CC); } + + zend_do_begin_variable_parse(TSRMLS_C); fetch_list_ptr = zend_stack_top(&CG(bp_stack)); - if (result->op_type == IS_CV) { - init_op(&opline TSRMLS_CC); + init_op(&opline TSRMLS_CC); - opline.opcode = ZEND_FETCH_W; - opline.result_type = IS_VAR; - opline.result.var = get_temporary_variable(CG(active_op_array)); - opline.op1_type = IS_CONST; - LITERAL_STR(opline.op1, STR_COPY(CG(active_op_array)->vars[EX_VAR_TO_NUM(result->u.op.var)])); + opline.opcode = ZEND_FETCH_W; + opline.result_type = IS_VAR; + opline.result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline.op1, member_name); + if (opline.op1_type == IS_CONST) { GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant); - if (class_node.op_type == IS_CONST) { - opline.op2_type = IS_CONST; - opline.op2.constant = - zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); - } else { - SET_NODE(opline.op2, &class_node); - } - GET_NODE(result,opline.result); - opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; - opline_ptr = &opline; - - zend_llist_add_element(fetch_list_ptr, &opline); + } + if (class_node.op_type == IS_CONST) { + opline.op2_type = IS_CONST; + opline.op2.constant = + zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); } else { - le = fetch_list_ptr->head; - - opline_ptr = (zend_op *)le->data; - if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) { - init_op(&opline TSRMLS_CC); - opline.opcode = ZEND_FETCH_W; - opline.result_type = IS_VAR; - opline.result.var = get_temporary_variable(CG(active_op_array)); - opline.op1_type = IS_CONST; - LITERAL_STR(opline.op1, STR_COPY(CG(active_op_array)->vars[EX_VAR_TO_NUM(opline_ptr->op1.var)])); - GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant); - if (class_node.op_type == IS_CONST) { - opline.op2_type = IS_CONST; - opline.op2.constant = - zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); - } else { - SET_NODE(opline.op2, &class_node); - } - opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; - COPY_NODE(opline_ptr->op1, opline.result); - - zend_llist_prepend_element(fetch_list_ptr, &opline); - } else { - if (opline_ptr->op1_type == IS_CONST) { - GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant); - } - if (class_node.op_type == IS_CONST) { - opline_ptr->op2_type = IS_CONST; - opline_ptr->op2.constant = - zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); - } else { - SET_NODE(opline_ptr->op2, &class_node); - } - opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER; - } + SET_NODE(opline.op2, &class_node); } + GET_NODE(result,opline.result); + opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; + + zend_llist_add_element(fetch_list_ptr, &opline); } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 9f17b110d1814..bb4142884d781 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -464,7 +464,7 @@ void zend_do_fetch_global_variable(znode *varname, const znode *static_assignmen void fetch_array_begin(znode *result, znode *varname, znode *first_dim TSRMLS_DC); void fetch_array_dim(znode *result, znode *parent, znode *dim TSRMLS_DC); void fetch_string_offset(znode *result, znode *parent, znode *offset TSRMLS_DC); -void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC); +void zend_do_fetch_static_member(znode *result, znode *class_name, znode *member_name TSRMLS_DC); void zend_do_print(znode *result, znode *arg TSRMLS_DC); void zend_do_echo(znode *arg TSRMLS_DC); typedef int (*unary_op_type)(zval *, zval * TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 08c3ffe7ebeab..d22d1c266d04d 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -898,13 +898,13 @@ function_call: function_call_parameter_list { zend_do_end_function_call(&$2, &$$, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { fetch_simple_variable_ex(&$$, &$3, 0, ZEND_FETCH_R TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$$ TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { fetch_simple_variable_ex(&$$, &$3, 0, ZEND_FETCH_R TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$$ TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } + | directly_callable_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; @@ -1086,7 +1086,6 @@ variable: object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $6.EA; } | reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } - | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } | array_function_dereference { $$ = $1; } | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; @@ -1116,8 +1115,8 @@ variable_without_objects: ; static_member: - class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 TSRMLS_CC); } - | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 TSRMLS_CC); } + class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } ; @@ -1131,12 +1130,17 @@ array_function_dereference: '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } ; -reference_variable: +directly_callable_variable: reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } | simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } ; +reference_variable: + directly_callable_variable { $$ = $1; } + | static_member { $$ = $1; } +; + simple_variable: T_VARIABLE { $$ = $1; } | '$' '{' expr '}' { $$ = $3; } From 667f8409c58da7043d7b2ebd888376c3349bb6db Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 22:53:30 +0200 Subject: [PATCH 06/33] Recursive definition for object proprety fetches --- Zend/zend_language_parser.y | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index d22d1c266d04d..9b3e2c7d1e66f 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -765,8 +765,8 @@ chaining_instance_call: instance_call: /* empty */ { $$ = $0; } - | { zend_do_push_object(&$0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); } - chaining_instance_call { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); } +/* | { zend_do_push_object(&$0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); } + chaining_instance_call { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); }*/ ; new_expr: @@ -1082,10 +1082,7 @@ rw_variable: ; variable: - variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } - object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not - { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $6.EA; } - | reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } + reference_variable { $$ = $1; } | array_function_dereference { $$ = $1; } | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; @@ -1131,14 +1128,28 @@ array_function_dereference: ; directly_callable_variable: - reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } - | simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } + reference_variable '[' dim_offset ']' + { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } + | reference_variable '{' expr '}' + { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } + | simple_variable + { zend_do_begin_variable_parse(TSRMLS_C); + fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); + $$.EA = ZEND_PARSED_VARIABLE; } + | variable T_OBJECT_OPERATOR object_member + { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); + zend_do_begin_method_call(&$$ TSRMLS_CC); } + function_call_parameter_list + { zend_do_end_function_call(&$4, &$$, 1, 1 TSRMLS_CC); + zend_do_extended_fcall_end(TSRMLS_C); + $$.EA = ZEND_PARSED_METHOD_CALL; } ; reference_variable: directly_callable_variable { $$ = $1; } - | static_member { $$ = $1; } + | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } + | variable T_OBJECT_OPERATOR object_member + { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } ; simple_variable: @@ -1152,6 +1163,10 @@ dim_offset: | expr { $$ = $1; } ; +object_member: + variable_name { $$ = $1; } + | simple_variable { fetch_simple_variable_ex(&$$, &$1, 0, ZEND_FETCH_R TSRMLS_CC); } +; object_property: object_dim_list { $$ = $1; } From e89958a6340201f9c0e00f9fac7d1d00c5e30e84 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 23:30:37 +0200 Subject: [PATCH 07/33] Make function calls directly callable --- Zend/zend_language_parser.y | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 9b3e2c7d1e66f..41c2bc3391e30 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1083,8 +1083,6 @@ rw_variable: variable: reference_variable { $$ = $1; } - | array_function_dereference { $$ = $1; } - | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; variable_property: @@ -1143,6 +1141,9 @@ directly_callable_variable: { zend_do_end_function_call(&$4, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); $$.EA = ZEND_PARSED_METHOD_CALL; } + | function_call + { zend_do_begin_variable_parse(TSRMLS_C); + $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; reference_variable: From 067fca0e89cbb9feb2ac21464f36a6d6cc16eddf Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 23:36:30 +0200 Subject: [PATCH 08/33] Remove reference_variable indirection --- Zend/zend_language_parser.y | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 41c2bc3391e30..97589831e5c6d 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1081,10 +1081,6 @@ rw_variable: zend_check_writable_variable(&$1); } ; -variable: - reference_variable { $$ = $1; } -; - variable_property: T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } method_or_not { $$.EA = $4.EA; } ; @@ -1106,7 +1102,7 @@ method_or_not: ; variable_without_objects: - reference_variable { $$ = $1; } + variable { $$ = $1; } ; static_member: @@ -1116,7 +1112,7 @@ static_member: ; variable_class_name: - reference_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } + variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } ; array_function_dereference: @@ -1126,9 +1122,9 @@ array_function_dereference: ; directly_callable_variable: - reference_variable '[' dim_offset ']' + variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | reference_variable '{' expr '}' + | variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } | simple_variable { zend_do_begin_variable_parse(TSRMLS_C); @@ -1146,7 +1142,7 @@ directly_callable_variable: $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; -reference_variable: +variable: directly_callable_variable { $$ = $1; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } | variable T_OBJECT_OPERATOR object_member From 295d07e373486cd2fdb45d62710abaca1189ba9c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 23:44:30 +0200 Subject: [PATCH 09/33] Reintroduce new expression dereferencing --- Zend/zend_language_parser.y | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 97589831e5c6d..a9293e66153bb 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1105,12 +1105,6 @@ variable_without_objects: variable { $$ = $1; } ; -static_member: - class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } - | variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } - -; - variable_class_name: variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } ; @@ -1121,16 +1115,21 @@ array_function_dereference: '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } ; +dereferencable: + variable { $$ = $1; } + | '(' new_expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } +; + directly_callable_variable: - variable '[' dim_offset ']' + dereferencable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | variable '{' expr '}' + | dereferencable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } | simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | variable T_OBJECT_OPERATOR object_member + | dereferencable T_OBJECT_OPERATOR object_member { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); } function_call_parameter_list @@ -1145,7 +1144,7 @@ directly_callable_variable: variable: directly_callable_variable { $$ = $1; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } - | variable T_OBJECT_OPERATOR object_member + | dereferencable T_OBJECT_OPERATOR object_member { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } ; @@ -1155,6 +1154,13 @@ simple_variable: | '$' simple_variable { zend_do_indirect_reference(&$$, &$2 TSRMLS_CC); } ; +static_member: + class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } + +; + + dim_offset: /* empty */ { $$.op_type = IS_UNUSED; } | expr { $$ = $1; } From 87f8e758c840a88c435c684cbea6defba4a88710 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 May 2014 23:51:54 +0200 Subject: [PATCH 10/33] Cleanup old grammar rules --- Zend/zend_compile.c | 2 -- Zend/zend_language_parser.y | 64 ------------------------------------- 2 files changed, 66 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b6754d202b1fb..a0610b6c32129 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -707,8 +707,6 @@ void zend_do_fetch_static_member(znode *result, znode *class_name, znode *member { znode class_node; zend_llist *fetch_list_ptr; - zend_llist_element *le; - zend_op *opline_ptr; zend_op opline; if (class_name->op_type == IS_CONST && diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index a9293e66153bb..2b8b32e78a3c7 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -747,28 +747,6 @@ non_empty_for_expr: | expr { $$ = $1; } ; -chaining_method_or_property: - chaining_method_or_property variable_property { $$.EA = $2.EA; } - | variable_property { $$.EA = $1.EA; } -; - -chaining_dereference: - chaining_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | '[' dim_offset ']' { zend_do_pop_object(&$1 TSRMLS_CC); fetch_array_dim(&$$, &$1, &$2 TSRMLS_CC); } -; - -chaining_instance_call: - chaining_dereference { zend_do_push_object(&$1 TSRMLS_CC); } chaining_method_or_property { $$ = $3; } - | chaining_dereference { zend_do_push_object(&$1 TSRMLS_CC); $$ = $1; } - | chaining_method_or_property { $$ = $1; } -; - -instance_call: - /* empty */ { $$ = $0; } -/* | { zend_do_push_object(&$0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); } - chaining_instance_call { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); }*/ -; - new_expr: T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; @@ -827,7 +805,6 @@ expr_without_variable: | expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); } | parenthesis_expr { $$ = $1; } | new_expr { $$ = $1; } - | '(' new_expr ')' { $$ = $2; } instance_call { $$ = $5; } | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); } expr { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); } @@ -1081,40 +1058,10 @@ rw_variable: zend_check_writable_variable(&$1); } ; -variable_property: - T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } method_or_not { $$.EA = $4.EA; } -; - -array_method_dereference: - array_method_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | method '[' dim_offset ']' { $1.EA = ZEND_PARSED_METHOD_CALL; fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } -; - -method: - { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } -; - -method_or_not: - method { $$ = $1; $$.EA = ZEND_PARSED_METHOD_CALL; zend_do_push_object(&$$ TSRMLS_CC); } - | array_method_dereference { $$ = $1; zend_do_push_object(&$$ TSRMLS_CC); } - | /* empty */ { $$.EA = ZEND_PARSED_MEMBER; } -; - -variable_without_objects: - variable { $$ = $1; } -; - variable_class_name: variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } ; -array_function_dereference: - array_function_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | function_call { zend_do_begin_variable_parse(TSRMLS_C); $1.EA = ZEND_PARSED_FUNCTION_CALL; } - '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } -; - dereferencable: variable { $$ = $1; } | '(' new_expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } @@ -1171,17 +1118,6 @@ object_member: | simple_variable { fetch_simple_variable_ex(&$$, &$1, 0, ZEND_FETCH_R TSRMLS_CC); } ; -object_property: - object_dim_list { $$ = $1; } - | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); } { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} -; - -object_dim_list: - object_dim_list '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | object_dim_list '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } - | variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} -; - variable_name: T_STRING { $$ = $1; } | '{' expr '}' { $$ = $2; } From 5712f0e9bdf2c2abc513dfd9dcbc17a9c0839871 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 00:02:51 +0200 Subject: [PATCH 11/33] Minor cleanup --- Zend/zend_language_parser.y | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 2b8b32e78a3c7..47f9a3eeeb21d 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1059,7 +1059,7 @@ rw_variable: ; variable_class_name: - variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } + variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } ; dereferencable: @@ -1068,14 +1068,14 @@ dereferencable: ; directly_callable_variable: - dereferencable '[' dim_offset ']' - { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | dereferencable '{' expr '}' - { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | simple_variable + simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } + | dereferencable '[' dim_offset ']' + { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } + | dereferencable '{' expr '}' + { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } | dereferencable T_OBJECT_OPERATOR object_member { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); } From 46a2ca8324ed70c457e8cc57a9cd868c493e47d3 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 00:09:11 +0200 Subject: [PATCH 12/33] Generalize expression dereferencing --- Zend/zend_language_parser.y | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 47f9a3eeeb21d..ec8d29f1942b4 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -45,7 +45,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %} %pure_parser -%expect 3 +%expect 2 %code requires { #ifdef ZTS @@ -1063,8 +1063,8 @@ variable_class_name: ; dereferencable: - variable { $$ = $1; } - | '(' new_expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } + variable { $$ = $1; } + | '(' expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } ; directly_callable_variable: From 75c0db1119eb8b9a1bb414725d1abd1687511640 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 00:18:50 +0200 Subject: [PATCH 13/33] Integrate combined scalar as dereferencable --- Zend/zend_language_parser.y | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index ec8d29f1942b4..1b2026359c4fa 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -821,7 +821,6 @@ expr_without_variable: | T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); } | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } | scalar { $$ = $1; } - | combined_scalar_offset { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); } | combined_scalar { $$ = $1; } | '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } @@ -841,14 +840,10 @@ yield_expr: | T_YIELD expr T_DOUBLE_ARROW variable { zend_do_yield(&$$, &$4, &$2, 1 TSRMLS_CC); } ; -combined_scalar_offset: - combined_scalar '[' dim_offset ']' { zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | combined_scalar_offset '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']' { $1.EA = 0; zend_do_begin_variable_parse(TSRMLS_C); fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - combined_scalar: - T_ARRAY '(' array_pair_list ')' { $$ = $3; } - | '[' array_pair_list ']' { $$ = $2; } + T_ARRAY '(' array_pair_list ')' { $$ = $3; } + | '[' array_pair_list ']' { $$ = $2; } +; function: T_FUNCTION { $$.u.op.opline_num = CG(zend_lineno); } @@ -1065,6 +1060,8 @@ variable_class_name: dereferencable: variable { $$ = $1; } | '(' expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } + | combined_scalar { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } + | T_CONSTANT_ENCAPSED_STRING { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } ; directly_callable_variable: From ff475e9e763ffc74c8c63d26b3d5c9f37c702904 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 00:37:03 +0200 Subject: [PATCH 14/33] Allow arrays + object access for new expressions --- Zend/zend_language_parser.y | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1b2026359c4fa..04455cac9ee89 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -902,7 +902,7 @@ class_name_reference: dynamic_class_name_reference: - simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } + new_variable { $$ = $1; } ; exit_expr: @@ -1104,6 +1104,15 @@ static_member: ; +new_variable: + simple_variable + { zend_do_begin_variable_parse(TSRMLS_C); + fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } + | new_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | new_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } + | new_variable T_OBJECT_OPERATOR object_member + { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); } +; dim_offset: /* empty */ { $$.op_type = IS_UNUSED; } From c5920af515c6833c80d8eef28c9727e5c385c250 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 00:40:32 +0200 Subject: [PATCH 15/33] Update two tests with new semantics --- Zend/tests/isset_003.phpt | 2 +- Zend/tests/isset_003_2_4.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/tests/isset_003.phpt b/Zend/tests/isset_003.phpt index 4db42a933b6b7..92225b59066bb 100644 --- a/Zend/tests/isset_003.phpt +++ b/Zend/tests/isset_003.phpt @@ -14,7 +14,7 @@ var_dump(isset($a[0]->a)); var_dump(isset($c[0][1][2]->a->b->c->d)); -var_dump(isset(${$a}->{$b->$c[$d]})); +var_dump(isset(${$a}->{$b->{$c[$d]}})); var_dump(isset($GLOBALS)); diff --git a/Zend/tests/isset_003_2_4.phpt b/Zend/tests/isset_003_2_4.phpt index c05f3e26f4c1a..42d8cc6a089de 100644 --- a/Zend/tests/isset_003_2_4.phpt +++ b/Zend/tests/isset_003_2_4.phpt @@ -16,7 +16,7 @@ var_dump(isset($a[0]->a)); var_dump(isset($c[0][1][2]->a->b->c->d)); -var_dump(isset(${$a}->{$b->$c[$d]})); +var_dump(isset(${$a}->{$b->{$c[$d]}})); var_dump(isset($GLOBALS)); From c29d3b6e3e7738573f269f62dc119651a27995a5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 00:48:06 +0200 Subject: [PATCH 16/33] Update another test --- Zend/tests/024.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/tests/024.phpt b/Zend/tests/024.phpt index ff35a5c895f13..f89c49e61380a 100644 --- a/Zend/tests/024.phpt +++ b/Zend/tests/024.phpt @@ -11,7 +11,7 @@ var_dump($a++); var_dump(++$b); var_dump($a->$b); var_dump($a->$b); -var_dump($a->$b->$c[1]); +var_dump($a->$b->{$c[1]}); ?> --EXPECTF-- From fcf42d817df81c887056ebcab8c6d16f4e987316 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 15:59:54 +0200 Subject: [PATCH 17/33] Remove object_stack (mostly) --- Zend/zend.c | 3 --- Zend/zend_compile.c | 18 ------------------ Zend/zend_globals.h | 2 +- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index 841fc38565cb4..aec5b331ee0ca 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1036,7 +1036,6 @@ ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ zend_stack function_call_stack; zend_stack switch_cond_stack; zend_stack foreach_copy_stack; - zend_stack object_stack; zend_stack declare_stack; zend_stack list_stack; zend_stack context_stack; @@ -1192,7 +1191,6 @@ ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ SAVE_STACK(function_call_stack); SAVE_STACK(switch_cond_stack); SAVE_STACK(foreach_copy_stack); - SAVE_STACK(object_stack); SAVE_STACK(declare_stack); SAVE_STACK(list_stack); SAVE_STACK(context_stack); @@ -1218,7 +1216,6 @@ ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ RESTORE_STACK(function_call_stack); RESTORE_STACK(switch_cond_stack); RESTORE_STACK(foreach_copy_stack); - RESTORE_STACK(object_stack); RESTORE_STACK(declare_stack); RESTORE_STACK(list_stack); RESTORE_STACK(context_stack); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index a0610b6c32129..e8182a6d05375 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -194,7 +194,6 @@ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ zend_stack_init(&CG(function_call_stack), sizeof(zend_function_call_entry)); zend_stack_init(&CG(switch_cond_stack), sizeof(zend_switch_entry)); zend_stack_init(&CG(foreach_copy_stack), sizeof(zend_op)); - zend_stack_init(&CG(object_stack), sizeof(znode)); zend_stack_init(&CG(declare_stack), sizeof(zend_declarables)); CG(active_class_entry) = NULL; zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0); @@ -242,7 +241,6 @@ void shutdown_compiler(TSRMLS_D) /* {{{ */ zend_stack_destroy(&CG(function_call_stack)); zend_stack_destroy(&CG(switch_cond_stack)); zend_stack_destroy(&CG(foreach_copy_stack)); - zend_stack_destroy(&CG(object_stack)); zend_stack_destroy(&CG(declare_stack)); zend_stack_destroy(&CG(list_stack)); zend_hash_destroy(&CG(filenames_table)); @@ -5556,22 +5554,6 @@ void zend_do_halt_compiler_register(TSRMLS_D) /* {{{ */ } /* }}} */ -void zend_do_push_object(const znode *object TSRMLS_DC) /* {{{ */ -{ - zend_stack_push(&CG(object_stack), object); -} -/* }}} */ - -void zend_do_pop_object(znode *object TSRMLS_DC) /* {{{ */ -{ - if (object) { - znode *tmp = zend_stack_top(&CG(object_stack)); - *object = *tmp; - } - zend_stack_del_top(&CG(object_stack)); -} -/* }}} */ - void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* {{{ */ { zend_op *opline; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 2a29e337de5de..ee68a7be96cce 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -73,7 +73,7 @@ struct _zend_compiler_globals { zend_stack bp_stack; zend_stack switch_cond_stack; zend_stack foreach_copy_stack; - zend_stack object_stack; + zend_stack object_stack; /* TODO: remove */ zend_stack declare_stack; zend_class_entry *active_class_entry; From 8a65c3b2343a7a53f2bfac73db7693e81c59a65c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 16:08:38 +0200 Subject: [PATCH 18/33] Remove now unnecessary code in begin_method_call --- Zend/zend_compile.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e8182a6d05375..02698fca18f14 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1961,35 +1961,22 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead"); } - if (last_op->opcode == ZEND_FETCH_OBJ_R) { - if (last_op->op2_type == IS_CONST) { - zval name; - name = CONSTANT(last_op->op2.constant); - if (Z_TYPE(name) != IS_STRING) { - zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string"); - } - Z_STR(name) = STR_COPY(Z_STR(name)); - FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); - last_op->op2.constant = - zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC); - GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); - } - last_op->opcode = ZEND_INIT_METHOD_CALL; - last_op->result_type = IS_UNUSED; - last_op->result.num = CG(context).nested_calls; - Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; - } else { - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->result.num = CG(context).nested_calls; - SET_UNUSED(opline->op1); - if (left_bracket->op_type == IS_CONST) { - opline->op2_type = IS_CONST; - opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &left_bracket->u.constant TSRMLS_CC); - GET_CACHE_SLOT(opline->op2.constant); - } else { - SET_NODE(opline->op2, left_bracket); + /* Convert ZEND_FETCH_OBJ_R to ZEND_INIT_METHOD_CALL */ + last_op->opcode = ZEND_INIT_METHOD_CALL; + last_op->result_type = IS_UNUSED; + last_op->result.num = CG(context).nested_calls; + Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; + if (last_op->op2_type == IS_CONST) { + zval name; + name = CONSTANT(last_op->op2.constant); + if (Z_TYPE(name) != IS_STRING) { + zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string"); } + Z_STR(name) = STR_COPY(Z_STR(name)); + FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); + last_op->op2.constant = + zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC); + GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); } zend_push_function_call_entry(NULL TSRMLS_CC); From f48241f734b7994c69bfd2636169982b6e5c9045 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 16:27:03 +0200 Subject: [PATCH 19/33] Generalize static access syntax --- Zend/zend_language_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 04455cac9ee89..3257bfff864fd 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1054,7 +1054,7 @@ rw_variable: ; variable_class_name: - variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } + dereferencable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } ; dereferencable: From 4ec505f9b5b1d64f180d7f13ec8a1363485afc92 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 16:33:52 +0200 Subject: [PATCH 20/33] Add two initial tests --- Zend/tests/varSyntax/indirectFcall.phpt | 25 ++++++++++++++++++ Zend/tests/varSyntax/staticMember.phpt | 34 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Zend/tests/varSyntax/indirectFcall.phpt create mode 100644 Zend/tests/varSyntax/staticMember.phpt diff --git a/Zend/tests/varSyntax/indirectFcall.phpt b/Zend/tests/varSyntax/indirectFcall.phpt new file mode 100644 index 0000000000000..e42376a89b705 --- /dev/null +++ b/Zend/tests/varSyntax/indirectFcall.phpt @@ -0,0 +1,25 @@ +--TEST-- +Indirect function calls +--FILE-- + 'id', 'b' => 'udef'])->a)(); + +?> +--EXPECT-- +int(0) +int(1) +int(2) +int(3) +int(4) +int(5) diff --git a/Zend/tests/varSyntax/staticMember.phpt b/Zend/tests/varSyntax/staticMember.phpt new file mode 100644 index 0000000000000..13325bb1c9746 --- /dev/null +++ b/Zend/tests/varSyntax/staticMember.phpt @@ -0,0 +1,34 @@ +--TEST-- +Static member access +--FILE-- + +--EXPECT-- +int(0) +int(0) +int(0) +int(0) +int(0) +int(0) +int(0) +int(1) From 64f80b3835aba0d3ad2c17a78e2d6dcf1c0bfc5e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 16:44:53 +0200 Subject: [PATCH 21/33] Introduce dereferencable_scalar to simplify future additions --- Zend/zend_language_parser.y | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 3257bfff864fd..014915f489e88 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -821,7 +821,6 @@ expr_without_variable: | T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); } | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } | scalar { $$ = $1; } - | combined_scalar { $$ = $1; } | '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } | T_YIELD { zend_do_yield(&$$, NULL, NULL, 0 TSRMLS_CC); } @@ -840,11 +839,6 @@ yield_expr: | T_YIELD expr T_DOUBLE_ARROW variable { zend_do_yield(&$$, &$4, &$2, 1 TSRMLS_CC); } ; -combined_scalar: - T_ARRAY '(' array_pair_list ')' { $$ = $3; } - | '[' array_pair_list ']' { $$ = $2; } -; - function: T_FUNCTION { $$.u.op.opline_num = CG(zend_lineno); } ; @@ -924,10 +918,15 @@ ctor_arguments: ; +dereferencable_scalar: + T_ARRAY '(' array_pair_list ')' { $$ = $3; } + | '[' array_pair_list ']' { $$ = $2; } + | T_CONSTANT_ENCAPSED_STRING { $$ = $1; } +; + common_scalar: T_LNUMBER { $$ = $1; } | T_DNUMBER { $$ = $1; } - | T_CONSTANT_ENCAPSED_STRING { $$ = $1; } | T_LINE { $$ = $1; } | T_FILE { $$ = $1; } | T_DIR { $$ = $1; } @@ -955,6 +954,7 @@ static_scalar_value: | T_NS_SEPARATOR namespace_name { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); if (Z_DELREF($2.u.constant) == 0) {efree(Z_STR($2.u.constant));} Z_STR($2.u.constant) = Z_STR(tmp); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); $$.u.ast = zend_ast_create_constant(&$$.u.constant); } | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; } | '[' static_array_pair_list ']' { $$ = $2; } + | T_CONSTANT_ENCAPSED_STRING { $$ = $1; } | static_class_constant { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } | T_CLASS_C { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } | static_operation { $$ = $1; } @@ -1007,6 +1007,7 @@ scalar: | '"' encaps_list '"' { $$ = $2; } | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; } | T_CLASS_C { if (Z_TYPE($1.u.constant) == IS_CONSTANT) {zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC);} else {$$ = $1;} } + | dereferencable_scalar { $$ = $1; } ; @@ -1058,10 +1059,9 @@ variable_class_name: ; dereferencable: - variable { $$ = $1; } - | '(' expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } - | combined_scalar { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } - | T_CONSTANT_ENCAPSED_STRING { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } + variable { $$ = $1; } + | '(' expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } + | dereferencable_scalar { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } ; directly_callable_variable: From fd85f77857b38ba0ec2c27a1c27a3e0ebae36410 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 17:02:48 +0200 Subject: [PATCH 22/33] Fix previous commit --- Zend/zend_language_parser.y | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 014915f489e88..4473e3771d37a 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -946,17 +946,21 @@ static_scalar: /* compile-time evaluated scalars */ static_scalar_value { zend_do_constant_expression(&$$, $1.u.ast TSRMLS_CC); } ; +static_scalar_base: + common_scalar { $$ = $1; } + | T_CONSTANT_ENCAPSED_STRING { $$ = $1; } + | T_CLASS_C { $$ = $1; } + | static_class_name_scalar { $$ = $1; } + | static_class_constant { $$ = $1; } + | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); } + | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); if (Z_DELREF($2.u.constant) == 0) {efree(Z_STR($2.u.constant));} Z_STR($2.u.constant) = Z_STR(tmp); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); } +; + static_scalar_value: - common_scalar { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } - | static_class_name_scalar { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } - | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); $$.u.ast = zend_ast_create_constant(&$$.u.constant); } - | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); $$.u.ast = zend_ast_create_constant(&$$.u.constant); } - | T_NS_SEPARATOR namespace_name { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); if (Z_DELREF($2.u.constant) == 0) {efree(Z_STR($2.u.constant));} Z_STR($2.u.constant) = Z_STR(tmp); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); $$.u.ast = zend_ast_create_constant(&$$.u.constant); } + static_scalar_base { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; } | '[' static_array_pair_list ']' { $$ = $2; } - | T_CONSTANT_ENCAPSED_STRING { $$ = $1; } - | static_class_constant { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } - | T_CLASS_C { $$.u.ast = zend_ast_create_constant(&$1.u.constant); } | static_operation { $$ = $1; } ; From 64e4c9eff16b082f87e94fc02ec620b85124197d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 17:18:37 +0200 Subject: [PATCH 23/33] Support directly calling closure --- Zend/tests/varSyntax/indirectFcall.phpt | 16 +++++++++++++++- Zend/zend_language_parser.y | 12 +++++++++--- Zend/zend_vm_def.h | 4 ++-- Zend/zend_vm_execute.h | 16 ++++++++-------- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Zend/tests/varSyntax/indirectFcall.phpt b/Zend/tests/varSyntax/indirectFcall.phpt index e42376a89b705..4499f5ab641d1 100644 --- a/Zend/tests/varSyntax/indirectFcall.phpt +++ b/Zend/tests/varSyntax/indirectFcall.phpt @@ -13,7 +13,17 @@ id('id')('id')('var_dump')(3); id()()('var_dump')(4); id(['udef', 'id'])[1]()('var_dump')(5); -// (id((object) ['a' => 'id', 'b' => 'udef'])->a)(); +(id((object) ['a' => 'id', 'b' => 'udef'])->a)()()()()('var_dump')(6); + +$id = function($x) { return $x; }; + +$id($id)('var_dump')(7); + +(function($x) { return $x; })('id')('var_dump')(8); + +($f = function($x = null) use (&$f) { + return $x ?: $f; +})()()()('var_dump')(9); ?> --EXPECT-- @@ -23,3 +33,7 @@ int(2) int(3) int(4) int(5) +int(6) +int(7) +int(8) +int(9) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 4473e3771d37a..d6b0f874c3588 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -870,7 +870,7 @@ function_call: function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { fetch_simple_variable_ex(&$$, &$3, 0, ZEND_FETCH_R TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$$ TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | directly_callable_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } + | callable_expr { zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; @@ -1068,7 +1068,13 @@ dereferencable: | dereferencable_scalar { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } ; -directly_callable_variable: +callable_expr: + callable_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } + | '(' expr ')' { $$ = $2; } + | dereferencable_scalar { $$ = $1; } +; + +callable_variable: simple_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); @@ -1090,7 +1096,7 @@ directly_callable_variable: ; variable: - directly_callable_variable { $$ = $1; } + callable_variable { $$ = $1; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } | dereferencable T_OBJECT_OPERATOR object_member { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0b5dde159922a..20d350a892387 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2646,7 +2646,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && + } else if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { @@ -2657,7 +2657,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name_ptr; - } else { + } else if (OP2_TYPE == IS_CV) { FREE_OP2(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a5b678c9d247b..c2e103965a48e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1515,7 +1515,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && + } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { @@ -1526,7 +1526,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name_ptr; - } else { + } else if (IS_CONST == IS_CV) { } @@ -1846,7 +1846,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && + } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { @@ -1857,7 +1857,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name_ptr; - } else { + } else if (IS_TMP_VAR == IS_CV) { zval_dtor(free_op2.var); } @@ -2035,7 +2035,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && + } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { @@ -2046,7 +2046,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name_ptr; - } else { + } else if (IS_VAR == IS_CV) { zval_ptr_dtor_nogc(free_op2.var); } @@ -2261,7 +2261,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && + } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { @@ -2272,7 +2272,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name_ptr; - } else { + } else if (IS_CV == IS_CV) { } From c53a7ea4e5e70e6f748f5c13f48c24843a0bac45 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 17:36:22 +0200 Subject: [PATCH 24/33] Property handle calls on [] and '' consts/tmps --- Zend/tests/varSyntax/indirectFcall.phpt | 14 ++++++++++++++ Zend/zend_compile.c | 2 +- Zend/zend_vm_def.h | 5 ++--- Zend/zend_vm_execute.h | 20 ++++++++------------ 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Zend/tests/varSyntax/indirectFcall.phpt b/Zend/tests/varSyntax/indirectFcall.phpt index 4499f5ab641d1..4cc5c1171a993 100644 --- a/Zend/tests/varSyntax/indirectFcall.phpt +++ b/Zend/tests/varSyntax/indirectFcall.phpt @@ -25,6 +25,16 @@ $id($id)('var_dump')(7); return $x ?: $f; })()()()('var_dump')(9); +class Test { + public static function id($x = [__CLASS__, 'id']) { return $x; } +} + +$obj = new Test; +[$obj, 'id']()('id')($id)('var_dump')(10); +['Test', 'id']()()('var_dump')(11); +'id'()('id')('var_dump')(12); +('i' . 'd')()('var_dump')(13); + ?> --EXPECT-- int(0) @@ -37,3 +47,7 @@ int(6) int(7) int(8) int(9) +int(10) +int(11) +int(12) +int(13) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 02698fca18f14..7040ed6c5aa7c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2018,7 +2018,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML opline->opcode = ZEND_INIT_FCALL_BY_NAME; opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); - if (function_name->op_type == IS_CONST) { + if (function_name->op_type == IS_CONST && Z_TYPE(function_name->u.constant) == IS_STRING) { opline->op2_type = IS_CONST; opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); GET_CACHE_SLOT(opline->op2.constant); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 20d350a892387..2bd0280900721 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2595,7 +2595,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) zval *function_name_ptr, *function_name, *func; call_slot *call = EX(call_slots) + opline->result.num; - if (OP2_TYPE == IS_CONST) { + if (OP2_TYPE == IS_CONST && Z_TYPE_P(opline->op2.zv) == IS_STRING) { function_name_ptr = function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); @@ -2667,8 +2667,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (OP2_TYPE != IS_CONST && - EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { zval *obj; zval *method; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c2e103965a48e..24f016066cbec 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1465,7 +1465,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE zval *function_name_ptr, *function_name, *func; call_slot *call = EX(call_slots) + opline->result.num; - if (IS_CONST == IS_CONST) { + if (IS_CONST == IS_CONST && Z_TYPE_P(opline->op2.zv) == IS_STRING) { function_name_ptr = function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); @@ -1536,8 +1536,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_CONST != IS_CONST && - EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { zval *obj; zval *method; @@ -1795,7 +1794,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H zval *function_name_ptr, *function_name, *func; call_slot *call = EX(call_slots) + opline->result.num; - if (IS_TMP_VAR == IS_CONST) { + if (IS_TMP_VAR == IS_CONST && Z_TYPE_P(opline->op2.zv) == IS_STRING) { function_name_ptr = function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); @@ -1867,8 +1866,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_TMP_VAR != IS_CONST && - EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { zval *obj; zval *method; @@ -1984,7 +1982,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H zval *function_name_ptr, *function_name, *func; call_slot *call = EX(call_slots) + opline->result.num; - if (IS_VAR == IS_CONST) { + if (IS_VAR == IS_CONST && Z_TYPE_P(opline->op2.zv) == IS_STRING) { function_name_ptr = function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); @@ -2056,8 +2054,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_VAR != IS_CONST && - EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { zval *obj; zval *method; @@ -2211,7 +2208,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA zval *function_name_ptr, *function_name, *func; call_slot *call = EX(call_slots) + opline->result.num; - if (IS_CV == IS_CONST) { + if (IS_CV == IS_CONST && Z_TYPE_P(opline->op2.zv) == IS_STRING) { function_name_ptr = function_name = (zval*)(opline->op2.zv+1); if (CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv))) { call->fbc = CACHED_PTR(Z_CACHE_SLOT_P(opline->op2.zv)); @@ -2282,8 +2279,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_CV != IS_CONST && - EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && + } else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) && zend_hash_num_elements(Z_ARRVAL_P(function_name)) == 2) { zval *obj; zval *method; From f0ac7f7d7b694a4c567d190b79377219a1994f62 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 17:51:22 +0200 Subject: [PATCH 25/33] Properly handle property read on const/tmp --- Zend/tests/varSyntax/parenthesesDeref.phpt | 20 ++ .../varSyntax/propertyOfStringError.phpt | 10 + Zend/zend_vm_def.h | 4 +- Zend/zend_vm_execute.h | 316 +++++++++++++++++- 4 files changed, 340 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/varSyntax/parenthesesDeref.phpt create mode 100644 Zend/tests/varSyntax/propertyOfStringError.phpt diff --git a/Zend/tests/varSyntax/parenthesesDeref.phpt b/Zend/tests/varSyntax/parenthesesDeref.phpt new file mode 100644 index 0000000000000..0ebfe9c5d7206 --- /dev/null +++ b/Zend/tests/varSyntax/parenthesesDeref.phpt @@ -0,0 +1,20 @@ +--TEST-- +Dereferencing expression parentheses +--FILE-- + 0, 'b' => 1])->b); + +$obj = (object) ['a' => 0, 'b' => ['var_dump', 1]]; +(clone $obj)->b[0](1); + +?> +--EXPECT-- +int(1) +int(1) +int(1) +int(1) diff --git a/Zend/tests/varSyntax/propertyOfStringError.phpt b/Zend/tests/varSyntax/propertyOfStringError.phpt new file mode 100644 index 0000000000000..85abc5849a7ff --- /dev/null +++ b/Zend/tests/varSyntax/propertyOfStringError.phpt @@ -0,0 +1,10 @@ +--TEST-- +Cannot take property of a string +--FILE-- +bar; + +?> +--EXPECTF-- +Notice: Trying to get property of non-object in %s on line %d diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2bd0280900721..aaf1e494bb4ea 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1386,7 +1386,7 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HELPER(zend_fetch_property_address_read_helper, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1; @@ -1419,7 +1419,7 @@ ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_property_address_read_helper); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 24f016066cbec..d2b8f57d79722 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3725,6 +3725,43 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4704,6 +4741,44 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5532,6 +5607,44 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_ptr_dtor_nogc(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -7039,6 +7152,43 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -8896,6 +9046,43 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9743,6 +9930,44 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op2.var); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10571,6 +10796,44 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_ptr_dtor_nogc(free_op2.var); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -11946,6 +12209,43 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDL ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -41965,16 +42265,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_DIM_R_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_DIM_R_SPEC_CV_CV_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER, ZEND_FETCH_OBJ_R_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_OBJ_R_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_OBJ_R_SPEC_VAR_VAR_HANDLER, From 72b5e0cac00bac0b2253c4324d44eb4438a103de Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 18:18:20 +0200 Subject: [PATCH 26/33] Add another static member access test --- Zend/tests/varSyntax/staticMember.phpt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zend/tests/varSyntax/staticMember.phpt b/Zend/tests/varSyntax/staticMember.phpt index 13325bb1c9746..22a1fa2b13215 100644 --- a/Zend/tests/varSyntax/staticMember.phpt +++ b/Zend/tests/varSyntax/staticMember.phpt @@ -6,6 +6,7 @@ Static member access class A { public static $b = 0; public static $c = [0, 1]; + public static $A_str = 'A'; } $A_str = 'A'; @@ -21,6 +22,7 @@ var_dump('A'::$b); var_dump('A'[0]::$b); var_dump(A::$$b_str); var_dump(A::$$c_str[1]); +var_dump(A::$A_str::$b); ?> --EXPECT-- @@ -32,3 +34,4 @@ int(0) int(0) int(0) int(1) +int(0) From 5c2120b6cf0d4a92a29dc7c38b407ee5ed213ddf Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 19:41:39 +0200 Subject: [PATCH 27/33] Forbid writing to temporary expressions --- Zend/tests/varSyntax/writeToTempExpr.phpt | 10 ++++ Zend/zend_compile.c | 62 ++++++++++++++++------- Zend/zend_language_parser.y | 4 +- 3 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 Zend/tests/varSyntax/writeToTempExpr.phpt diff --git a/Zend/tests/varSyntax/writeToTempExpr.phpt b/Zend/tests/varSyntax/writeToTempExpr.phpt new file mode 100644 index 0000000000000..daeaf2493811c --- /dev/null +++ b/Zend/tests/varSyntax/writeToTempExpr.phpt @@ -0,0 +1,10 @@ +--TEST-- +Writing to a temporary expression is not allowed +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use temporary expression in write context in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7040ed6c5aa7c..f5efd84144544 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1234,6 +1234,22 @@ void zend_do_begin_variable_parse(TSRMLS_D) /* {{{ */ } /* }}} */ +static zend_bool zend_can_parse_variable_for_write(znode *variable TSRMLS_DC) /* {{{ */ +{ + zend_llist *fetch_list_ptr = zend_stack_top(&CG(bp_stack)); + zend_llist_element *le = fetch_list_ptr->head; + for (le = fetch_list_ptr->head; le; le = le->next) { + zend_op *opline = (zend_op *) le->data; + if ((opline->opcode != ZEND_SEPARATE && opline->opcode != ZEND_FETCH_W) + && (opline->op1_type == IS_TMP_VAR || opline->op1_type == IS_CONST) + ) { + return 0; + } + } + return 1; +} +/* }}} */ + void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) /* {{{ */ { zend_llist *fetch_list_ptr = zend_stack_top(&CG(bp_stack)); @@ -1286,6 +1302,13 @@ void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS opline->op1_type = IS_CV; opline->op1.var = CG(active_op_array)->this_var; } + if (opline->opcode != ZEND_FETCH_W + && (opline->op1_type == IS_TMP_VAR || opline->op1_type == IS_CONST) + && (type != BP_VAR_R && type != BP_VAR_IS && type != BP_VAR_FUNC_ARG) + ) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use temporary expression in write context"); + } switch (type) { case BP_VAR_R: if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { @@ -6373,18 +6396,19 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno zend_bool is_variable; zend_op dummy_opline; + open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); if (variable) { - if (zend_is_function_or_method_call(array)) { + if (zend_is_function_or_method_call(array) + || !zend_can_parse_variable_for_write(array TSRMLS_CC) + ) { is_variable = 0; + zend_do_end_variable_parse(array, BP_VAR_R, 0 TSRMLS_CC); } else { is_variable = 1; + zend_do_end_variable_parse(array, BP_VAR_W, 0 TSRMLS_CC); } - /* save the location of FETCH_W instruction(s) */ - open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); - zend_do_end_variable_parse(array, BP_VAR_W, 0 TSRMLS_CC); } else { is_variable = 0; - open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); } /* save the location of FE_RESET */ @@ -6464,19 +6488,21 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE; } else { zend_op *fetch = &CG(active_op_array)->opcodes[foreach_token->u.op.opline_num]; - zend_op *end = &CG(active_op_array)->opcodes[open_brackets_token->u.op.opline_num]; - - /* Change "write context" into "read context" */ - fetch->extended_value = 0; /* reset ZEND_FE_RESET_VARIABLE */ - while (fetch != end) { - --fetch; - if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2_type == IS_UNUSED) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading"); - } - if (fetch->opcode == ZEND_SEPARATE) { - MAKE_NOP(fetch); - } else { - fetch->opcode -= 3; /* FETCH_W -> FETCH_R */ + if (fetch->extended_value == ZEND_FE_RESET_VARIABLE) { + zend_op *end = &CG(active_op_array)->opcodes[open_brackets_token->u.op.opline_num]; + + /* Change "write context" into "read context" */ + fetch->extended_value = 0; /* reset ZEND_FE_RESET_VARIABLE */ + while (fetch != end) { + --fetch; + if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2_type == IS_UNUSED) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading"); + } + if (fetch->opcode == ZEND_SEPARATE) { + MAKE_NOP(fetch); + } else { + fetch->opcode -= 3; /* FETCH_W -> FETCH_R */ + } } } } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index d6b0f874c3588..68ac2b7076a50 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1064,8 +1064,8 @@ variable_class_name: dereferencable: variable { $$ = $1; } - | '(' expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); } - | dereferencable_scalar { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); } + | '(' expr ')' { $$ = $2; zend_do_begin_variable_parse(TSRMLS_C); $$.EA = 0; } + | dereferencable_scalar { $$ = $1; zend_do_begin_variable_parse(TSRMLS_C); $$.EA = 0; } ; callable_expr: From 96b32ec532feb256e503a67bdc4dfe6a2ce4d281 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 20:05:03 +0200 Subject: [PATCH 28/33] Support isset() on temporaries --- Zend/tests/varSyntax/issetOnTemp.phpt | 26 + Zend/zend_vm_def.h | 12 +- Zend/zend_vm_execute.h | 1564 ++++++++++++++++++++++++- 3 files changed, 1564 insertions(+), 38 deletions(-) create mode 100644 Zend/tests/varSyntax/issetOnTemp.phpt diff --git a/Zend/tests/varSyntax/issetOnTemp.phpt b/Zend/tests/varSyntax/issetOnTemp.phpt new file mode 100644 index 0000000000000..cd7bc006cde8b --- /dev/null +++ b/Zend/tests/varSyntax/issetOnTemp.phpt @@ -0,0 +1,26 @@ +--TEST-- +isset() can be used on dereferences of temporary expressions +--FILE-- + 'b'])->a)); +var_dump(isset(['a' => 'b']->a)); +var_dump(isset("str"->a)); +var_dump(isset((['a' => 'b'] + [])->a)); +var_dump(isset((['a' => 'b'] + [])->a->b)); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index aaf1e494bb4ea..b1993f99a35b9 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1317,7 +1317,7 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMP|VAR|UNUSED|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, VAR|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -1473,7 +1473,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1; @@ -4627,7 +4627,7 @@ ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(115, ZEND_ISSET_ISEMPTY_DIM_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -4731,12 +4731,12 @@ ZEND_VM_C_LABEL(str_index_prop): FREE_OP2(); ZVAL_BOOL(EX_VAR(opline->result.var), result); - FREE_OP1_IF_VAR(); + FREE_OP1(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -4764,7 +4764,7 @@ ZEND_VM_HANDLER(148, ZEND_ISSET_ISEMPTY_PROP_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|C FREE_OP2(); ZVAL_BOOL(EX_VAR(opline->result.var), result); - FREE_OP1_IF_VAR(); + FREE_OP1(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d2b8f57d79722..fd9247ffc2812 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3725,6 +3725,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + SAVE_OPLINE(); + container = opline->op1.zv; + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3762,6 +3777,37 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_ return zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4271,6 +4317,146 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_CONST_HANDLER(ZEND_O ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = opline->op2.zv; + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_CONST != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = opline->op2.zv; + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4741,6 +4927,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *container; + + SAVE_OPLINE(); + container = opline->op1.zv; + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4779,6 +4980,38 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HA return zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5024,6 +5257,148 @@ static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HAN } } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_TMP_VAR != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_dtor(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_dtor(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5607,6 +5982,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *container; + + SAVE_OPLINE(); + container = opline->op1.zv; + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5645,6 +6035,38 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HA return zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_ptr_dtor_nogc(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -6041,6 +6463,148 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_VAR_HANDLER(ZEND_OPC ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_VAR != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_ptr_dtor_nogc(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_ptr_dtor_nogc(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -7152,6 +7716,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + SAVE_OPLINE(); + container = opline->op1.zv; + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -7189,6 +7768,37 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HAN return zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -7486,6 +8096,146 @@ static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HAND } } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_CV != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9046,6 +9796,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9083,6 +9848,37 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HA return zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9493,6 +10289,146 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPC ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = opline->op2.zv; + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_CONST != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = opline->op2.zv; + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9930,6 +10866,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *container; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); + zval_dtor(free_op2.var); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9968,6 +10919,38 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HAND return zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op2.var); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10213,6 +11196,148 @@ static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDL } } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_TMP_VAR != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_dtor(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_dtor(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10796,6 +11921,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *container; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10834,6 +11974,38 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HAND return zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_ptr_dtor_nogc(free_op2.var); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -11230,6 +12402,148 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCOD ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_VAR != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_ptr_dtor_nogc(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + zval_ptr_dtor_nogc(free_op2.var); + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12209,6 +13523,21 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDL ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_IS(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12246,6 +13575,37 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDL return zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + zval *retval; + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1), EX_VAR(opline->result.var) TSRMLS_CC); + + if (retval != EX_VAR(opline->result.var)) { + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12488,6 +13848,146 @@ static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLE } } +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + int result; + ulong hval; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(container); + zval *value = NULL; + zend_string *str; + +isset_again: + switch (Z_TYPE_P(offset)) { + case IS_DOUBLE: + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_prop; + case IS_LONG: + hval = Z_LVAL_P(offset); +num_index_prop: + value = zend_hash_index_find(ht, hval); + break; + case IS_STRING: + str = Z_STR_P(offset); + if (IS_CV != IS_CONST) { + ZEND_HANDLE_NUMERIC_EX(str->val, str->len+1, hval, goto num_index_prop); + } +str_index_prop: + value = zend_hash_find_ind(ht, str); + break; + case IS_NULL: + str = STR_EMPTY_ALLOC(); + goto str_index_prop; + break; + case IS_FALSE: + hval = 0; + goto num_index_prop; + case IS_TRUE: + hval = 0; + goto num_index_prop; + case IS_RESOURCE: + hval = Z_RES_HANDLE_P(offset); + goto num_index_prop; + case IS_REFERENCE: + offset = Z_REFVAL_P(offset); + goto isset_again; + break; + default: + zend_error(E_WARNING, "Illegal offset type in isset or empty"); + break; + } + + if (opline->extended_value & ZEND_ISSET) { + /* > IS_NULL means not IS_UNDEF and not IS_NULL */ + result = (value != NULL && Z_TYPE_P(value) > IS_NULL); + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + result = (value == NULL || !i_zend_is_true(value TSRMLS_CC)); + } + } else if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_dimension) { + result = Z_OBJ_HT_P(container)->has_dimension(container, offset, (opline->extended_value & ZEND_ISSET) == 0 TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check element of non-array"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else if (Z_TYPE_P(container) == IS_STRING) { /* string offsets */ + zval tmp; + + result = 0; + if (UNEXPECTED(Z_TYPE_P(offset) != IS_LONG)) { + if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */ + || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */ + && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) { + ZVAL_DUP(&tmp, offset); + convert_to_long(&tmp); + offset = &tmp; + } + } + if (Z_TYPE_P(offset) == IS_LONG) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_P(container)) { + if ((opline->extended_value & ZEND_ISSET) || + Z_STRVAL_P(container)[offset->value.lval] != '0') { + result = 1; + } + } + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + int result; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (Z_TYPE_P(container) == IS_OBJECT) { + if (Z_OBJ_HT_P(container)->has_property) { + result = Z_OBJ_HT_P(container)->has_property(container, offset, (opline->extended_value & ZEND_ISSET) == 0, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(offset) : -1) TSRMLS_CC); + } else { + zend_error(E_NOTICE, "Trying to check property of non-object"); + result = 0; + } + if ((opline->extended_value & ZEND_ISSET) == 0) { + result = !result; + } + } else { + result = ((opline->extended_value & ZEND_ISSET) == 0); + } + + ZVAL_BOOL(EX_VAR(opline->result.var), result); + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -42465,16 +43965,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_IS_SPEC_CV_VAR_HANDLER, ZEND_FETCH_IS_SPEC_CV_UNUSED_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_CV_HANDLER, ZEND_FETCH_DIM_IS_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_DIM_IS_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_DIM_IS_SPEC_VAR_VAR_HANDLER, @@ -42490,16 +43990,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_DIM_IS_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_DIM_IS_SPEC_CV_CV_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_CV_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_VAR_VAR_HANDLER, @@ -43090,16 +44590,16 @@ void zend_init_opcodes_handlers(void) ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_VAR_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_UNUSED_HANDLER, ZEND_NULL_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_CONST_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_TMP_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CONST_CV_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_CONST_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_TMP_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_TMP_CV_HANDLER, ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_VAR_CONST_HANDLER, ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_VAR_TMP_HANDLER, ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_VAR_VAR_HANDLER, @@ -43915,16 +45415,16 @@ void zend_init_opcodes_handlers(void) ZEND_ASSIGN_DIM_SPEC_CV_VAR_HANDLER, ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER, ZEND_ASSIGN_DIM_SPEC_CV_CV_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_CONST_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_TMP_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CONST_CV_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_CONST_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_TMP_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_TMP_CV_HANDLER, ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_CONST_HANDLER, ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_TMP_HANDLER, ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_VAR_HANDLER, From 8515b96e534aa1cf78d9314e6efda6c5ed87c1ea Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 20:15:55 +0200 Subject: [PATCH 29/33] Handle FUNC_ARG fetches on temporaries --- .../varSyntax/tempDimFetchByRefError.phpt | 11 + .../varSyntax/tempPropFetchByRefError.phpt | 11 + Zend/zend_vm_def.h | 10 +- Zend/zend_vm_execute.h | 716 +++++++++++++++++- 4 files changed, 728 insertions(+), 20 deletions(-) create mode 100644 Zend/tests/varSyntax/tempDimFetchByRefError.phpt create mode 100644 Zend/tests/varSyntax/tempPropFetchByRefError.phpt diff --git a/Zend/tests/varSyntax/tempDimFetchByRefError.phpt b/Zend/tests/varSyntax/tempDimFetchByRefError.phpt new file mode 100644 index 0000000000000..dbcac75ea9886 --- /dev/null +++ b/Zend/tests/varSyntax/tempDimFetchByRefError.phpt @@ -0,0 +1,11 @@ +--TEST-- +Passing a dimention fetch on a temporary by reference is not allowed +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use temporary expression in write context in %s on line %d diff --git a/Zend/tests/varSyntax/tempPropFetchByRefError.phpt b/Zend/tests/varSyntax/tempPropFetchByRefError.phpt new file mode 100644 index 0000000000000..f8298a936dca2 --- /dev/null +++ b/Zend/tests/varSyntax/tempPropFetchByRefError.phpt @@ -0,0 +1,11 @@ +--TEST-- +Passing a property fetch on a temporary by reference is not allowed +--FILE-- +prop); + +?> +--EXPECTF-- +Fatal error: Cannot use temporary expression in write context in %s on line %d diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b1993f99a35b9..84503b7d9f597 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1332,7 +1332,7 @@ ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV) +ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNUSED|CV) { USE_OPLINE zval *container; @@ -1341,6 +1341,9 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV) SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -1505,7 +1508,7 @@ ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zval *container; @@ -1519,6 +1522,9 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV) property = GET_OP2_ZVAL_PTR(BP_VAR_R); container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fd9247ffc2812..b93f1ef88181c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3740,6 +3740,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + + } else { + if (IS_CONST == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = opline->op1.zv; + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); + + + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3808,6 +3843,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1; + zval *property; + + SAVE_OPLINE(); + property = opline->op2.zv; + container = NULL; + + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_CONST == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4942,6 +5010,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_H ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1, free_op2; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + zval_dtor(free_op2.var); + + } else { + if (IS_TMP_VAR == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = opline->op1.zv; + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); + zval_dtor(free_op2.var); + + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5012,6 +5115,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_H ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1, free_op2; + zval *property; + + SAVE_OPLINE(); + property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = NULL; + + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_CONST == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + zval_dtor(free_op2.var); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5997,6 +6133,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_H ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1, free_op2; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + zval_ptr_dtor_nogc(free_op2.var); + + } else { + if (IS_VAR == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = opline->op1.zv; + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -6067,6 +6238,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_H ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1, free_op2; + zval *property; + + SAVE_OPLINE(); + property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = NULL; + + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_CONST == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -6896,6 +7100,41 @@ static int ZEND_FASTCALL ZEND_FETCH_IS_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_IS, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + + } else { + if (IS_UNUSED == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = opline->op1.zv; + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); + + + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -7731,6 +7970,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_CONST == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + + } else { + if (IS_CV == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = opline->op1.zv; + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); + + + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -7799,6 +8073,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1; + zval *property; + + SAVE_OPLINE(); + property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + container = NULL; + + if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_CONST == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + + if (IS_CONST == IS_VAR && 0 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9811,6 +10118,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_H ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + + } else { + if (IS_CONST == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, opline->op2.zv, IS_CONST TSRMLS_CC); + + zval_dtor(free_op1.var); + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9879,6 +10221,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_H ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1; + zval *property; + + SAVE_OPLINE(); + property = opline->op2.zv; + container = NULL; + + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_CONST == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10881,6 +11256,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1, free_op2; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + zval_dtor(free_op2.var); + + } else { + if (IS_TMP_VAR == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR TSRMLS_CC); + zval_dtor(free_op2.var); + zval_dtor(free_op1.var); + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10951,6 +11361,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1, free_op2; + zval *property; + + SAVE_OPLINE(); + property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = NULL; + + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_TMP_VAR == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + zval_dtor(free_op2.var); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -11936,6 +12379,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1, free_op2; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + zval_ptr_dtor_nogc(free_op2.var); + + } else { + if (IS_VAR == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + zval_dtor(free_op1.var); + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12006,6 +12484,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1, free_op2; + zval *property; + + SAVE_OPLINE(); + property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + container = NULL; + + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_VAR == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + zval_ptr_dtor_nogc(free_op2.var); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12835,6 +13346,41 @@ static int ZEND_FASTCALL ZEND_FETCH_IS_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HAND return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(BP_VAR_IS, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + + } else { + if (IS_UNUSED == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, NULL, IS_UNUSED TSRMLS_CC); + + zval_dtor(free_op1.var); + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -13538,6 +14084,41 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + zend_free_op free_op1; + + SAVE_OPLINE(); + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + container = NULL; + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(container == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); + } + zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + + } else { + if (IS_CV == IS_UNUSED) { + zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); + } + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV TSRMLS_CC); + + zval_dtor(free_op1.var); + } + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -13606,6 +14187,39 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *container; + + if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + /* Behave like FETCH_OBJ_W */ + zend_free_op free_op1; + zval *property; + + SAVE_OPLINE(); + property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + container = NULL; + + if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } + if (IS_TMP_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { + zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); + } + zend_fetch_property_address(EX_VAR(opline->result.var), container, property, ((IS_CV == IS_CONST) ? Z_CACHE_SLOT_P(property) : -1), BP_VAR_W, 0 TSRMLS_CC); + + if (IS_TMP_VAR == IS_VAR && 1 && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else { + return zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -16623,6 +17237,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -16799,6 +17416,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP property = opline->op2.zv; container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -18838,6 +19458,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -19016,6 +19639,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -20963,6 +21589,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -21141,6 +21770,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -22815,6 +23447,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_O SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -24328,6 +24963,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -24504,6 +25142,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); container = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -26205,6 +26846,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CONST_HANDLER(ZEND property = opline->op2.zv; container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -27566,6 +28210,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_TMP_HANDLER(ZEND_O property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -28844,6 +29491,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_VAR_HANDLER(ZEND_O property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -30633,6 +31283,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CV_HANDLER(ZEND_OP property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); container = _get_obj_zval_ptr_unused(TSRMLS_C); + if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_UNUSED == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -33557,6 +34210,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -33733,6 +34389,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC property = opline->op2.zv; container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -35563,6 +36222,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -35741,6 +36403,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD property = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -37571,6 +38236,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -37749,6 +38417,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD property = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -39305,6 +39976,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OP SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -40684,6 +41358,9 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE SAVE_OPLINE(); if (zend_is_by_ref_func_arg_fetch(opline, EX(call) TSRMLS_CC)) { + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -40860,6 +41537,9 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE property = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); container = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); + if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { + zend_error_noreturn(E_ERROR, "Cannot use temporary expression in write context"); + } if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(container) == IS_STR_OFFSET)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } @@ -44040,16 +44720,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_FUNC_ARG_SPEC_CV_VAR_HANDLER, ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_VAR_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_VAR_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER, + ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CV_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_VAR_HANDLER, @@ -44065,16 +44745,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_VAR_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNUSED_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV_HANDLER, ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_VAR_HANDLER, From 8d7f5a403a248fa7de3da6729505aa53feb7549a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 20:58:44 +0200 Subject: [PATCH 30/33] Remove duplication --- Zend/zend_language_parser.y | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 68ac2b7076a50..20e41d3ba6f20 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -862,13 +862,9 @@ function_call: function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | T_NS_SEPARATOR namespace_name { $$.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$2, &$$, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } - | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | class_name T_PAAMAYIM_NEKUDOTAYIM member_name_or_variable { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { fetch_simple_variable_ex(&$$, &$3, 0, ZEND_FETCH_R TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$$ TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable { fetch_simple_variable_ex(&$$, &$3, 0, ZEND_FETCH_R TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$$ TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name_or_variable { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | callable_expr { zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} @@ -1083,7 +1079,7 @@ callable_variable: { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } | dereferencable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | dereferencable T_OBJECT_OPERATOR object_member + | dereferencable T_OBJECT_OPERATOR member_name_or_variable { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); } function_call_parameter_list @@ -1098,7 +1094,7 @@ callable_variable: variable: callable_variable { $$ = $1; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } - | dereferencable T_OBJECT_OPERATOR object_member + | dereferencable T_OBJECT_OPERATOR member_name_or_variable { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } ; @@ -1120,7 +1116,7 @@ new_variable: fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } | new_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | new_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } - | new_variable T_OBJECT_OPERATOR object_member + | new_variable T_OBJECT_OPERATOR member_name_or_variable { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); } ; @@ -1129,12 +1125,12 @@ dim_offset: | expr { $$ = $1; } ; -object_member: - variable_name { $$ = $1; } - | simple_variable { fetch_simple_variable_ex(&$$, &$1, 0, ZEND_FETCH_R TSRMLS_CC); } +member_name_or_variable: + member_name { $$ = $1; } + | simple_variable { fetch_simple_variable_ex(&$$, &$1, 0, ZEND_FETCH_R TSRMLS_CC); } ; -variable_name: +member_name: T_STRING { $$ = $1; } | '{' expr '}' { $$ = $2; } ; From f4a11b66cc54995cfe7c25ea34e8f1948ed7a055 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 31 May 2014 21:00:11 +0200 Subject: [PATCH 31/33] Merge and rename to member_name --- Zend/zend_language_parser.y | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 20e41d3ba6f20..6eb2c4287e22d 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -862,9 +862,9 @@ function_call: function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | T_NS_SEPARATOR namespace_name { $$.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$2, &$$, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } - | class_name T_PAAMAYIM_NEKUDOTAYIM member_name_or_variable { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | class_name T_PAAMAYIM_NEKUDOTAYIM member_name { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name_or_variable { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | callable_expr { zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} @@ -1079,7 +1079,7 @@ callable_variable: { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } | dereferencable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } - | dereferencable T_OBJECT_OPERATOR member_name_or_variable + | dereferencable T_OBJECT_OPERATOR member_name { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); } function_call_parameter_list @@ -1094,7 +1094,7 @@ callable_variable: variable: callable_variable { $$ = $1; } | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } - | dereferencable T_OBJECT_OPERATOR member_name_or_variable + | dereferencable T_OBJECT_OPERATOR member_name { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } ; @@ -1116,7 +1116,7 @@ new_variable: fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } | new_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } | new_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } - | new_variable T_OBJECT_OPERATOR member_name_or_variable + | new_variable T_OBJECT_OPERATOR member_name { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); } ; @@ -1125,14 +1125,10 @@ dim_offset: | expr { $$ = $1; } ; -member_name_or_variable: - member_name { $$ = $1; } - | simple_variable { fetch_simple_variable_ex(&$$, &$1, 0, ZEND_FETCH_R TSRMLS_CC); } -; - member_name: T_STRING { $$ = $1; } | '{' expr '}' { $$ = $2; } + | simple_variable { fetch_simple_variable_ex(&$$, &$1, 0, ZEND_FETCH_R TSRMLS_CC); } ; assignment_list: From e4e42df4e6fc99bc05d243978146fb0b6e5b4085 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 4 Jun 2014 17:15:16 +0200 Subject: [PATCH 32/33] Allow only simple variables with global keyword --- Zend/zend_language_parser.y | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 6eb2c4287e22d..e28949d71cdcd 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -597,15 +597,12 @@ function_call_parameter: ; global_var_list: - global_var_list ',' global_var { zend_do_fetch_global_variable(&$3, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); } - | global_var { zend_do_fetch_global_variable(&$1, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); } + global_var_list ',' global_var + | global_var ; - global_var: - T_VARIABLE { $$ = $1; } - | '$' r_variable { $$ = $2; } - | '$' '{' expr '}' { $$ = $3; } + simple_variable { zend_do_fetch_global_variable(&$1, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); } ; From c8aa51f82590d8353640a0470ed49f7a1a21fcaa Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 6 Jun 2014 17:05:14 +0200 Subject: [PATCH 33/33] Accept static member fetch in new variable (BC) --- .../globalNonSimpleVariableError.phpt | 10 +++++ Zend/tests/varSyntax/newVariable.phpt | 39 +++++++++++++++++++ Zend/zend_language_parser.y | 14 +++---- 3 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 Zend/tests/varSyntax/globalNonSimpleVariableError.phpt create mode 100644 Zend/tests/varSyntax/newVariable.phpt diff --git a/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt b/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt new file mode 100644 index 0000000000000..ed04921f89470 --- /dev/null +++ b/Zend/tests/varSyntax/globalNonSimpleVariableError.phpt @@ -0,0 +1,10 @@ +--TEST-- +Global keyword only accepts simple variables +--FILE-- +bar; + +?> +--EXPECTF-- +Parse error: syntax error, unexpected '->' (T_OBJECT_OPERATOR), expecting ',' or ';' in %s on line %d diff --git a/Zend/tests/varSyntax/newVariable.phpt b/Zend/tests/varSyntax/newVariable.phpt new file mode 100644 index 0000000000000..360f99ac36b68 --- /dev/null +++ b/Zend/tests/varSyntax/newVariable.phpt @@ -0,0 +1,39 @@ +--TEST-- +Variable as class name for new expression +--FILE-- + 'stdClass']; +$obj = (object) ['className' => 'stdClass']; + +class Test { + public static $className = 'stdClass'; +} +$test = 'Test'; +$weird = [0 => (object) ['foo' => 'Test']]; + +var_dump(new $className); +var_dump(new $array['className']); +var_dump(new $array{'className'}); +var_dump(new $obj->className); +var_dump(new Test::$className); +var_dump(new $test::$className); +var_dump(new $weird[0]->foo::$className); + +?> +--EXPECTF-- +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} +object(stdClass)#%d (0) { +} diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e28949d71cdcd..013e3ddbf0b64 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -883,13 +883,8 @@ fully_qualified_class_name: class_name_reference: - class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } - | dynamic_class_name_reference { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } -; - - -dynamic_class_name_reference: - new_variable { $$ = $1; } + class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | new_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; exit_expr: @@ -1115,6 +1110,11 @@ new_variable: | new_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } | new_variable T_OBJECT_OPERATOR member_name { zend_do_fetch_property(&$$, &$1, &$3 TSRMLS_CC); } + | class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable + { zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } + | new_variable T_PAAMAYIM_NEKUDOTAYIM simple_variable + { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); + zend_do_fetch_static_member(&$$, &$1, &$3 TSRMLS_CC); } ; dim_offset: