php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72248 Optimization erroneously enforces strict types in call_user_func
Submitted: 2016-05-20 13:47 UTC Modified: 2018-08-20 16:01 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: bwoebi@php.net Assigned:
Status: Verified Package: Scripting Engine problem
PHP Version: 7.0.6 OS: Irrelevant
Private report: No CVE-ID: None
 [2016-05-20 13:47 UTC] bwoebi@php.net
Description:
------------
Due to our call_user_func() optimizations (which by the way also removes the additional internal stack frame in the stacktrace...; which ultimately causes the misbehavior), call_user_func[_array]() calls apply, when optimized, the strict_type mode of the caller, which they shouldn't.

In general, PHP functions count internally as weakly typed and this behavior shall be always the same.

Test script:
---------------
// first script (works as expected, with namespace)
<?php declare(strict_types=1); namespace a; var_dump(call_user_func("strlen", 1));'

// second script (bad behavior, without namespace)
<?php declare(strict_types=1); var_dump(call_user_func("strlen", 1));'

Expected result:
----------------
// first script
int(1)

// second script
int(1)

Actual result:
--------------
// first script
int(1)

// second script
Fatal error: Uncaught TypeError: strlen() expects parameter 1 to be string, integer given in Command line code:1
Stack trace:
#0 Command line code(1): strlen(1)
#1 {main}
  thrown in Command line code on line 1


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-20 08:41 UTC] sam at mousa dot nl
This does not only apply to PHP internal functions, this code has the same behavior:
Test scripts:

<?php declare(strict_types=1); namespace a; var_dump(
    call_user_func(function(string $test) {
        return $test;
    }, 5)
);

<?php declare(strict_types=1); var_dump(
    call_user_func(function(string $test) {
        return $test;
    }, 5)
);

However in this scenario the desired behavior is different. Since we have strict types on user code I assume we would always want an error, even in namespaces.
 [2018-08-20 14:11 UTC] cmb@php.net
-Summary: Optimization erroneously enforces strict types in call_user_func +Summary: Optimization doesn't enforce strict types in call_user_func -Status: Open +Status: Verified
 [2018-08-20 14:11 UTC] cmb@php.net
From the PHP manual[1]:

| Strict typing applies to function calls made from within the
| file with strict typing enabled, not to the functions declared
| within that file.

So the behavior of the non-namespaced code is correct, but the
namespaced code behaves erroneously.

[1] <http://php.net/manual/en/functions.arguments.php>
 [2018-08-20 15:02 UTC] requinix@php.net
-Summary: Optimization doesn't enforce strict types in call_user_func +Summary: Optimization erroneously enforces strict types in call_user_func
 [2018-08-20 15:02 UTC] requinix@php.net
> So the behavior of the non-namespaced code is correct, but the namespaced code behaves erroneously.
That's backwards. The bug is as reported.

Function calls made from within PHP do not use strict typing. call_user_func("strlen") should work as if strlen is being called from within call_user_func's stack frame and thus not use strict typing, however c_u_f used when not in a namespace is optimized into the equivalent function call - the second script compiles into a literal strlen(1) call - which is why strict_types kicked in.

Optimization or not, it should work just like a userland implementation of

<?php
// declare(strict_types=0);
function call_user_func_userland($function, ...$args) {
  return $function(...$args);
}
?>
 [2018-08-20 16:01 UTC] cmb@php.net
> That's backwards. The bug is as reported.

I stand corrected.  Thanks!
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 30 14:01:28 2024 UTC