Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:55606 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 1048 invoked from network); 23 Sep 2011 12:06:41 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 23 Sep 2011 12:06:41 -0000 Authentication-Results: pb1.pair.com smtp.mail=dk@uw.no; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=dk@uw.no; sender-id=unknown Received-SPF: error (pb1.pair.com: domain uw.no from 193.71.32.2 cause and error) X-PHP-List-Original-Sender: dk@uw.no X-Host-Fingerprint: 193.71.32.2 mx-1.vendo.no Linux 2.4/2.6 Received: from [193.71.32.2] ([193.71.32.2:54643] helo=mx-1.vendo.no) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 63/C0-29222-F467C7E4 for ; Fri, 23 Sep 2011 08:06:40 -0400 Received: (qmail 20938 invoked from network); 23 Sep 2011 12:06:36 -0000 Received: from daniel.tbg.sysedata.no (HELO ?10.0.1.127?) (195.159.98.89) by mx-1.vendo.no with SMTP; 23 Sep 2011 12:06:36 -0000 Message-ID: <4E7C764C.3000808@uw.no> Date: Fri, 23 Sep 2011 14:06:36 +0200 User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.21) Gecko/20110831 Thunderbird/3.1.13 MIME-Version: 1.0 To: internals@lists.php.net Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Subject: [PATCH] Fix for bug #55754 From: dk@uw.no ("Daniel K.") When a built-in function is defined with ZEND_SEND_PREFER_REF, PHP will issue a strict warning if you use an assignment expression as the parameter. As an example, current() show this behaviour. current() has this arginfo defined: ZEND_BEGIN_ARG_INFO(arginfo_current, ZEND_SEND_PREFER_REF) ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg) ZEND_END_ARG_INFO() and a call like: Presents you with: PHP Strict Standards: Only variables should be passed by reference in %s on line %d I think it is wrong to warn about this, because, to me, the _PREFER_ part of ZEND_SEND_PREFER_REF, conveys that we should prefer to pass by reference, if possible, and not care otherwise. The below patch implements the not care part that was missing until now. This is done by having the lexer mark the result variable of the assignment expression as not passable by reference, and changing the function zend_do_pass_param() to ignore the marked variables when considering if a parameter could be passed by reference or not. I have run make test, before and after, with no regressions. The only test affected was the one I sent earlier to specifically test for this bug. I am, however, not sure if this is the right approach to solve the problem, in which case, I hope to at least have put one of you on the right track to the _real_ solution, and to have made you interested in fixing it properly. The patch is for php-5.3.8 Daniel K. diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c325a7e..df30d3d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2096,7 +2096,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ if (function_ptr) { if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { - if (param->op_type & (IS_VAR|IS_CV)) { + if (param->op_type & (IS_VAR|IS_CV) && param->u.EA.type != ZEND_PARSED_EXPR_NO_PASS_BY_REF) { send_by_reference = 1; if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) { /* Method call */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 15f24df..475f976 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -650,6 +650,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_PARSED_VARIABLE (1<<4) #define ZEND_PARSED_REFERENCE_VARIABLE (1<<5) #define ZEND_PARSED_NEW (1<<6) +#define ZEND_PARSED_EXPR_NO_PASS_BY_REF (1<<7) /* unset types */ diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 1753e97..666b9e2 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -578,7 +578,7 @@ non_empty_for_expr: expr_without_variable: T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } - | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } + | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); $$.u.EA.type = ZEND_PARSED_EXPR_NO_PASS_BY_REF; } | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.u.EA.type = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } | 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, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}