Skip to content

Commit 151cd90

Browse files
committed
Fix handling of zend_ast_decl AST nodes when copying
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.
1 parent 85f69a7 commit 151cd90

File tree

5 files changed

+74
-1
lines changed

5 files changed

+74
-1
lines changed

Zend/zend_ast.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,14 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
10881088
size += zend_ast_tree_size(list->child[i]);
10891089
}
10901090
}
1091+
} else if (zend_ast_is_decl(ast)) {
1092+
zend_ast_decl *decl = (zend_ast_decl*)ast;
1093+
size = sizeof(zend_ast_decl);
1094+
for (size_t i = 0; i < 5; i++) {
1095+
if (decl->child[i]) {
1096+
size += zend_ast_tree_size(decl->child[i]);
1097+
}
1098+
}
10911099
} else {
10921100
uint32_t i, children = zend_ast_get_num_children(ast);
10931101

@@ -1141,6 +1149,34 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
11411149
ZVAL_COPY(&new->val, &((zend_ast_zval *) ast)->val);
11421150
Z_LINENO(new->val) = zend_ast_get_lineno(ast);
11431151
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
1152+
} else if (zend_ast_is_decl(ast)) {
1153+
zend_ast_decl *old = (zend_ast_decl*)ast;
1154+
zend_ast_decl *new = (zend_ast_decl*)buf;
1155+
new->kind = old->kind;
1156+
new->attr = old->attr;
1157+
new->start_lineno = old->start_lineno;
1158+
new->end_lineno = old->end_lineno;
1159+
new->flags = old->flags;
1160+
if (old->doc_comment) {
1161+
new->doc_comment = zend_string_copy(old->doc_comment);
1162+
} else {
1163+
new->doc_comment = NULL;
1164+
}
1165+
if (old->name) {
1166+
new->name = zend_string_copy(old->name);
1167+
} else {
1168+
new->name = NULL;
1169+
}
1170+
1171+
buf = (void*)((char*)buf + sizeof(zend_ast_decl));
1172+
for (size_t i = 0; i < 5; i++) {
1173+
if (old->child[i]) {
1174+
new->child[i] = (zend_ast*)buf;
1175+
buf = zend_ast_tree_copy(old->child[i], buf);
1176+
} else {
1177+
new->child[i] = NULL;
1178+
}
1179+
}
11441180
} else {
11451181
uint32_t i, children = zend_ast_get_num_children(ast);
11461182
zend_ast *new = (zend_ast*)buf;
@@ -1206,7 +1242,7 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
12061242
zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
12071243
} else if (EXPECTED(ast->kind == ZEND_AST_OP_ARRAY)) {
12081244
ZEND_ASSERT(!Z_REFCOUNTED(((zend_ast_zval*)(ast))->val));
1209-
} else if (EXPECTED(ast->kind >= ZEND_AST_FUNC_DECL)) {
1245+
} else if (zend_ast_is_decl(ast)) {
12101246
zend_ast_decl *decl = (zend_ast_decl *) ast;
12111247

12121248
if (decl->name) {

Zend/zend_ast.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ static zend_always_inline bool zend_ast_is_special(zend_ast *ast) {
331331
return (ast->kind >> ZEND_AST_SPECIAL_SHIFT) & 1;
332332
}
333333

334+
static zend_always_inline bool zend_ast_is_decl(zend_ast *ast) {
335+
return zend_ast_is_special(ast) && ast->kind >= ZEND_AST_FUNC_DECL;
336+
}
337+
334338
static zend_always_inline bool zend_ast_is_list(zend_ast *ast) {
335339
return (ast->kind >> ZEND_AST_IS_LIST_SHIFT) & 1;
336340
}

ext/opcache/zend_file_cache.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,16 @@ static void zend_file_cache_serialize_ast(zend_ast *ast,
366366
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
367367
/* The op_array itself will be serialized as part of the dynamic_func_defs. */
368368
SERIALIZE_PTR(Z_PTR(((zend_ast_zval*)ast)->val));
369+
} else if (zend_ast_is_decl(ast)) {
370+
zend_ast_decl *decl = (zend_ast_decl*)ast;
371+
for (i = 0; i < 5; i++) {
372+
if (decl->child[i] && !IS_SERIALIZED(decl->child[i])) {
373+
SERIALIZE_PTR(decl->child[i]);
374+
tmp = decl->child[i];
375+
UNSERIALIZE_PTR(tmp);
376+
zend_file_cache_serialize_ast(tmp, script, info, buf);
377+
}
378+
}
369379
} else {
370380
uint32_t children = zend_ast_get_num_children(ast);
371381
for (i = 0; i < children; i++) {
@@ -1248,6 +1258,14 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast,
12481258
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
12491259
/* The op_array itself will be unserialized as part of the dynamic_func_defs. */
12501260
UNSERIALIZE_PTR(Z_PTR(((zend_ast_zval*)ast)->val));
1261+
} else if (zend_ast_is_decl(ast)) {
1262+
zend_ast_decl *decl = (zend_ast_decl*)ast;
1263+
for (i = 0; i < 5; i++) {
1264+
if (decl->child[i] && !IS_UNSERIALIZED(decl->child[i])) {
1265+
UNSERIALIZE_PTR(decl->child[i]);
1266+
zend_file_cache_unserialize_ast(decl->child[i], script, buf);
1267+
}
1268+
}
12511269
} else {
12521270
uint32_t children = zend_ast_get_num_children(ast);
12531271
for (i = 0; i < children; i++) {

ext/opcache/zend_persist.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
191191
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
192192
zend_ast_zval *copy = zend_shared_memdup(ast, sizeof(zend_ast_zval));
193193
zend_persist_op_array(&copy->val);
194+
} else if (zend_ast_is_decl(ast)) {
195+
zend_ast_decl *copy = zend_shared_memdup(ast, sizeof(zend_ast_decl));
196+
for (i = 0; i < 5; i++) {
197+
if (copy->child[i]) {
198+
copy->child[i] = zend_persist_ast(copy->child[i]);
199+
}
200+
}
194201
node = (zend_ast *) copy;
195202
} else {
196203
uint32_t children = zend_ast_get_num_children(ast);

ext/opcache/zend_persist_calc.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ static void zend_persist_ast_calc(zend_ast *ast)
8989
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
9090
ADD_SIZE(sizeof(zend_ast_zval));
9191
zend_persist_op_array_calc(&((zend_ast_zval*)(ast))->val);
92+
} else if (zend_ast_is_decl(ast)) {
93+
zend_ast_decl *decl = (zend_ast_decl*)ast;
94+
ADD_SIZE(sizeof(zend_ast_decl));
95+
for (size_t i = 0; i < 5; i++) {
96+
if (decl->child[i]) {
97+
zend_persist_ast_calc(decl->child[i]);
98+
}
99+
}
92100
} else {
93101
uint32_t children = zend_ast_get_num_children(ast);
94102
ADD_SIZE(zend_ast_size(children));

0 commit comments

Comments
 (0)