summaryrefslogtreecommitdiff
path: root/Zend/zend_compile.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2016-06-16 02:30:23 +0300
committerDmitry Stogov <dmitry@zend.com>2016-06-16 02:30:23 +0300
commita9512af8109e889eb2c6042c57797184930667cd (patch)
tree4f4f8bbcbddd3798d50d35c555a5a7620e77735f /Zend/zend_compile.c
parentfba6f90ae3d9d15b2fab7a0ec06be5767e2ab148 (diff)
downloadphp-git-a9512af8109e889eb2c6042c57797184930667cd.tar.gz
Implemented RFC: Fix inconsistent behavior of $this variable
Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r--Zend/zend_compile.c79
1 files changed, 47 insertions, 32 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 6928af10b8..02507f2366 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -756,6 +756,9 @@ void zend_do_free(znode *op1) /* {{{ */
additional FREE opcode and simplify the FETCH handlers
their selves */
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
+ } else if (opline->opcode == ZEND_FETCH_THIS) {
+ opline->opcode = ZEND_NOP;
+ opline->result_type = IS_UNUSED;
} else {
opline->result_type = IS_UNUSED;
}
@@ -1928,6 +1931,10 @@ static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */
{
zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3;
+ if (opline->opcode == ZEND_FETCH_THIS) {
+ return;
+ }
+
switch (type & BP_VAR_MASK) {
case BP_VAR_R:
return;
@@ -2527,9 +2534,6 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
/* lookup_cv may be using another zend_string instance */
name = CG(active_op_array)->vars[EX_VAR_TO_NUM(result->u.op.var)];
- if (zend_string_equals_literal(name, "this")) {
- CG(active_op_array)->this_var = result->u.op.var;
- }
return SUCCESS;
}
@@ -2560,22 +2564,31 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint
opline->extended_value = ZEND_FETCH_GLOBAL;
} else {
opline->extended_value = ZEND_FETCH_LOCAL;
- /* there is a chance someone is accessing $this */
- if (ast->kind != ZEND_AST_ZVAL
- && CG(active_op_array)->scope && CG(active_op_array)->this_var == (uint32_t)-1
- ) {
- zend_string *key = CG(known_strings)[ZEND_STR_THIS];
- CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), key);
- }
}
return opline;
}
/* }}} */
+static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */
+{
+ if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
+ zval *name = zend_ast_get_zval(ast->child[0]);
+ return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
+ }
+
+ return 0;
+}
+/* }}} */
+
static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */
{
- if (zend_try_compile_cv(result, ast) == FAILURE) {
+ zend_op *opline;
+
+ if (is_this_fetch(ast)) {
+ opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL);
+ zend_adjust_for_fetch_type(opline, type);
+ } else if (zend_try_compile_cv(result, ast) == FAILURE) {
zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type, delayed);
zend_adjust_for_fetch_type(opline, type);
}
@@ -2656,17 +2669,6 @@ void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
}
/* }}} */
-static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */
-{
- if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
- zval *name = zend_ast_get_zval(ast->child[0]);
- return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
- }
-
- return 0;
-}
-/* }}} */
-
static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
{
zend_ast *obj_ast = ast->child[0];
@@ -2965,7 +2967,8 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_W);
- if (zend_is_assign_to_self(var_ast, expr_ast)) {
+ if (zend_is_assign_to_self(var_ast, expr_ast)
+ && !is_this_fetch(expr_ast)) {
/* $a[0] = $a should evaluate the right $a first */
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
} else {
@@ -3899,7 +3902,9 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */
convert_to_string(&name_node.u.constant);
}
- if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
+ if (is_this_fetch(var_ast)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable");
+ } else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node);
zend_alloc_cache_slot(opline->op2.constant);
} else {
@@ -3944,6 +3949,10 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
}
zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value);
+ if (zend_string_equals_literal(Z_STR(var_node.u.constant), "this")) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
+ }
+
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node);
opline->op1_type = IS_CV;
opline->op1.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR(var_node.u.constant)));
@@ -3977,7 +3986,9 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
switch (var_ast->kind) {
case ZEND_AST_VAR:
- if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
+ if (is_this_fetch(var_ast)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot unset $this");
+ } else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
opline = zend_emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL);
opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
} else {
@@ -4412,7 +4423,9 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
opnum_fetch = get_next_op_number(CG(active_op_array));
opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
- if (value_ast->kind == ZEND_AST_VAR &&
+ if (is_this_fetch(value_ast)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
+ } else if (value_ast->kind == ZEND_AST_VAR &&
zend_try_compile_cv(&value_node, value_ast) == SUCCESS) {
SET_NODE(opline->op2, &value_node);
} else {
@@ -4666,6 +4679,10 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
opline->op1.constant = zend_add_class_name_literal(CG(active_op_array),
zend_resolve_class_name_ast(class_ast));
+ if (zend_string_equals_literal(Z_STR_P(var_name), "this")) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
+ }
+
opline->op2_type = IS_CV;
opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name)));
@@ -5009,11 +5026,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s",
ZSTR_VAL(name));
} else if (zend_string_equals_literal(name, "this")) {
- if ((op_array->scope || (op_array->fn_flags & ZEND_ACC_CLOSURE))
- && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter");
- }
- op_array->this_var = var_node.u.op.var;
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter");
}
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
@@ -6996,7 +7009,9 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
switch (var_ast->kind) {
case ZEND_AST_VAR:
- if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
+ if (is_this_fetch(var_ast)) {
+ opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
+ } else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL);
opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
} else {