Skip to content

Commit 7275204

Browse files
committed
More groundwork for runtime variance checks
1 parent 7d820d6 commit 7275204

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

Zend/zend.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,8 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals) /* {{
627627
zend_hash_init_ex(compiler_globals->class_table, 64, NULL, ZEND_CLASS_DTOR, 1, 0);
628628
zend_hash_copy(compiler_globals->class_table, global_class_table, zend_class_add_ref);
629629

630+
compiler_globals->unverified_types = NULL;
631+
630632
zend_set_default_compile_time_values();
631633

632634
compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable));

Zend/zend_compile.c

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6266,6 +6266,7 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
62666266

62676267
zend_class_entry *original_ce = CG(active_class_entry);
62686268

6269+
62696270
if (EXPECTED((decl->flags & ZEND_ACC_ANON_CLASS) == 0)) {
62706271
zend_string *unqualified_name = decl->name;
62716272

@@ -6392,6 +6393,15 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
63926393
ce->ce_flags |= ZEND_ACC_TOP_LEVEL;
63936394
}
63946395

6396+
// todo: add to set of classnames that need variance checks iff inheritance is involved
6397+
if (extends_ast || implements_ast) {
6398+
if (CG(unverified_types)) {
6399+
zend_hash_add_empty_element(CG(unverified_types), lcname);
6400+
} else {
6401+
// todo: figure out why it's null; need a caller (somewhere) to initialize, emit, and destroy the unverified types
6402+
}
6403+
}
6404+
63956405
if (toplevel
63966406
/* We currently don't early-bind classes that implement interfaces or use traits */
63976407
&& !(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
@@ -6471,8 +6481,6 @@ void zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
64716481
opline->opcode = ZEND_DECLARE_CLASS;
64726482
}
64736483
}
6474-
6475-
// todo: add to set of classnames that need variance checks iff inheritance is involved
64766484
}
64776485
/* }}} */
64786486

@@ -8076,6 +8084,35 @@ void zend_const_expr_to_zval(zval *result, zend_ast *ast) /* {{{ */
80768084
}
80778085
/* }}} */
80788086

8087+
static zend_bool _is_type_decl(zend_ast *ast) {
8088+
return ast && ast->kind == ZEND_AST_CLASS;
8089+
}
8090+
8091+
static zend_bool _is_not_decl_stmt(zend_ast *ast) {
8092+
if (ast) {
8093+
/* todo: what else should be considered a decl stmt? */
8094+
switch (ast->kind) {
8095+
case ZEND_AST_FUNC_DECL:
8096+
case ZEND_AST_CLASS:
8097+
return 0;
8098+
8099+
default:
8100+
return 1;
8101+
}
8102+
}
8103+
8104+
/* todo: why are these sometimes null? */
8105+
return 0;
8106+
}
8107+
8108+
static zend_ast **_ast_find(zend_ast **begin, zend_ast **end,
8109+
zend_bool (*pred)(zend_ast *)) {
8110+
while (begin < end)
8111+
if (pred(*begin++))
8112+
return begin;
8113+
return begin;
8114+
}
8115+
80798116
/* Same as compile_stmt, but with early binding */
80808117
void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
80818118
{
@@ -8085,9 +8122,37 @@ void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
80858122

80868123
if (ast->kind == ZEND_AST_STMT_LIST) {
80878124
zend_ast_list *list = zend_ast_get_list(ast);
8088-
uint32_t i;
8089-
for (i = 0; i < list->children; ++i) {
8090-
zend_compile_top_stmt(list->child[i]);
8125+
zend_ast **begin = list->child;
8126+
zend_ast **end = begin + list->children;
8127+
zend_ast **first_decl = _ast_find(begin, end, &_is_type_decl);
8128+
zend_ast **last_decl = _ast_find(first_decl, end, &_is_not_decl_stmt);
8129+
zend_ast **p;
8130+
8131+
/* Compile opcodes before first type decl */
8132+
for (p = begin; p < first_decl; ++p) {
8133+
zend_compile_top_stmt(*p);
8134+
}
8135+
8136+
/* Compile decl stmts */
8137+
{
8138+
HashTable unverified_types;
8139+
HashTable *prev_unverified_types;
8140+
zend_hash_init(&unverified_types, 0, NULL, NULL, 1);
8141+
prev_unverified_types = CG(unverified_types);
8142+
CG(unverified_types) = &unverified_types;
8143+
8144+
for (p = first_decl; p < last_decl; ++p) {
8145+
zend_compile_top_stmt(*p);
8146+
}
8147+
8148+
/* todo: emit ZEND_VERIFY_VARIANCE */
8149+
zend_hash_destroy(&unverified_types);
8150+
CG(unverified_types) = prev_unverified_types;
8151+
}
8152+
8153+
/* Compile remainder */
8154+
for (p = last_decl; p < end; ++p) {
8155+
zend_compile_top_stmt(*p);
80918156
}
80928157
return;
80938158
}

Zend/zend_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct _zend_compiler_globals {
6565
zend_stack loop_var_stack;
6666

6767
zend_class_entry *active_class_entry;
68+
HashTable *unverified_types;
6869

6970
zend_string *compiled_filename;
7071

0 commit comments

Comments
 (0)