]> granicus.if.org Git - php/commitdiff
- Implement return by reference:
authorZeev Suraski <zeev@php.net>
Wed, 15 Dec 1999 20:15:32 +0000 (20:15 +0000)
committerZeev Suraski <zeev@php.net>
Wed, 15 Dec 1999 20:15:32 +0000 (20:15 +0000)
  - In function declaration instead of the return statement
  - In the assignment phase
- Implement ability to turn off support for call-time pass by reference

Zend/zend-parser.y
Zend/zend.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_opcode.c

index 1a8f3e6fdbd86e2609e674533f8141a5a12d1ddc..1b543abf2a4c92361ed685aaa7e222ef42938eb1 100644 (file)
@@ -180,7 +180,8 @@ statement:
        |       T_CONTINUE ';'          { do_brk_cont(ZEND_CONT, NULL CLS_CC); }
        |       T_CONTINUE expr ';'     { do_brk_cont(ZEND_CONT, &$2 CLS_CC); }
        |       T_RETURN ';'                    { do_return(NULL CLS_CC); }
-       |       T_RETURN expr ';'               { do_return(&$2 CLS_CC); }
+       |       T_RETURN expr_without_variable ';'              { do_return(&$2 CLS_CC); }
+       |       T_RETURN cvar ';'               { do_return(&$2 CLS_CC); }
        |       T_GLOBAL global_var_list
        |       T_STATIC static_var_list
        |       T_ECHO echo_expr_list ';'
@@ -201,9 +202,9 @@ use_filename:
 
 
 declaration_statement:
-               T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); }
+               T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { do_begin_function_declaration(&$1, &$4, 0, $3.op_type CLS_CC); }
                        '(' parameter_list ')' '{' inner_statement_list '}' { do_end_function_declaration(&$1 CLS_CC); }
-       |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING  { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); }
+       |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING  { do_begin_function_declaration(&$1, &$4, 0, $3.op_type CLS_CC); }
                        parameter_list '(' inner_statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); }
        |       T_CLASS T_STRING { do_begin_class_declaration(&$2, NULL CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); }
        |       T_CLASS T_STRING T_EXTENDS T_STRING { do_begin_class_declaration(&$2, &$4 CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); }
@@ -347,13 +348,16 @@ class_statement_list:
 
 class_statement:
                T_VAR class_variable_decleration ';'
-       |       T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 1 CLS_CC); } '(' 
+       |       T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { do_begin_function_declaration(&$1, &$4, 1, $3.op_type CLS_CC); } '(' 
                        parameter_list ')' '{' inner_statement_list '}' { do_end_function_declaration(&$1 CLS_CC); }
-       |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 1 CLS_CC); }
+       |       T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { do_begin_function_declaration(&$1, &$4, 1, $3.op_type CLS_CC); }
                        parameter_list '(' inner_statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); }
 
 ;
 
+is_reference:
+               /* empty */ { $$.op_type = ZEND_RETURN_VAL; }
+       |       '&'                     { $$.op_type = ZEND_RETURN_REF; }
 
 class_variable_decleration:
                class_variable_decleration ',' T_VARIABLE { do_declare_property(&$3, NULL CLS_CC); }
@@ -384,6 +388,7 @@ expr_without_variable:
                T_LIST '(' { do_list_init(CLS_C); } assignment_list ')' '=' expr { do_list_end(&$$, &$7 CLS_CC); }
        |       cvar '=' expr           { do_end_variable_parse(BP_VAR_W, 0 CLS_CC); do_assign(&$$, &$1, &$3 CLS_CC); }
        |       cvar '=' '&' w_cvar     { do_end_variable_parse(BP_VAR_W, 0 CLS_CC); do_assign_ref(&$$, &$1, &$4 CLS_CC); }
+       |       cvar '=' '&' function_call { do_end_variable_parse(BP_VAR_W, 0 CLS_CC); do_assign_ref(&$$, &$1, &$4 CLS_CC); }
        |       T_NEW class_name { do_extended_fcall_begin(CLS_C); do_begin_new_object(&$1, &$2 CLS_CC); } ctor_arguments { do_end_new_object(&$$, &$2, &$1, &$4 CLS_CC); do_extended_fcall_end(CLS_C);}
        |       cvar T_PLUS_EQUAL expr  { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 CLS_CC); }
        |       cvar T_MINUS_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 CLS_CC); }
@@ -431,15 +436,7 @@ expr_without_variable:
        |       expr '?' { do_begin_qm_op(&$1, &$2 CLS_CC); }
                expr ':' { do_qm_true(&$4, &$2, &$5 CLS_CC); }
                expr     { do_qm_false(&$$, &$7, &$2, &$5 CLS_CC); }
-       |       T_STRING        '(' { do_extended_fcall_begin(CLS_C); $2.u.opline_num = do_begin_function_call(&$1 CLS_CC); }
-                               function_call_parameter_list
-                               ')' { do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num CLS_CC); do_extended_fcall_end(CLS_C); }
-       |       r_cvar '(' { do_extended_fcall_begin(CLS_C); do_begin_dynamic_function_call(&$1 CLS_CC); } 
-                               function_call_parameter_list 
-                               ')' { do_end_function_call(&$1, &$$, &$4, 0, 1 CLS_CC); do_extended_fcall_end(CLS_C);}
-       |       T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { do_extended_fcall_begin(CLS_C); do_begin_class_member_function_call(&$1, &$3 CLS_CC); } 
-                                                                                       function_call_parameter_list 
-                                                                                       ')' { do_end_function_call(&$3, &$$, &$6, 1, 1 CLS_CC); do_extended_fcall_end(CLS_C);}
+       |       function_call { $$ = $1; }
        |       internal_functions_in_yacc { $$ = $1; }
        |       T_INT_CAST expr                 { do_cast(&$$, &$2, IS_LONG CLS_CC); }
        |       T_DOUBLE_CAST expr      { do_cast(&$$, &$2, IS_DOUBLE CLS_CC); }
@@ -456,6 +453,19 @@ expr_without_variable:
 ;
 
 
+function_call:
+               T_STRING        '(' { do_extended_fcall_begin(CLS_C); $2.u.opline_num = do_begin_function_call(&$1 CLS_CC); }
+                               function_call_parameter_list
+                               ')' { do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num CLS_CC); do_extended_fcall_end(CLS_C); }
+       |       r_cvar '(' { do_extended_fcall_begin(CLS_C); do_begin_dynamic_function_call(&$1 CLS_CC); } 
+                               function_call_parameter_list 
+                               ')' { do_end_function_call(&$1, &$$, &$4, 0, 1 CLS_CC); do_extended_fcall_end(CLS_C);}
+       |       T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { do_extended_fcall_begin(CLS_C); do_begin_class_member_function_call(&$1, &$3 CLS_CC); } 
+                                                                                       function_call_parameter_list 
+                                                                                       ')' { do_end_function_call(&$3, &$$, &$6, 1, 1 CLS_CC); do_extended_fcall_end(CLS_C);}
+;
+
+
 exit_expr:
                /* empty */             { $$.op_type = IS_UNUSED; }     
        |       '(' ')'                 { $$.op_type = IS_UNUSED; }     
index 212997035295a116642ca81634311f932b5274ce..0ef98ee46aa2f67ee217e136866af60d8f2983b3 100644 (file)
@@ -187,8 +187,9 @@ typedef struct _zend_utility_functions {
 
                
 typedef struct _zend_utility_values {
-       unsigned char short_tags;
-       unsigned char asp_tags;
+       zend_bool short_tags;
+       zend_bool asp_tags;
+       zend_bool allow_call_time_pass_reference;
        char *import_use_extension;
        uint import_use_extension_length;
 } zend_utility_values;
index b56bd50f139aee5c8cf8d9665d90133820a20762..879e67640624ed4a058fd792708dc4b1b058836f 100644 (file)
@@ -98,6 +98,7 @@ void init_compiler(CLS_D ELS_DC)
        zend_llist_init(&CG(filenames_list), sizeof(char *), free_filename, 0);
        CG(short_tags) = ZEND_UV(short_tags);
        CG(asp_tags) = ZEND_UV(asp_tags);
+       CG(allow_call_time_pass_reference) = ZEND_UV(allow_call_time_pass_reference);
        CG(handle_op_arrays) = 1;
        zend_hash_apply(&module_registry, (int (*)(void *)) module_registry_request_startup);
        init_resource_list(ELS_C);
@@ -667,7 +668,7 @@ void do_free(znode *op1 CLS_DC)
 }
 
 
-void do_begin_function_declaration(znode *function_token, znode *function_name, int is_method CLS_DC)
+void do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference  CLS_DC)
 {
        zend_op_array op_array;
        char *name = function_name->u.constant.value.str.val;
@@ -678,8 +679,10 @@ void do_begin_function_declaration(znode *function_token, znode *function_name,
        zend_str_tolower(name, name_len);
 
        init_op_array(&op_array, INITIAL_OP_ARRAY_SIZE);
+
        op_array.function_name = name;
        op_array.arg_types = NULL;
+       op_array.return_reference = return_reference;
 
        if (is_method) {
                zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
@@ -839,7 +842,7 @@ void do_end_function_call(znode *function_name, znode *result, znode *argument_l
        }
        opline->op1 = *function_name;
        opline->result.u.var = get_temporary_variable(CG(active_op_array));
-       opline->result.op_type = IS_TMP_VAR;
+       opline->result.op_type = IS_VAR;
        *result = opline->result;
        SET_UNUSED(opline->op2);
        opline->op2.u.constant.value.lval = is_method;
@@ -855,8 +858,22 @@ void do_pass_param(znode *param, int op, int offset CLS_DC)
        int original_op=op;
        zend_function **function_ptr_ptr, *function_ptr;
 
+                                               
        zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
        function_ptr = *function_ptr_ptr;
+
+       if (original_op==ZEND_SEND_REF
+               && !CG(allow_call_time_pass_reference)) {
+               zend_error(E_COMPILE_WARNING,
+                                       "Call-time pass-by-reference has been deprecated - argument passed by value;  "
+                                       "If you would like to pass it by reference, modify the declaration of %s().  "
+                                       "If you would like to enable call-time pass-by-reference, you can set"
+                                       "allow_call_time_pass_reference to true in your INI file.  "
+                                       "However, future versions may not support this any longer.",
+                                       (function_ptr?function_ptr->common.function_name:"[runtime function name]"),
+                                       offset+1);
+       }
+
        if (function_ptr) {
                arg_types = function_ptr->common.arg_types;
        } else {
@@ -952,6 +969,13 @@ void do_return(znode *expr CLS_DC)
 {
        zend_op *opline;
        
+       if (expr->op_type==IS_VAR) {
+               if (CG(active_op_array)->return_reference) {
+                       do_end_variable_parse(BP_VAR_W, 0 CLS_CC);
+               } else {
+                       do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
+               }
+       }
 #ifdef ZTS
        zend_stack_apply_with_argument(&CG(switch_cond_stack), (int (*)(void *element, void *)) generate_free_switch_expr, ZEND_STACK_APPLY_TOPDOWN CLS_CC);
        zend_stack_apply_with_argument(&CG(foreach_copy_stack), (int (*)(void *element, void *)) generate_free_foreach_copy, ZEND_STACK_APPLY_TOPDOWN CLS_CC);
@@ -963,6 +987,7 @@ void do_return(znode *expr CLS_DC)
        opline = get_next_op(CG(active_op_array) CLS_CC);
 
        opline->opcode = ZEND_RETURN;
+       
        if (expr) {
                opline->op1 = *expr;
        } else {
index b76d107ba68979d7681416567d1497640e8a14f9..a026b2c4b0f3206cc8bbdddc9c071b1e00d2fbb8 100644 (file)
@@ -115,6 +115,7 @@ struct _zend_op_array {
        int last_executed_op_number;
        int backpatch_count;
 #endif
+       zend_bool return_reference;
 
        void *reserved[ZEND_MAX_RESERVED_RESOURCES];
 };
@@ -260,7 +261,7 @@ void do_add_char(znode *result, znode *op1, znode *op2 CLS_DC);
 void do_add_string(znode *result, znode *op1, znode *op2 CLS_DC);
 void do_add_variable(znode *result, znode *op1, znode *op2 CLS_DC);
 
-void do_begin_function_declaration(znode *function_token, znode *function_name, int is_method CLS_DC);
+void do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference CLS_DC);
 void do_end_function_declaration(znode *function_token CLS_DC);
 void do_receive_arg(int op, znode *var, znode *offset, znode *initialization, unsigned char pass_type CLS_DC);
 int do_begin_function_call(znode *function_name CLS_DC);
@@ -573,21 +574,24 @@ int zendlex(znode *zendlval CLS_DC);
 #define PZVAL_IS_REF(z)                ((z)->is_ref)
 
 #define PZVAL_LOCK(z)  ((z)->refcount++)
-#define PZVAL_UNLOCK(z)        { ((z)->refcount--);                                                    \
-                                                       if (!(z)->refcount) {                                           \
-                                                               EG(garbage)[EG(garbage_ptr)++] = (z);   \
-                                                               if (EG(garbage_ptr) == 4) {                             \
-                                                                       zval_dtor(EG(garbage)[0]);                      \
-                                                                       efree(EG(garbage)[0]);                          \
-                                                                       zval_dtor(EG(garbage)[1]);                      \
-                                                                       efree(EG(garbage)[1]);                          \
-                                                                       EG(garbage)[0] = EG(garbage)[2];        \
-                                                                       EG(garbage)[1] = EG(garbage)[3];        \
-                                                                       EG(garbage_ptr) -= 2;                           \
-                                                               }                                                                               \
-                                                       }                                                                                       \
+#define PZVAL_UNLOCK(z)        { ((z)->refcount--);                                                            \
+                                                       if (!(z)->refcount && !EG(suspend_garbage)) {   \
+                                                               EG(garbage)[EG(garbage_ptr)++] = (z);           \
+                                                               if (EG(garbage_ptr) == 4) {                                     \
+                                                                       zval_dtor(EG(garbage)[0]);                              \
+                                                                       efree(EG(garbage)[0]);                                  \
+                                                                       zval_dtor(EG(garbage)[1]);                              \
+                                                                       efree(EG(garbage)[1]);                                  \
+                                                                       EG(garbage)[0] = EG(garbage)[2];                \
+                                                                       EG(garbage)[1] = EG(garbage)[3];                \
+                                                                       EG(garbage_ptr) -= 2;                                   \
+                                                               }                                                                                       \
+                                                       }                                                                                               \
                                                }
 
+#define SUSPEND_GARBAGE() (EG(suspend_garbage)=1)
+#define RESUME_GARBAGE() (EG(suspend_garbage)=0)
+
 #define SELECTIVE_PZVAL_LOCK(pzv, pzn)         if (!((pzn)->u.EA.type & EXT_TYPE_UNUSED)) { PZVAL_LOCK(pzv); }
 
 
@@ -609,4 +613,7 @@ int zendlex(znode *zendlval CLS_DC);
                )                                                                                                                       \
        )
 
+#define ZEND_RETURN_VAL 0
+#define ZEND_RETURN_REF 1
+
 #endif /* _COMPILE_H */
index b1ebfb0b86c661bafdf5320e0e583652a1d5ea9c..78982c85c4e7e0838240eb255606a981b39e457f 100644 (file)
@@ -378,7 +378,7 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2
                                        */
                                        /* break missing intentionally */
                                case IS_CONST:
-                                       if (PZVAL_IS_REF(value)) {
+                                       if (PZVAL_IS_REF(value) && value->refcount > 0) {
                                                variable_ptr = *variable_ptr_ptr = (zval *) emalloc(sizeof(zval));
                                                *variable_ptr = *value;
                                                zval_copy_ctor(variable_ptr);
@@ -1218,14 +1218,19 @@ binary_assign_op_addr: {
                                AI_USE_PTR(Ts[opline->result.u.var].var);
                                break;
                        case ZEND_ASSIGN: {
-                                       zval *value = get_zval_ptr(&opline->op2, Ts, &EG(free_op2), BP_VAR_R);
+                                       zval *value;
+                                       SUSPEND_GARBAGE();
+                                       value = get_zval_ptr(&opline->op2, Ts, &EG(free_op2), BP_VAR_R);
+                                       RESUME_GARBAGE();
 
                                        zend_assign_to_variable(&opline->result, &opline->op1, &opline->op2, value, (EG(free_op2)?IS_TMP_VAR:opline->op2.op_type), Ts ELS_CC);
                                        /* zend_assign_to_variable() always takes care of op2, never free it! */
                                }
                                break;
                        case ZEND_ASSIGN_REF:
+                               SUSPEND_GARBAGE();
                                zend_assign_to_variable_reference(&opline->result, get_zval_ptr_ptr(&opline->op1, Ts, BP_VAR_W), get_zval_ptr_ptr(&opline->op2, Ts, BP_VAR_W), Ts ELS_CC);
+                               RESUME_GARBAGE();
                                break;
                        case ZEND_JMP:
 #if DEBUG_ZEND>=2
@@ -1467,16 +1472,23 @@ overloaded_function_call_cont:
                                }
 do_fcall_common:
                                {
-                                       zval *original_return_value;
+                                       zval **original_return_value;
                                        int return_value_not_used = (opline->result.u.EA.type & EXT_TYPE_UNUSED);
 
                                        zend_ptr_stack_push(&EG(argument_stack), (void *) opline->extended_value);
-                                       var_uninit(&Ts[opline->result.u.var].tmp_var);
+                                       Ts[opline->result.u.var].var.ptr = (zval *)emalloc(sizeof(zval));
+                                       Ts[opline->result.u.var].var.ptr_ptr = &Ts[opline->result.u.var].var.ptr;
+                                       var_uninit(Ts[opline->result.u.var].var.ptr);
+                                       Ts[opline->result.u.var].var.ptr->is_ref = 0;
+                                       Ts[opline->result.u.var].var.ptr->refcount = 1;
+
                                        if (function_state.function->type==ZEND_INTERNAL_FUNCTION) {
-                                               ((zend_internal_function *) function_state.function)->handler(opline->extended_value, &Ts[opline->result.u.var].tmp_var, &EG(regular_list), &EG(persistent_list), object.ptr, !return_value_not_used);
+                                               ((zend_internal_function *) function_state.function)->handler(opline->extended_value, Ts[opline->result.u.var].var.ptr, &EG(regular_list), &EG(persistent_list), object.ptr, !return_value_not_used);
                                                if (object.ptr) {
                                                        object.ptr->refcount--;
                                                }
+                                               Ts[opline->result.u.var].var.ptr->is_ref = 0;
+                                               Ts[opline->result.u.var].var.ptr->refcount = 1;
                                        } else if (function_state.function->type==ZEND_USER_FUNCTION) {
                                                HashTable *calling_symbol_table;
 
@@ -1502,13 +1514,13 @@ do_fcall_common:
                                                        *this_ptr = object.ptr;
                                                        object.ptr = NULL;
                                                }
-                                               original_return_value = EG(return_value);
-                                               EG(return_value) = &Ts[opline->result.u.var].tmp_var;
+                                               original_return_value = EG(return_value_ptr_ptr);
+                                               EG(return_value_ptr_ptr) = Ts[opline->result.u.var].var.ptr_ptr;
                                                EG(active_op_array) = (zend_op_array *) function_state.function;
                                                zend_execute(EG(active_op_array) ELS_CC);
                                                EG(opline_ptr) = &opline;
                                                EG(active_op_array) = op_array;
-                                               EG(return_value)=original_return_value;
+                                               EG(return_value_ptr_ptr)=original_return_value;
                                                if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
                                                        zend_hash_destroy(function_state.function_symbol_table);
                                                        efree(function_state.function_symbol_table);
@@ -1518,11 +1530,11 @@ do_fcall_common:
                                                }
                                                EG(active_symbol_table) = calling_symbol_table;
                                        } else { /* ZEND_OVERLOADED_FUNCTION */
-                                               call_overloaded_function(opline->extended_value, &Ts[opline->result.u.var].tmp_var, &EG(regular_list), &EG(persistent_list) ELS_CC);
+                                               call_overloaded_function(opline->extended_value, Ts[opline->result.u.var].var.ptr, &EG(regular_list), &EG(persistent_list) ELS_CC);
                                                efree(fbc);
                                        }
                                        if (return_value_not_used) {
-                                                       zendi_zval_dtor(Ts[opline->result.u.var].tmp_var);
+                                               zval_ptr_dtor(&Ts[opline->result.u.var].var.ptr);
                                        }
                                        object.ptr = zend_ptr_stack_pop(&EG(arg_types_stack));
                                        if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
@@ -1534,11 +1546,41 @@ do_fcall_common:
                                }
                                break;
                        case ZEND_RETURN: {
-                                       zval *retval = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       zval *retval_ptr;
+                                       zval **retval_ptr_ptr;
                                        
-                                       *EG(return_value) = *retval;
-                                       if (!EG(free_op1)) {
-                                               zendi_zval_copy_ctor(*EG(return_value));
+                                       if ((EG(active_op_array)->return_reference == ZEND_RETURN_REF) &&
+                                               (opline->op1.op_type != IS_CONST) && 
+                                               (opline->op1.op_type != IS_TMP_VAR)) {
+                                               
+                                               retval_ptr_ptr = get_zval_ptr_ptr(&opline->op1, Ts, BP_VAR_W);
+
+                                               if (!PZVAL_IS_REF(*retval_ptr_ptr)) {
+                                                       SEPARATE_ZVAL(retval_ptr_ptr);
+                                                       (*retval_ptr_ptr)->is_ref = 1;
+                                               }
+                                               (*retval_ptr_ptr)->refcount++;
+                                               efree(*EG(return_value_ptr_ptr));
+                                               (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr);
+                                       } else {
+                                               retval_ptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       
+                                               if (!EG(free_op1)) { /* Not a temp var */
+                                                       if (PZVAL_IS_REF(retval_ptr) && retval_ptr->refcount > 0) {
+                                                               **EG(return_value_ptr_ptr) = *retval_ptr;
+                                                               (*EG(return_value_ptr_ptr))->is_ref = 0;
+                                                               (*EG(return_value_ptr_ptr))->refcount = 1;
+                                                               zval_copy_ctor(*EG(return_value_ptr_ptr));
+                                                       } else {
+                                                               efree(*EG(return_value_ptr_ptr));
+                                                               *EG(return_value_ptr_ptr) = retval_ptr;
+                                                               retval_ptr->refcount++;
+                                                       }
+                                               } else {
+                                                       **EG(return_value_ptr_ptr) = *retval_ptr;
+                                                       (*EG(return_value_ptr_ptr))->refcount = 1;
+                                                       (*EG(return_value_ptr_ptr))->is_ref = 0;
+                                               }
                                        }
 #if SUPPORT_INTERACTIVE
                                        op_array->last_executed_op_number = opline-op_array->opcodes;
@@ -1566,7 +1608,10 @@ do_fcall_common:
                                                goto send_by_ref;
                                }
                                {
-                                       zval *varptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       zval *varptr;
+                                       SUSPEND_GARBAGE();
+                                       varptr = get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R);
+                                       RESUME_GARBAGE();
 
                                        if (varptr == &EG(uninitialized_zval)) {
                                                varptr = (zval *) emalloc(sizeof(zval));
@@ -1589,8 +1634,13 @@ do_fcall_common:
                                break;
 send_by_ref:
                        case ZEND_SEND_REF: {
-                                       zval **varptr_ptr = get_zval_ptr_ptr(&opline->op1, Ts, BP_VAR_W);
-                                       zval *varptr = *varptr_ptr;
+                                       zval **varptr_ptr;
+                                       zval *varptr;
+                                       SUSPEND_GARBAGE();
+                                       varptr_ptr = get_zval_ptr_ptr(&opline->op1, Ts, BP_VAR_W);
+                                       RESUME_GARBAGE();
+
+                                       varptr = *varptr_ptr;
 
                                        if (!PZVAL_IS_REF(varptr)) {
                                                /* code to break away this variable */
index 40bea673816c60e87a66036f8fd8ce60c2f63d8b..536e63f9c050f7eba89c049828fede7cbd060d93 100644 (file)
@@ -115,6 +115,7 @@ void init_executor(CLS_D ELS_DC)
        zend_llist_apply(&zend_extensions, (void (*)(void *)) zend_extension_activator);
        EG(opline_ptr) = NULL;
        EG(garbage_ptr) = 0;
+       EG(suspend_garbage) = 0;
 
        zend_hash_init(&EG(imported_files), 5, NULL, NULL, 0);
 }
index 947fc0044dd3eb1375d1e317bf41a1864317c388..f4b20ee8757a1c345e14cc7a1c7fcec3e3fe40c6 100644 (file)
@@ -90,6 +90,7 @@ struct _zend_compiler_globals {
 
        zend_bool short_tags;
        zend_bool asp_tags;
+       zend_bool allow_call_time_pass_reference;
 
        /* For extensions support */
        zend_bool extended_info;        /* generate extension information for debugger/profiler */
@@ -110,6 +111,7 @@ struct _zend_compiler_globals {
 
 struct _zend_executor_globals {
        zval *return_value;
+       zval **return_value_ptr_ptr;
 
        zval uninitialized_zval;
        zval *uninitialized_zval_ptr;
@@ -160,6 +162,7 @@ struct _zend_executor_globals {
 
        zval *garbage[4];
        int garbage_ptr;
+       zend_bool suspend_garbage;
 
        void *reserved[ZEND_MAX_RESERVED_RESOURCES];
 #if SUPPORT_INTERACTIVE
index 5aa107305ba7b957ba764a4af70756ea5292b244..53d066ac09b1a3ffd72c367d2ddfa2b9f9743f03 100644 (file)
@@ -99,6 +99,8 @@ void init_op_array(zend_op_array *op_array, int initial_ops_size)
 
        op_array->uses_globals = 0;
 
+       op_array->return_reference = 0;
+
        zend_llist_apply_with_argument(&zend_extensions, (void (*)(void *, void *)) zend_extension_op_array_ctor_handler, op_array);
 }