From: Nikita Popov Date: Sat, 12 Mar 2016 15:00:04 +0000 (+0100) Subject: Evaluate arguments of new for classes without ctor X-Git-Tag: php-7.1.0alpha1~420 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e5b139732893d2a5f6ba3ae0a0b2b5cf6dba09f;p=php Evaluate arguments of new for classes without ctor ML: http://markmail.org/message/4b3mk7jid64zvz34 --- diff --git a/Zend/tests/bug52879.phpt b/Zend/tests/bug52879.phpt index 0193be4b45..6c3232f32d 100644 --- a/Zend/tests/bug52879.phpt +++ b/Zend/tests/bug52879.phpt @@ -8,7 +8,7 @@ class MyClass { $this->myRef = $value; } } -$myGlobal=new MyClass($myGlobal); +$myGlobal=new MyClass(); $myGlobal->myRef=&$myGlobal; $myGlobal->myNonExistentProperty="ok\n"; echo $myGlobal; diff --git a/Zend/tests/new_args_without_ctor.phpt b/Zend/tests/new_args_without_ctor.phpt new file mode 100644 index 0000000000..91456890d2 --- /dev/null +++ b/Zend/tests/new_args_without_ctor.phpt @@ -0,0 +1,10 @@ +--TEST-- +Argument of new on class without constructor are evaluated +--FILE-- + +--EXPECT-- +ab diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0b871ed52a..521cd08f36 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3792,7 +3792,8 @@ void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */ zend_compile_call_common(&ctor_result, args_ast, NULL); zend_do_free(&ctor_result); - /* New jumps over ctor call if ctor does not exist */ + /* We save the position of DO_FCALL for convenience in find_live_range(). + * This info is not preserved for runtime. */ opline = &CG(active_op_array)->opcodes[opnum]; opline->op2.opline_num = get_next_op_number(CG(active_op_array)); } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index ab67a88272..4800939b5f 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -673,7 +673,6 @@ ZEND_API int pass_two(zend_op_array *op_array) case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_COALESCE: - case ZEND_NEW: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index e2ee420f89..9539b6e2ed 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5073,12 +5073,13 @@ ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMPVAR|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, JMP_ADDR, NUM) +ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, ANY, NUM) { USE_OPLINE zval *result; zend_function *constructor; zend_class_entry *ce; + zend_execute_data *call; SAVE_OPLINE(); if (OP1_TYPE == IS_CONST) { @@ -5107,21 +5108,30 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, JMP_ADDR, NUM) constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); if (constructor == NULL) { - ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); + /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next + * opcode is DO_FCALL in case EXT instructions are used. */ + if (EXPECTED(opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL)) { + ZEND_VM_NEXT_OPCODE_EX(1, 2); + } + + /* Perform a dummy function call */ + call = zend_vm_stack_push_call_frame( + ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, + opline->extended_value, NULL, NULL); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( + call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR, constructor, opline->extended_value, ce, Z_OBJ_P(result)); - call->prev_execute_data = EX(call); - EX(call) = call; Z_ADDREF_P(result); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + + call->prev_execute_data = EX(call); + EX(call) = call; + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 612feb9e9c..4eee6dd3ea 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3756,6 +3756,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_HANDLER(ZEND_OP zval *result; zend_function *constructor; zend_class_entry *ce; + zend_execute_data *call; SAVE_OPLINE(); if (IS_CONST == IS_CONST) { @@ -3784,21 +3785,30 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_HANDLER(ZEND_OP constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); if (constructor == NULL) { - ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); + /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next + * opcode is DO_FCALL in case EXT instructions are used. */ + if (EXPECTED(opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL)) { + ZEND_VM_NEXT_OPCODE_EX(1, 2); + } + + /* Perform a dummy function call */ + call = zend_vm_stack_push_call_frame( + ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, + opline->extended_value, NULL, NULL); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( + call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR, constructor, opline->extended_value, ce, Z_OBJ_P(result)); - call->prev_execute_data = EX(call); - EX(call) = call; Z_ADDREF_P(result); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + + call->prev_execute_data = EX(call); + EX(call) = call; + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -16484,6 +16494,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_HANDLER(ZEND_OPCO zval *result; zend_function *constructor; zend_class_entry *ce; + zend_execute_data *call; SAVE_OPLINE(); if (IS_VAR == IS_CONST) { @@ -16512,21 +16523,30 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_HANDLER(ZEND_OPCO constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); if (constructor == NULL) { - ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); + /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next + * opcode is DO_FCALL in case EXT instructions are used. */ + if (EXPECTED(opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL)) { + ZEND_VM_NEXT_OPCODE_EX(1, 2); + } + + /* Perform a dummy function call */ + call = zend_vm_stack_push_call_frame( + ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, + opline->extended_value, NULL, NULL); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( + call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR, constructor, opline->extended_value, ce, Z_OBJ_P(result)); - call->prev_execute_data = EX(call); - EX(call) = call; Z_ADDREF_P(result); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + + call->prev_execute_data = EX(call); + EX(call) = call; + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -26780,6 +26800,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_HANDLER(ZEND_O zval *result; zend_function *constructor; zend_class_entry *ce; + zend_execute_data *call; SAVE_OPLINE(); if (IS_UNUSED == IS_CONST) { @@ -26808,21 +26829,30 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_HANDLER(ZEND_O constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); if (constructor == NULL) { - ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); + /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next + * opcode is DO_FCALL in case EXT instructions are used. */ + if (EXPECTED(opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL)) { + ZEND_VM_NEXT_OPCODE_EX(1, 2); + } + + /* Perform a dummy function call */ + call = zend_vm_stack_push_call_frame( + ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, + opline->extended_value, NULL, NULL); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( + call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR, constructor, opline->extended_value, ce, Z_OBJ_P(result)); - call->prev_execute_data = EX(call); - EX(call) = call; Z_ADDREF_P(result); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } + + call->prev_execute_data = EX(call); + EX(call) = call; + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index ac5f0d6a32..d4c76ad265 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -277,7 +277,7 @@ static uint32_t zend_vm_opcodes_flags[184] = { 0x00001003, 0x00001001, 0x00001001, - 0x01002073, + 0x01000073, 0x01000300, 0x00004005, 0x00186703, diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 159620c617..52a440fba0 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -846,7 +846,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 12a83f0d44..74edad6361 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -182,7 +182,6 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa) case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: @@ -250,7 +249,6 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa) case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c index aa04f6bc20..3ebbdad8cf 100644 --- a/ext/opcache/Optimizer/nop_removal.c +++ b/ext/opcache/Optimizer/nop_removal.c @@ -80,7 +80,6 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: @@ -123,7 +122,6 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index 5809d247ec..ae31504f4c 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -643,7 +643,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_FE_RESET_RW: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: - case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index f0127d5ed0..69a77f3b71 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -363,7 +363,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes); BB_START(i + 1); break; @@ -496,7 +495,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - case ZEND_NEW: record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]); record_successor(blocks, j, 1, j + 1); break; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index dc4cb5f747..2fe5b61384 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -404,7 +404,6 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_COALESCE: - case ZEND_NEW: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_ASSERT_CHECK: @@ -982,7 +981,6 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_COALESCE: - case ZEND_NEW: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_ASSERT_CHECK: diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 48fefd8918..aa3b8e82f3 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -541,7 +541,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_COALESCE: - case ZEND_NEW: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_ASSERT_CHECK: diff --git a/sapi/phpdbg/tests/print_001.phpt b/sapi/phpdbg/tests/print_001.phpt index a4f300572a..1f7a5ac0b9 100644 --- a/sapi/phpdbg/tests/print_001.phpt +++ b/sapi/phpdbg/tests/print_001.phpt @@ -34,7 +34,7 @@ prompt> [Context %s (11 ops)] L1-19 {main}() %s - %s + 11 ops L4 #0 NOP L14 #1 NOP - L18 #2 NEW "Foo\\Bar" J4 @1 + L18 #2 NEW "Foo\\Bar" @1 L18 #3 DO_FCALL L18 #4 INIT_METHOD_CALL @1 "Foo" L18 #5 SEND_VAL_EX "test" 1