Skip to content

Commit 5287c6b

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 cee64ed commit 5287c6b

File tree

4 files changed

+65
-13
lines changed

4 files changed

+65
-13
lines changed

Zend/zend_ast.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,8 +1103,13 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
11031103
}
11041104
}
11051105
} else if (zend_ast_is_decl(ast)) {
1106-
/* Not implemented. */
1107-
ZEND_UNREACHABLE();
1106+
zend_ast_decl *decl = (zend_ast_decl*)ast;
1107+
size = sizeof(zend_ast_decl);
1108+
for (size_t i = 0; i < 5; i++) {
1109+
if (decl->child[i]) {
1110+
size += zend_ast_tree_size(decl->child[i]);
1111+
}
1112+
}
11081113
} else {
11091114
uint32_t i, children = zend_ast_get_num_children(ast);
11101115

@@ -1160,8 +1165,33 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
11601165
new->op_array = old->op_array;
11611166
buf = (void*)((char*)buf + sizeof(zend_ast_op_array));
11621167
} else if (zend_ast_is_decl(ast)) {
1163-
/* Not implemented. */
1164-
ZEND_UNREACHABLE();
1168+
zend_ast_decl *old = (zend_ast_decl*)ast;
1169+
zend_ast_decl *new = (zend_ast_decl*)buf;
1170+
new->kind = old->kind;
1171+
new->attr = old->attr;
1172+
new->start_lineno = old->start_lineno;
1173+
new->end_lineno = old->end_lineno;
1174+
new->flags = old->flags;
1175+
if (old->doc_comment) {
1176+
new->doc_comment = zend_string_copy(old->doc_comment);
1177+
} else {
1178+
new->doc_comment = NULL;
1179+
}
1180+
if (old->name) {
1181+
new->name = zend_string_copy(old->name);
1182+
} else {
1183+
new->name = NULL;
1184+
}
1185+
1186+
buf = (void*)((char*)buf + sizeof(zend_ast_decl));
1187+
for (size_t i = 0; i < 5; i++) {
1188+
if (old->child[i]) {
1189+
new->child[i] = (zend_ast*)buf;
1190+
buf = zend_ast_tree_copy(old->child[i], buf);
1191+
} else {
1192+
new->child[i] = NULL;
1193+
}
1194+
}
11651195
} else {
11661196
uint32_t i, children = zend_ast_get_num_children(ast);
11671197
zend_ast *new = (zend_ast*)buf;
@@ -1227,7 +1257,7 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
12271257
zend_string_release_ex(zend_ast_get_constant_name(ast), 0);
12281258
} else if (EXPECTED(ast->kind == ZEND_AST_OP_ARRAY)) {
12291259
/* Nothing to do. */
1230-
} else if (EXPECTED(zend_ast_is_decl(ast))) {
1260+
} else if (zend_ast_is_decl(ast)) {
12311261
zend_ast_decl *decl = (zend_ast_decl *) ast;
12321262

12331263
if (decl->name) {

ext/opcache/zend_file_cache.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,15 @@ static void zend_file_cache_serialize_ast(zend_ast *ast,
367367
/* The op_array itself will be serialized as part of the dynamic_func_defs. */
368368
SERIALIZE_PTR(zend_ast_get_op_array(ast)->op_array);
369369
} else if (zend_ast_is_decl(ast)) {
370-
/* Not implemented. */
371-
ZEND_UNREACHABLE();
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+
}
372379
} else {
373380
uint32_t children = zend_ast_get_num_children(ast);
374381
for (i = 0; i < children; i++) {
@@ -1252,8 +1259,13 @@ static void zend_file_cache_unserialize_ast(zend_ast *ast,
12521259
/* The op_array itself will be unserialized as part of the dynamic_func_defs. */
12531260
UNSERIALIZE_PTR(zend_ast_get_op_array(ast)->op_array);
12541261
} else if (zend_ast_is_decl(ast)) {
1255-
/* Not implemented. */
1256-
ZEND_UNREACHABLE();
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+
}
12571269
} else {
12581270
uint32_t children = zend_ast_get_num_children(ast);
12591271
for (i = 0; i < children; i++) {

ext/opcache/zend_persist.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,13 @@ static zend_ast *zend_persist_ast(zend_ast *ast)
196196
copy->op_array = Z_PTR(z);
197197
node = (zend_ast *) copy;
198198
} else if (zend_ast_is_decl(ast)) {
199-
/* Not implemented. */
200-
ZEND_UNREACHABLE();
199+
zend_ast_decl *copy = zend_shared_memdup(ast, sizeof(zend_ast_decl));
200+
for (i = 0; i < 5; i++) {
201+
if (copy->child[i]) {
202+
copy->child[i] = zend_persist_ast(copy->child[i]);
203+
}
204+
}
205+
node = (zend_ast *) copy;
201206
} else {
202207
uint32_t children = zend_ast_get_num_children(ast);
203208
node = zend_shared_memdup(ast, zend_ast_size(children));

ext/opcache/zend_persist_calc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,13 @@ static void zend_persist_ast_calc(zend_ast *ast)
9292
ZVAL_PTR(&z, zend_ast_get_op_array(ast)->op_array);
9393
zend_persist_op_array_calc(&z);
9494
} else if (zend_ast_is_decl(ast)) {
95-
/* Not implemented. */
96-
ZEND_UNREACHABLE();
95+
zend_ast_decl *decl = (zend_ast_decl*)ast;
96+
ADD_SIZE(sizeof(zend_ast_decl));
97+
for (size_t i = 0; i < 5; i++) {
98+
if (decl->child[i]) {
99+
zend_persist_ast_calc(decl->child[i]);
100+
}
101+
}
97102
} else {
98103
uint32_t children = zend_ast_get_num_children(ast);
99104
ADD_SIZE(zend_ast_size(children));

0 commit comments

Comments
 (0)