]> granicus.if.org Git - php/commitdiff
Fix behavior of return-by-reference functions. Remove erroneous warnings,
authorZeev Suraski <zeev@php.net>
Sun, 14 Dec 2003 16:09:07 +0000 (16:09 +0000)
committerZeev Suraski <zeev@php.net>
Sun, 14 Dec 2003 16:09:07 +0000 (16:09 +0000)
add E_STRICT warnings in case you return something by reference that you're
not supposed to (anything that's not a variable, or a return-value of a
function that returned by reference).

Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute.h

index d121d677d050cea106127124775163a29c67dcec..9b0cdb93a44679f751746fe914f13df6a24fdebf 100644 (file)
@@ -739,7 +739,7 @@ void zend_check_writable_variable(znode *variable)
        }
 }
 
-zend_bool zend_is_function_or_method_call(znode *variable)
+static inline zend_bool zend_is_function_or_method_call(znode *variable)
 {
        zend_uint type = variable->u.EA.type;
 
@@ -1475,10 +1475,6 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC)
                } else {
                        zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC);
                }
-#if 0
-       } else if (expr && CG(active_op_array)->return_reference) {
-               zend_error(E_COMPILE_ERROR, "Only variables may be returned by reference");
-#endif
        }
 
 #ifdef ZTS
@@ -1499,6 +1495,15 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC)
                opline->op1.op_type = IS_CONST;
                INIT_ZVAL(opline->op1.u.constant);
        }
+
+       if (do_end_vparse) {
+               if (zend_is_function_or_method_call(expr)) {
+                       opline->extended_value = ZEND_RETURNS_FUNCTION; 
+               } else {
+                       opline->extended_value = 0;
+               }
+       }
+
        SET_UNUSED(opline->op2);
 }
 
index 381b82190e67aa295bcfd10c7a3d5d1ebd92df42..67fe568c1b428db3cd030d47b74ab47aa0cb80a0 100644 (file)
@@ -790,6 +790,9 @@ int zendlex(znode *zendlval TSRMLS_DC);
 #define ZEND_RETURN_VAL 0
 #define ZEND_RETURN_REF 1
 
+
+#define ZEND_RETURNS_FUNCTION 1<<0
+
 END_EXTERN_C()
 
 #define ZEND_CLONE_FUNC_NAME           "__clone"
index 3491e76cc0412fd97e9bb1f4955bc1066a66fa2c..4c42e48344ad6816abefed1267ecfdcccb3387c6 100644 (file)
@@ -2512,6 +2512,8 @@ int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS)
                should_change_scope = 0;
        }
 
+       EX_T(EX(opline)->result.u.var).var.fcall_returned_reference = 0;
+
        if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {      
                ALLOC_ZVAL(EX_T(EX(opline)->result.u.var).var.ptr);
                INIT_ZVAL(*(EX_T(EX(opline)->result.u.var).var.ptr));
@@ -2561,6 +2563,7 @@ int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS)
                EG(active_op_array) = (zend_op_array *) EX(function_state).function;
 
                zend_execute(EG(active_op_array) TSRMLS_CC);
+               EX_T(EX(opline)->result.u.var).var.fcall_returned_reference = EG(active_op_array)->return_reference;
 
                if (return_value_used && !EX_T(EX(opline)->result.u.var).var.ptr) {
                        if (!EG(exception)) {
@@ -2685,20 +2688,28 @@ int zend_return_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
        zval *retval_ptr;
        zval **retval_ptr_ptr;
-       
-       if ((EG(active_op_array)->return_reference == ZEND_RETURN_REF) &&
-               (EX(opline)->op1.op_type != IS_CONST) && 
-               (EX(opline)->op1.op_type != IS_TMP_VAR)) {
-               
+                       
+       if (EG(active_op_array)->return_reference == ZEND_RETURN_REF) {
+               if (EX(opline)->op1.op_type == IS_CONST || EX(opline)->op1.op_type == IS_TMP_VAR) {
+                       /* Not supposed to happen, but we'll allow it */
+                       zend_error(E_STRICT, "Only variable references should be returned by reference");
+                       goto return_by_value;
+               }
+
                retval_ptr_ptr = get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), BP_VAR_W);
 
                if (!retval_ptr_ptr) {
-                       zend_error(E_ERROR, "Cannot return overloaded elements or string offsets by reference");
+                       zend_error(E_ERROR, "Cannot return string offsets by reference");
                }
 
                if (!(*retval_ptr_ptr)->is_ref
-                       && EX_T(EX(opline)->op1.u.var).var.ptr_ptr == &EX_T(EX(opline)->op1.u.var).var.ptr) {
-                       zend_error(E_ERROR, "Only variables or references can be returned by reference");
+                       /*&& EX_T(EX(opline)->op1.u.var).var.ptr_ptr == &EX_T(EX(opline)->op1.u.var).var.ptr*/) {
+                       if (EX(opline)->extended_value == ZEND_RETURNS_FUNCTION
+                               && !EX_T(EX(opline)->op1.u.var).var.fcall_returned_reference) {
+                               zend_error(E_STRICT, "Only variable references should be returned by reference");
+                               PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */
+                               goto return_by_value;
+                       }
                }
                
                SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr_ptr);
@@ -2706,6 +2717,7 @@ int zend_return_handler(ZEND_OPCODE_HANDLER_ARGS)
                
                (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr);
        } else {
+return_by_value:
                retval_ptr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
        
                if (!EG(free_op1)) { /* Not a temp var */
index ce7541f546559ad90d8b1c8e92c84eaaff79c8e2..087fcf19114f406694cb85d45a6a09cd9a9b3939 100644 (file)
@@ -36,6 +36,7 @@ typedef union _temp_variable {
                        zval *str;
                        zend_uint offset;
                } str_offset;
+               zend_bool fcall_returned_reference;
        } var;
        zend_class_entry *class_entry;
 } temp_variable;