Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ PHP NEWS
hooked subclass). (Lazizbek Ergashev)
. Fixed bug GH-25299 (Exception string code is lost after unserialize()).
(Lazizbek Ergashev, David Carlier)
. Fixed AST export of static member names that do not lex as identifiers.
(Jorg Sowa)

- Curl:
. Fixed curl_reset() retaining CURLOPT_PRIVATE after reset. (lacatoire)
Expand Down
55 changes: 55 additions & 0 deletions Zend/tests/ast/ast_export_unlexable_static_member.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
--TEST--
AST export of static member names that do not lex as identifiers
--EXTENSIONS--
zend_test
--FILE--
<?php

$code = <<<'PHP'
<?php
C::{'__halt_compiler'};
C::{'__HALT_compiler'};
$o::{'__halt_compiler'};
C::{'__halt_compiler'}();
C::{'__HALT_compiler'}();
$o::{'__halt_compiler'}();
C::{'a b'}();
C::{''}();
C::public( set );
C::protected( set );
C::private( set );
C::PUBLIC( SET );
$o::public( set );
C::{'public'}(set);
C::public();
C::static(set);
$o->__halt_compiler();
$o->public(set);
C::$__halt_compiler;
PHP;

$export = zend_test_compile_to_ast($code);
echo $export;
eval("return;\n$export");

?>
--EXPECT--
C::{'__halt_compiler'};
C::{'__HALT_compiler'};
$o::{'__halt_compiler'};
C::{'__halt_compiler'}();
C::{'__HALT_compiler'}();
$o::{'__halt_compiler'}();
C::{'a b'}();
C::{''}();
C::{'public'}(set);
C::{'protected'}(set);
C::{'private'}(set);
C::{'PUBLIC'}(SET);
$o::{'public'}(set);
C::{'public'}(set);
C::{'public'}();
C::static(set);
$o->__halt_compiler();
$o->public(set);
C::$__halt_compiler;
47 changes: 30 additions & 17 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1429,22 +1429,11 @@ static ZEND_COLD bool zend_ast_var_needs_braces(char ch)
return ch == '[' || zend_ast_valid_var_char(ch);
}

static ZEND_COLD void zend_ast_export_class_const_name(smart_str *str, zend_ast *ast, int indent)
/* T_HALT_COMPILER is the only keyword the grammar rejects as an identifier. */
static ZEND_COLD bool zend_ast_valid_identifier(const zend_string *name)
{
if (ast->kind == ZEND_AST_ZVAL) {
const zval *zv = zend_ast_get_zval(ast);

/* A bare "class" would turn the dynamic fetch into a class name fetch. */
if (Z_TYPE_P(zv) == IS_STRING
&& zend_ast_valid_var_name(Z_STRVAL_P(zv), Z_STRLEN_P(zv))
&& !zend_string_equals_ci(Z_STR_P(zv), ZSTR_KNOWN(ZEND_STR_CLASS))) {
smart_str_append(str, Z_STR_P(zv));
return;
}
}
smart_str_appendc(str, '{');
zend_ast_export_ex(str, ast, 0, indent);
smart_str_appendc(str, '}');
return zend_ast_valid_var_name(ZSTR_VAL(name), ZSTR_LEN(name))
&& !zend_string_equals_literal_ci(name, "__halt_compiler");
}

static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int priority, int indent)
Expand All @@ -1465,6 +1454,30 @@ static ZEND_COLD void zend_ast_export_var(smart_str *str, zend_ast *ast, int pri
smart_str_appendc(str, '}');
}

static ZEND_COLD void zend_ast_export_static_member_name(smart_str *str, zend_ast *ast, bool is_call, int indent)
{
if (ast->kind == ZEND_AST_ZVAL && Z_TYPE_P(zend_ast_get_zval(ast)) == IS_STRING) {
const zend_string *name = zend_ast_get_str(ast);
/* A bare "class" fetch is a class name fetch, and "public(set)" and its siblings lex as one token. */
bool needs_braces = is_call
? zend_string_equals_literal_ci(name, "public")
|| zend_string_equals_literal_ci(name, "protected")
|| zend_string_equals_literal_ci(name, "private")
: zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_CLASS));

if (zend_ast_valid_identifier(name) && !needs_braces) {
smart_str_append(str, name);
return;
}
} else if (is_call) {
zend_ast_export_var(str, ast, 0, indent);
return;
}
smart_str_appendc(str, '{');
zend_ast_export_ex(str, ast, 0, indent);
smart_str_appendc(str, '}');
}

static ZEND_COLD void zend_ast_export_list(smart_str *str, zend_ast_list *list, bool separator, int priority, int indent)
{
uint32_t i = 0;
Expand Down Expand Up @@ -2255,7 +2268,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_AST_CLASS_CONST:
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
smart_str_appends(str, "::");
zend_ast_export_class_const_name(str, ast->child[1], indent);
zend_ast_export_static_member_name(str, ast->child[1], false, indent);
break;
case ZEND_AST_CLASS_NAME:
if (ast->child[0] == NULL) {
Expand Down Expand Up @@ -2580,7 +2593,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
case ZEND_AST_STATIC_CALL:
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
smart_str_appends(str, "::");
zend_ast_export_var(str, ast->child[1], 0, indent);
zend_ast_export_static_member_name(str, ast->child[1], true, indent);
smart_str_appendc(str, '(');
zend_ast_export_ex(str, ast->child[2], 0, indent);
smart_str_appendc(str, ')');
Expand Down
Loading