Skip to content

Make "{$g{'h'}}" emit fatal error and no incorrect deprecation notice in 8.2 #9264

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

Merged

Conversation

TysonAndre
Copy link
Contributor

@TysonAndre TysonAndre commented Aug 7, 2022

The ast node flag constants ZEND_DIM_ALTERNATIVE_SYNTAX and
ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR node have identical values (1<<1),
causing a deprecation notice to be incorrectly emitted before the fatal error
for unsupported syntax.

To fix this, check if the kind is the expected kind of AST_VAR/AST_DIM associated with the flag being checked for. The node kind in encapsulated strings can also be PROP/METHOD_CALL, which currently have no flags, but explicitly check the kind to make the deprecation notice logic easier to reason about and less likely to break if flags are added.

  • Previously, the test would incorrectly also emit Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead before the fatal error

Fixes GH-9263

Followup to https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation in php 8.2

@iluuu1994
Copy link
Member

Thank you @TysonAndre! I missed this conflict.

@TysonAndre
Copy link
Contributor Author

TysonAndre commented Aug 7, 2022

To make a note of something I was confused about:

The check when compiling the encapsulated variable list isn't checking the node kind (which can either be AST_DIM or AST_VAR or AST_ZVAL)

The node kinds for AST_DIM were previously not overlapping (ZEND_ENCAPS_VAR_DOLLAR_CURLY != ZEND_DIM_ALTERNATIVE_SYNTAX) - the actual issue causing the deprecation notice is that nothing bothered to distinguish between ast_node->kind AST_VAR and AST_DIM (and any other/future flag types) when checking if the deprecation notice should be emitted.

Still, having these bit flag values be entirely separate ranges seems like the most convenient

Zend/zend_language_parser.y
1507:                   { $$ = zend_ast_create_ex(ZEND_AST_VAR, ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR, $2); }
1509:                   { $$ = zend_ast_create_ex(ZEND_AST_VAR, ZEND_ENCAPS_VAR_DOLLAR_CURLY, $2); }
1511:                   { $$ = zend_ast_create_ex(ZEND_AST_DIM, ZEND_ENCAPS_VAR_DOLLAR_CURLY,

Zend/zend_compile.c
9626:           if (encaps_var->attr & (ZEND_ENCAPS_VAR_DOLLAR_CURLY|ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR)) {
9627:                   if (encaps_var->attr & ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR) {
// Zend/zend_compile.c

	for (i = 0; i < list->children; i++) {
		zend_ast *encaps_var = list->child[i];
		if (encaps_var->attr & (ZEND_ENCAPS_VAR_DOLLAR_CURLY|ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR)) {
			if (encaps_var->attr & ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR) {
				zend_error(E_DEPRECATED, "Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead");
			} else {
				zend_error(E_DEPRECATED, "Using ${var} in strings is deprecated, use {$var} instead");
			}
		}

Copy link
Member

@iluuu1994 iluuu1994 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the actual issue causing the deprecation notice is that nothing bothered to distinguish between ast_node->kind AST_VAR and AST_DIM (and any other/future flag types) when checking if the deprecation notice should be emitted.

In that case we should probably add this check too. Changing the flags might even be more confusing then than anything, as it makes it look like they can clash when they really can't. At least looking at the parser, it doesn't look like ZEND_AST_VAR have any other flags.

if (encaps_var->kind == ZEND_AST_VAR && (encaps_var->attr & (ZEND_ENCAPS_VAR_DOLLAR_CURLY|ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR))) {

@TysonAndre
Copy link
Contributor Author

I had to double check, but it looks like it's safe to keep the values of the constants as is and just change the deprecation notice emitting logic to check kinds

There's code related to nodes of type ZEND_DIM_IS (for isset handling) where it's set after the parse phase in zend_compile.c but that overlap won't matter.

As far as I can tell, the overlap won't matter, because

  1. values of variables are never known when compiling ast nodes to a constant value
  2. when the flags of AST_DIM are set to ZEND_ENCAPS_VAR_DOLLAR_CURLY, the left hand side is always an AST_VAR
// Zend/zend_language_parser.y
	|	T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
			{ $$ = zend_ast_create_ex(ZEND_AST_DIM, ZEND_ENCAPS_VAR_DOLLAR_CURLY,
			      zend_ast_create(ZEND_AST_VAR, $2), $4); }
Zend/zend_ast.c
762:                    zend_fetch_dimension_const(result, &op1, &op2, (ast->attr & ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);

Zend/zend_compile.c
10441:                          ast->child[0]->attr |= ZEND_DIM_IS;
10501:                  if ((ast->attr & ZEND_DIM_IS) && ast->child[0]->kind == ZEND_AST_DIM) {
10502:                          ast->child[0]->attr |= ZEND_DIM_IS;

The ast node flag constants ZEND_DIM_ALTERNATIVE_SYNTAX and
ZEND_ENCAPS_VAR_DOLLAR_CURLY_VAR_VAR node have identical values (1<<1),
causing a deprecation notice to be incorrectly emitted before the fatal error
for unsupported syntax.
Only emit the deprecation notice if the ast_node kind is ZEND_AST_VAR.

Fixes phpGH-9263
@TysonAndre TysonAndre force-pushed the fix-9263-encaps-var-error-not-deprecation branch from 59f5ffc to e531959 Compare August 7, 2022 15:20
`AST_PROP`/`AST_METHOD_CALL` and nullsafe variants can also be found in
encapsulated strings - currently they have no flags but they may have flags in
the future. This also clarifies that this deprecation warning can only happen
for AST_VAR/AST_DIM nodes.
@TysonAndre TysonAndre requested a review from nikic August 7, 2022 16:00
@TysonAndre TysonAndre merged commit 6a50af2 into php:master Aug 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

PHP 8.2.0beta2 emits false positive deprecation warning before fatal error for "{$g{'h'}}";
3 participants