mirror of
https://github.com/php/php-src.git
synced 2024-11-27 20:03:40 +08:00
- Allow passing references which are returned from functions and new
- statements to be passed by reference.
This commit is contained in:
parent
aa11144649
commit
8d9082563a
@ -916,6 +916,7 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC)
|
||||
unsigned char *arg_types;
|
||||
int original_op=op;
|
||||
zend_function **function_ptr_ptr, *function_ptr;
|
||||
int send_by_reference;
|
||||
|
||||
|
||||
zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
|
||||
@ -939,20 +940,13 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC)
|
||||
arg_types = NULL;
|
||||
}
|
||||
|
||||
if (op==ZEND_SEND_VAL) {
|
||||
switch (param->op_type) {
|
||||
case IS_CONST: /* constants behave like variables when passed to functions,
|
||||
* as far as reference counting is concerned. Treat them
|
||||
* as if they were variables here.
|
||||
*/
|
||||
break;
|
||||
case IS_VAR:
|
||||
op = ZEND_SEND_VAR_NO_REF;
|
||||
break;
|
||||
}
|
||||
send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(offset, 1, arg_types)?ZEND_ARG_SEND_BY_REF:0;
|
||||
|
||||
if (op == ZEND_SEND_VAL && param->op_type == IS_VAR) {
|
||||
op = ZEND_SEND_VAR_NO_REF;
|
||||
}
|
||||
if (op!=ZEND_SEND_VAR_NO_REF
|
||||
&& ARG_SHOULD_BE_SENT_BY_REF(offset, 1, arg_types)) {
|
||||
|
||||
if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference == ZEND_ARG_SEND_BY_REF) {
|
||||
/* change to passing by reference */
|
||||
switch (param->op_type) {
|
||||
case IS_VAR:
|
||||
@ -964,9 +958,11 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC)
|
||||
}
|
||||
}
|
||||
|
||||
if (original_op==ZEND_SEND_VAR) {
|
||||
if (original_op == ZEND_SEND_VAR) {
|
||||
switch(op) {
|
||||
case ZEND_SEND_VAR_NO_REF:
|
||||
zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
|
||||
break;
|
||||
case ZEND_SEND_VAR:
|
||||
if (function_ptr) {
|
||||
zend_do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
|
||||
@ -981,10 +977,19 @@ void zend_do_pass_param(znode *param, int op, int offset CLS_DC)
|
||||
}
|
||||
|
||||
opline = get_next_op(CG(active_op_array) CLS_CC);
|
||||
if (function_ptr) {
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
|
||||
if (op == ZEND_SEND_VAR_NO_REF) {
|
||||
if (function_ptr) {
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference;
|
||||
} else {
|
||||
opline->extended_value = 0;
|
||||
}
|
||||
} else {
|
||||
opline->extended_value = ZEND_DO_FCALL_BY_NAME;
|
||||
if (function_ptr) {
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
} else {
|
||||
opline->extended_value = ZEND_DO_FCALL_BY_NAME;
|
||||
}
|
||||
}
|
||||
opline->opcode = op;
|
||||
opline->op1 = *param;
|
||||
|
@ -597,6 +597,8 @@ int zendlex(znode *zendlval CLS_DC);
|
||||
#define ZEND_MEMBER_FUNC_CALL 1<<0
|
||||
#define ZEND_CTOR_CALL 1<<1
|
||||
|
||||
#define ZEND_ARG_SEND_BY_REF (1<<0)
|
||||
#define ZEND_ARG_COMPILE_TIME_BOUND (1<<1)
|
||||
|
||||
#define AI_USE_PTR(ai) \
|
||||
if ((ai).ptr_ptr) { \
|
||||
|
@ -1656,37 +1656,55 @@ do_fcall_common:
|
||||
zend_ptr_stack_push(&EG(argument_stack), valptr);
|
||||
}
|
||||
NEXT_OPCODE();
|
||||
case ZEND_SEND_VAR:
|
||||
case ZEND_SEND_VAR_NO_REF:
|
||||
if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
|
||||
&& ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) {
|
||||
if (opline->opcode==ZEND_SEND_VAR_NO_REF) {
|
||||
zend_error(E_ERROR, "Only variables can be passed by reference");
|
||||
if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */
|
||||
if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) {
|
||||
goto send_by_var;
|
||||
}
|
||||
goto send_by_ref;
|
||||
} else if (!ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) {
|
||||
goto send_by_var;
|
||||
}
|
||||
{
|
||||
zval *varptr;
|
||||
varptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
|
||||
|
||||
if (varptr == &EG(uninitialized_zval)) {
|
||||
ALLOC_ZVAL(varptr);
|
||||
INIT_ZVAL(*varptr);
|
||||
varptr->refcount = 0;
|
||||
} else if (PZVAL_IS_REF(varptr)) {
|
||||
zval *original_var = varptr;
|
||||
|
||||
ALLOC_ZVAL(varptr);
|
||||
*varptr = *original_var;
|
||||
varptr->is_ref = 0;
|
||||
varptr->refcount = 0;
|
||||
zval_copy_ctor(varptr);
|
||||
if (varptr != &EG(uninitialized_zval) && (PZVAL_IS_REF(varptr) || varptr->refcount == 1)) {
|
||||
varptr->is_ref = 1;
|
||||
varptr->refcount++;
|
||||
zend_ptr_stack_push(&EG(argument_stack), varptr);
|
||||
NEXT_OPCODE();
|
||||
}
|
||||
varptr->refcount++;
|
||||
zend_ptr_stack_push(&EG(argument_stack), varptr);
|
||||
FREE_OP(&opline->op1, EG(free_op1)); /* for string offsets */
|
||||
zend_error(E_ERROR, "Only variables can be passed by reference");
|
||||
}
|
||||
NEXT_OPCODE();
|
||||
case ZEND_SEND_VAR:
|
||||
if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME)
|
||||
&& ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num, fbc, fbc->common.arg_types)) {
|
||||
goto send_by_ref;
|
||||
}
|
||||
send_by_var:
|
||||
{
|
||||
zval *varptr;
|
||||
varptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
|
||||
|
||||
if (varptr == &EG(uninitialized_zval)) {
|
||||
ALLOC_ZVAL(varptr);
|
||||
INIT_ZVAL(*varptr);
|
||||
varptr->refcount = 0;
|
||||
} else if (PZVAL_IS_REF(varptr)) {
|
||||
zval *original_var = varptr;
|
||||
|
||||
ALLOC_ZVAL(varptr);
|
||||
*varptr = *original_var;
|
||||
varptr->is_ref = 0;
|
||||
varptr->refcount = 0;
|
||||
zval_copy_ctor(varptr);
|
||||
}
|
||||
varptr->refcount++;
|
||||
zend_ptr_stack_push(&EG(argument_stack), varptr);
|
||||
FREE_OP(&opline->op1, EG(free_op1)); /* for string offsets */
|
||||
}
|
||||
NEXT_OPCODE();
|
||||
send_by_ref:
|
||||
case ZEND_SEND_REF: {
|
||||
zval **varptr_ptr;
|
||||
|
Loading…
Reference in New Issue
Block a user