-
Notifications
You must be signed in to change notification settings - Fork 7.9k
call_user_func(_array): Don't abort on reference warning #2059
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Motivation: Fix fallout from e730c8f. Earlier issue (also relating to array_slice, but due to a different change) reported in https://bugs.php.net/bug.php?id=72598. |
In general I like the idea of making it consistent, it may though introduce some subtle BC breaks. Though, can't we just promote non-refs to refs inside the array instead? |
This commit implements two changes: a) zend_call_function() will treat reference zvals with refcount=1 as if they were non-reference zvals. b) zend_call_function() will allow performing calls where a reference argument is passed by-value. The usual warning is still emitted, but the call is no longer aborted. The motivation for these changes is that currently the interaction of references and call_user_func_array() is very fragile and harmless internal changes can break calls as a side-effect. The reason is that due to internal optimizations (e.g. the recent array_slice() change that breaks WordPress) reference zvals with rc=1 may not be retained in an array (which is by itself perfectly fine, because rc=1 references are not references). Currently this will cause call_user_func_array() to fail. This change tries to counteract this by a) making sure we don't treat rc=1 zvals as references and thus make the behavior independent from internal details and b) making sure we don't introduce backwards-compatibility issues by no longer aborting the function call on the warning.
a742ae6
to
b02c429
Compare
@bwoebi The problem with creating refs is that this would require accepting the array by-reference (which we don't). I think that we need to do something for 7.1 to avoid currently existing breakage, i.e. should at least do the change to only throw a warning but not abort the call. I rolled the rc=1 change into this PR to make sure the warning is shown consistently, not depending on internal details. |
We could use prefer_ref instead. Yes, it's also a small change, but probably the most useful one. As said, I fully agree it should be fixed, I just don't think your PR is the optimal solution. Bob Weinand (iPhone)
|
@bwoebi, even if we use prefer_ref, call_user_func_array() might be called with array as value (or even immutable array), and in this case, we can't promote nested values to references. So we may keep the original behavior for the first two cases and try to promote values to references for the third case, but this doesn't add consistency. For now, I think this PR is a better compromise. |
@dstogov what exactly is the issue? The function then gets called, with the parameter promoted to a reference in the copy of the array. We do not get the result - but that's the responsibility of the caller. Not every by-ref parameter is meaningful to the caller. E.g. call_user_func_array("array_pop", [[1, 2, 3]]); // returns 3, doesn't modify the array
$a = [1, 2, 3];
call_user_func_array("array_pop", [$a]); // returns 3, doesn't modify $a
$a = [1, 2, 3];
call_user_func_array("array_pop", [&$a]); // returns 3 and $a is modified
$args = [[1,2,3]];
call_user_func_array("array_pop", $args); // returns 3 and $args[0] is modified I.e. cufa() calls MAKE_REF in any case on the passed array (which will be a copy if a value has been passed), and pass RC=2 references to the function [if not yet ref]. If the value gets modified, the modified value will just be thrown away after the call. |
@nikic this PR breaks few PDO and PHAR tests: via [ext/pdo_mysql/tests/common.phpt] |
@dstogov I've created a new PR at #2088. This one only allows the call to proceed (with warning), but does not change any behavior with regard to rc=1 references. The reason is that I was not sure what to do with the PDO failure on the FETCH_CLASS test -- it does some very odd things with references, but as there's a test for it it seems better to leave it alone. |
Superseded by #2088. |
This commit implements two changes:
a) zend_call_function() will treat reference zvals with refcount=1
as if they were non-reference zvals.
b) zend_call_function() will allow performing calls where a
reference argument is passed by-value. The usual warning is
still emitted, but the call is no longer aborted.
The motivation for these changes is that currently the interaction
of references and call_user_func_array() is very fragile and
harmless internal changes can break calls as a side-effect. The
reason is that due to internal optimizations (e.g. the recent
array_slice() change that breaks WordPress) reference zvals with
rc=1 may not be retained in an array (which is by itself perfectly
fine, because rc=1 references are not references). Currently this
will cause call_user_func_array() to fail.
This change tries to counteract this by a) making sure we don't
treat rc=1 zvals as references and thus make the behavior
independent from internal details and b) making sure we don't
introduce backwards-compatibility issues by no longer aborting
the function call on the warning.