-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix inconsistency in true/false/null constant resolution when opcache is not used #7441
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
Why is the resolution in eval() different? |
It seems like that was a red herring - the resolution appears to be different when the constant is defined before the file is loaded, AND opcache is not used (neither opcache nor the optimizer is used for eval right now, I think?) The constant resolution code checks if there are constants in the namespace (for non-FQ false, true, null) before trying the fallback That's because opcache has a pass that assumes these non-FQ constant names should always be the literals. https://github.com/php/php-src/blob/php-8.1.0beta3/Zend/Optimizer/block_pass.c#L32-L52
<?php // test.php
namespace foo {
define('foo\true', 'test');
require_once __DIR__ . '/other.php';
} <?php // other.php
namespace foo {
var_dump(true);
} Old behavior (proposed behavior is to always result in
|
Shouldn't this be fixed by moving the zend_get_special_const() call in zend_try_ct_eval_const() first, before the lookup? |
5619251
to
b061002
Compare
That seems to work - all callers of zend_resolve_const_name immediately call zend_try_ct_eval_const. Tests of the new behavior continue to pass |
…is used Strangely, uses of eval and 'php -a' will not treat non-FQ true/false/null as magic keywords, while compiled php required from a file would do that. This may confuse people learning the language, and result in code loaded with eval() behaving differently from the same snippet in a file loaded by require. ``` Interactive shell php > define('foo\true', 'test'); php > namespace foo { var_dump(true); } string(4) "test" ``` This will make the same session instead properly emit `bool(true);` like it already would if running those statements in files. (Interactive shell internally uses the same APIs eval uses) `zend_resolve_non_class_name` is a static C function where case_sensitive is only true for global constants (and false for global functions).
b061002
to
bdd72d1
Compare
php/php-src#7441 fixes other inconsistencies in 8.1 found while discovering this.
… is not used (#7441) Strangely, uses of eval and 'php -a' (or loading a file without opcache after a namespaced constant was declared) will not treat non-FQ true/false/null as magic keywords, while compiled php required from a file would do that. This may confuse people learning the language, and result in code loaded with eval() behaving differently from the same snippet in a file loaded by require. ``` Interactive shell php > define('foo\true', 'test'); php > namespace foo { var_dump(true); } string(4) "test" ``` This will make the same session instead properly emit `bool(true);` like it already would if running those statements in files when opcache was used. (cherry picked from commit 4c48fd2)
Strangely, uses of eval and 'php -a' will not treat non-FQ true/false/null as magickeywords, while compiled php required from a file would do that.
Currently, opcache assumes that the non-FQ true/false/null constant reference is safe to convert to the literal, even though it may also be defined in the same namespace. See https://github.com/php/php-src/blob/php-8.1.0beta3/Zend/Optimizer/block_pass.c#L32-L52
This may confuse people learning the language, and result in code loaded with
eval() behaving differently from the same snippet in a file loaded by require.
This PR will make the same session instead properly emit
bool(true);
like it already would if running those statements in files. (Interactive shell internally uses the same APIs eval uses)bool(true)
). I couldn't find related bugs in a quick search on bugs.php.netzend_resolve_non_class_name is a static C function where case_sensitive is only true for global constants (and false for global functions).
This targets php 8.1 - I'm not certain if it makes sense to fix this in earlier versions as well, if anything using eval() somehow relies on this.