Skip to content

Commit 3d46bc2

Browse files
committed
add more tests to validate scope resolution keywords
1 parent 1b85087 commit 3d46bc2

File tree

5 files changed

+275
-36
lines changed

5 files changed

+275
-36
lines changed

Zend/zend_compile.c

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,33 +1793,6 @@ static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
17931793
}
17941794
/* }}} */
17951795

1796-
static zend_string *zend_resolve_const_class_name_reference(zend_ast *ast, const char *type)
1797-
{
1798-
zend_string *class_name = zend_ast_get_str(ast);
1799-
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type_ast(ast)) {
1800-
zend_error_noreturn(E_COMPILE_ERROR,
1801-
"Cannot use \"%s\" as %s, as it is reserved",
1802-
ZSTR_VAL(class_name), type);
1803-
}
1804-
return zend_resolve_class_name(class_name, ast->attr);
1805-
}
1806-
1807-
static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
1808-
{
1809-
if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && zend_is_scope_known()) {
1810-
zend_class_entry *ce = CG(active_class_entry);
1811-
if (!ce) {
1812-
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
1813-
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
1814-
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
1815-
} else if (fetch_type == ZEND_FETCH_CLASS_PARENT && !ce->parent_name) {
1816-
zend_error_noreturn(E_COMPILE_ERROR,
1817-
"Cannot use \"parent\" when current class scope has no parent");
1818-
}
1819-
}
1820-
}
1821-
/* }}} */
1822-
18231796
static bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast);
18241797

18251798
static zend_string *zend_resolve_nested_class_name(zend_ast *ast) /* {{{ */
@@ -1853,6 +1826,37 @@ static zend_string *zend_resolve_nested_class_name(zend_ast *ast) /* {{{ */
18531826
}
18541827
/* }}} */
18551828

1829+
static zend_string *zend_resolve_const_class_name_reference(zend_ast *ast, const char *type)
1830+
{
1831+
if (ast->kind == ZEND_AST_INNER_CLASS) {
1832+
return zend_resolve_nested_class_name(ast);
1833+
}
1834+
1835+
zend_string *class_name = zend_ast_get_str(ast);
1836+
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type_ast(ast)) {
1837+
zend_error_noreturn(E_COMPILE_ERROR,
1838+
"Cannot use \"%s\" as %s, as it is reserved",
1839+
ZSTR_VAL(class_name), type);
1840+
}
1841+
return zend_resolve_class_name(class_name, ast->attr);
1842+
}
1843+
1844+
static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
1845+
{
1846+
if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && zend_is_scope_known()) {
1847+
zend_class_entry *ce = CG(active_class_entry);
1848+
if (!ce) {
1849+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
1850+
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
1851+
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
1852+
} else if (fetch_type == ZEND_FETCH_CLASS_PARENT && !ce->parent_name) {
1853+
zend_error_noreturn(E_COMPILE_ERROR,
1854+
"Cannot use \"parent\" when current class scope has no parent");
1855+
}
1856+
}
1857+
}
1858+
/* }}} */
1859+
18561860
static bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast) /* {{{ */
18571861
{
18581862
uint32_t fetch_type;
@@ -2917,7 +2921,7 @@ static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node) /
29172921

29182922
static void zend_compile_class_ref(znode *result, zend_ast *name_ast, uint32_t fetch_flags);
29192923

2920-
static void zend_compile_inner_class_ref(znode *result, zend_ast *ast) /* {{{ */
2924+
static void zend_compile_inner_class_ref(znode *result, zend_ast *ast, uint32_t fetch_flags) /* {{{ */
29212925
{
29222926
zend_ast *outer_class = ast->child[0];
29232927
zend_ast *inner_class = ast->child[1];
@@ -2926,9 +2930,9 @@ static void zend_compile_inner_class_ref(znode *result, zend_ast *ast) /* {{{ */
29262930

29272931
// handle nesting
29282932
if (outer_class->kind == ZEND_AST_INNER_CLASS) {
2929-
zend_compile_inner_class_ref(&outer_node, outer_class);
2933+
zend_compile_inner_class_ref(&outer_node, outer_class, fetch_flags);
29302934
} else {
2931-
zend_compile_class_ref(&outer_node, outer_class, ZEND_FETCH_CLASS_EXCEPTION);
2935+
zend_compile_class_ref(&outer_node, outer_class, fetch_flags);
29322936
}
29332937

29342938
if (inner_class->kind == ZEND_AST_ZVAL && Z_TYPE_P(zend_ast_get_zval(inner_class)) == IS_STRING) {
@@ -2948,7 +2952,7 @@ static void zend_compile_class_ref(znode *result, zend_ast *name_ast, uint32_t f
29482952
uint32_t fetch_type;
29492953

29502954
if (name_ast->kind == ZEND_AST_INNER_CLASS) {
2951-
zend_compile_inner_class_ref(result, name_ast);
2955+
zend_compile_inner_class_ref(result, name_ast, fetch_flags);
29522956
return;
29532957
}
29542958

@@ -11838,7 +11842,7 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
1183811842
zend_compile_match(result, ast);
1183911843
return;
1184011844
case ZEND_AST_INNER_CLASS:
11841-
zend_compile_inner_class_ref(result, ast);
11845+
zend_compile_inner_class_ref(result, ast, ZEND_FETCH_CLASS_EXCEPTION);
1184211846
return;
1184311847
default:
1184411848
ZEND_ASSERT(0 /* not supported */);

Zend/zend_vm_def.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1798,7 +1798,7 @@ ZEND_VM_C_LABEL(fetch_this):
17981798
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
17991799
}
18001800

1801-
ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR, CONST, CACHE_SLOT)
1801+
ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR|UNUSED, CONST, CACHE_SLOT)
18021802
{
18031803
USE_OPLINE
18041804
SAVE_OPLINE();
@@ -1813,6 +1813,42 @@ ZEND_VM_HANDLER(210, ZEND_FETCH_INNER_CLASS, CONST|TMPVAR, CONST, CACHE_SLOT)
18131813
zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL_P(outer_class_zv));
18141814
HANDLE_EXCEPTION();
18151815
}
1816+
} else if (OP1_TYPE == IS_UNUSED) {
1817+
uint32_t fetch_type;
1818+
zend_class_entry *called_scope, *scope;
1819+
1820+
fetch_type = opline->op1.num;
1821+
scope = EX(func)->op_array.scope;
1822+
if (UNEXPECTED(scope == NULL)) {
1823+
SAVE_OPLINE();
1824+
zend_throw_error(NULL, "Cannot use \"%s\" in the global scope",
1825+
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
1826+
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
1827+
ZVAL_UNDEF(EX_VAR(opline->result.var));
1828+
HANDLE_EXCEPTION();
1829+
}
1830+
if (fetch_type & ZEND_FETCH_CLASS_SELF) {
1831+
outer_ce = scope;
1832+
} else if (fetch_type & ZEND_FETCH_CLASS_PARENT) {
1833+
if (UNEXPECTED(scope->parent == NULL)) {
1834+
SAVE_OPLINE();
1835+
zend_throw_error(NULL,
1836+
"Cannot use \"parent\" when current class scope has no parent");
1837+
ZVAL_UNDEF(EX_VAR(opline->result.var));
1838+
HANDLE_EXCEPTION();
1839+
}
1840+
outer_ce = scope->parent;
1841+
} else if (fetch_type & ZEND_FETCH_CLASS_STATIC) {
1842+
if (Z_TYPE(EX(This)) == IS_OBJECT) {
1843+
called_scope = Z_OBJCE(EX(This));
1844+
} else {
1845+
called_scope = Z_CE(EX(This));
1846+
}
1847+
outer_ce = called_scope;
1848+
} else {
1849+
zend_throw_error(NULL, "Unknown scope resolution");
1850+
HANDLE_EXCEPTION();
1851+
}
18161852
} else {
18171853
outer_ce = CACHED_PTR(opline->extended_value);
18181854
if (UNEXPECTED(outer_ce == NULL)) {

Zend/zend_vm_execute.h

Lines changed: 158 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_vm_handlers.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)