Skip to content

Commit

Permalink
Fix handling of zend_ast_decl AST nodes when copying
Browse files Browse the repository at this point in the history
Previously `zend_ast_decl` AST nodes were handled as if they were regular
`zend_ast` nodes.

This was not observable, because copying an AST only happened when evaluating
const-expressions, which could not include declarations until the “Support
Closures in constant expressions” RFC.
  • Loading branch information
TimWolla committed Dec 11, 2024
1 parent 85f69a7 commit 151cd90
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 1 deletion.
38 changes: 37 additions & 1 deletion Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,14 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
size += zend_ast_tree_size(list->child[i]);
}
}
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *decl = (zend_ast_decl*)ast;
size = sizeof(zend_ast_decl);
for (size_t i = 0; i < 5; i++) {
if (decl->child[i]) {
size += zend_ast_tree_size(decl->child[i]);
}
}
} else {
uint32_t i, children = zend_ast_get_num_children(ast);

Expand Down Expand Up @@ -1141,6 +1149,34 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
ZVAL_COPY(&new->val, &((zend_ast_zval *) ast)->val);
Z_LINENO(new->val) = zend_ast_get_lineno(ast);
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *old = (zend_ast_decl*)ast;
zend_ast_decl *new = (zend_ast_decl*)buf;
new->kind = old->kind;
new->attr = old->attr;
new->start_lineno = old->start_lineno;
new->end_lineno = old->end_lineno;
new->flags = old->flags;
if (old->doc_comment) {
new->doc_comment = zend_string_copy(old->doc_comment);
} else {
new->doc_comment = NULL;
}
if (old->name) {
new->name = zend_string_copy(old->name);
} else {
new->name = NULL;
}

buf = (void*)((char*)buf + sizeof(zend_ast_decl));
for (size_t i = 0; i < 5; i++) {
if (old->child[i]) {
new->child[i] = (zend_ast*)buf;
buf = zend_ast_tree_copy(old->child[i], buf);
} else {
new->child[i] = NULL;
}
}
} else {
uint32_t i, children = zend_ast_get_num_children(ast);
zend_ast *new = (zend_ast*)buf;
Expand Down Expand Up @@ -1206,7 +1242,7 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
} else if (EXPECTED(ast->kind == ZEND_AST_OP_ARRAY)) {
ZEND_ASSERT(!Z_REFCOUNTED(((zend_ast_zval*)(ast))->val));
} else if (EXPECTED(ast->kind >= ZEND_AST_FUNC_DECL)) {
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *decl = (zend_ast_decl *) ast;

if (decl->name) {
Expand Down
4 changes: 4 additions & 0 deletions Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ static zend_always_inline bool zend_ast_is_special(zend_ast *ast) {
return (ast->kind >> ZEND_AST_SPECIAL_SHIFT) & 1;
}

static zend_always_inline bool zend_ast_is_decl(zend_ast *ast) {
return zend_ast_is_special(ast) && ast->kind >= ZEND_AST_FUNC_DECL;
}

static zend_always_inline bool zend_ast_is_list(zend_ast *ast) {
return (ast->kind >> ZEND_AST_IS_LIST_SHIFT) & 1;
}
Expand Down
18 changes: 18 additions & 0 deletions ext/opcache/zend_file_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,16 @@ static void zend_file_cache_serialize_ast(zend_ast *ast,
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
/* The op_array itself will be serialized as part of the dynamic_func_defs. */
SERIALIZE_PTR(Z_PTR(((zend_ast_zval*)ast)->val));
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *decl = (zend_ast_decl*)ast;
for (i = 0; i < 5; i++) {
if (decl->child[i] && !IS_SERIALIZED(decl->child[i])) {
SERIALIZE_PTR(decl->child[i]);
tmp = decl->child[i];
UNSERIALIZE_PTR(tmp);
zend_file_cache_serialize_ast(tmp, script, info, buf);
}
}
} else {
uint32_t children = zend_ast_get_num_children(ast);
for (i = 0; i < children; i++) {
Expand Down Expand Up @@ -1248,6 +1258,14 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast,
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
/* The op_array itself will be unserialized as part of the dynamic_func_defs. */
UNSERIALIZE_PTR(Z_PTR(((zend_ast_zval*)ast)->val));
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *decl = (zend_ast_decl*)ast;
for (i = 0; i < 5; i++) {
if (decl->child[i] && !IS_UNSERIALIZED(decl->child[i])) {
UNSERIALIZE_PTR(decl->child[i]);
zend_file_cache_unserialize_ast(decl->child[i], script, buf);
}
}
} else {
uint32_t children = zend_ast_get_num_children(ast);
for (i = 0; i < children; i++) {
Expand Down
7 changes: 7 additions & 0 deletions ext/opcache/zend_persist.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
zend_ast_zval *copy = zend_shared_memdup(ast, sizeof(zend_ast_zval));
zend_persist_op_array(&copy->val);
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *copy = zend_shared_memdup(ast, sizeof(zend_ast_decl));
for (i = 0; i < 5; i++) {
if (copy->child[i]) {
copy->child[i] = zend_persist_ast(copy->child[i]);
}
}
node = (zend_ast *) copy;
} else {
uint32_t children = zend_ast_get_num_children(ast);
Expand Down
8 changes: 8 additions & 0 deletions ext/opcache/zend_persist_calc.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ static void zend_persist_ast_calc(zend_ast *ast)
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
ADD_SIZE(sizeof(zend_ast_zval));
zend_persist_op_array_calc(&((zend_ast_zval*)(ast))->val);
} else if (zend_ast_is_decl(ast)) {
zend_ast_decl *decl = (zend_ast_decl*)ast;
ADD_SIZE(sizeof(zend_ast_decl));
for (size_t i = 0; i < 5; i++) {
if (decl->child[i]) {
zend_persist_ast_calc(decl->child[i]);
}
}
} else {
uint32_t children = zend_ast_get_num_children(ast);
ADD_SIZE(zend_ast_size(children));
Expand Down

0 comments on commit 151cd90

Please sign in to comment.