Skip to content

Undeclared var error #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -5007,7 +5007,6 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
case ZEND_NOP:
case ZEND_QM_ASSIGN:
case ZEND_JMP:
case ZEND_CHECK_VAR:
case ZEND_MAKE_REF:
case ZEND_BEGIN_SILENCE:
case ZEND_END_SILENCE:
Expand All @@ -5029,6 +5028,8 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
case ZEND_JMP_NULL:
case ZEND_JMP_FRAMELESS:
return 0;
case ZEND_CHECK_VAR:
return t1 & MAY_BE_UNDEF;
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
case ZEND_CASE_STRICT:
Expand Down
28 changes: 28 additions & 0 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1807,6 +1807,34 @@ ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const c
}
/* }}} */

ZEND_API ZEND_COLD void zend_throw_error_unchecked(zend_class_entry *exception_ce, const char *format, ...)
{
va_list va;
char *message = NULL;

if (!exception_ce) {
exception_ce = zend_ce_error;
}

/* Marker used to disable exception generation during preloading. */
if (EG(exception) == (void*)(uintptr_t)-1) {
return;
}

va_start(va, format);
zend_vspprintf(&message, 0, format, va);

//TODO: we can't convert compile-time errors to exceptions yet???
if (EG(current_execute_data) && !CG(in_compilation)) {
zend_throw_exception(exception_ce, message, 0);
} else {
zend_error_noreturn(E_ERROR, "%s", message);
}

efree(message);
va_end(va);
}

/* type should be one of the BP_VAR_* constants, only special messages happen for isset/empty and unset */
ZEND_API ZEND_COLD void zend_illegal_container_offset(const zend_string *container, const zval *offset, int type)
{
Expand Down
1 change: 1 addition & 0 deletions Zend/zend.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ ZEND_API ZEND_COLD void zend_error_zstr(int type, zend_string *message);
ZEND_API ZEND_COLD void zend_error_zstr_at(int type, zend_string *filename, uint32_t lineno, zend_string *message);

ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
ZEND_API ZEND_COLD void zend_throw_error_unchecked(zend_class_entry *exception_ce, const char *format, ...);
ZEND_API ZEND_COLD void zend_type_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
ZEND_API ZEND_COLD void zend_argument_count_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
ZEND_API ZEND_COLD void zend_value_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
Expand Down
24 changes: 15 additions & 9 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ static zend_always_inline uint32_t get_temporary_variable(void) /* {{{ */
}
/* }}} */

// FIXME: Check all uses of lookup_cv() to see whether they need CHECK_VAR.
static int lookup_cv(zend_string *name) /* {{{ */{
zend_op_array *op_array = CG(active_op_array);
int i = 0;
Expand Down Expand Up @@ -2870,7 +2871,7 @@ static void zend_compile_class_ref(znode *result, zend_ast *name_ast, uint32_t f
}
/* }}} */

static zend_result zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
static zend_result zend_try_compile_cv(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
{
zend_ast *name_ast = ast->child[0];
if (name_ast->kind == ZEND_AST_ZVAL) {
Expand All @@ -2890,6 +2891,11 @@ static zend_result zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
result->op_type = IS_CV;
result->u.op.var = lookup_cv(name);

// FIXME: Check whether the CV is guaranteed to be declared
if (type == BP_VAR_R || type == BP_VAR_RW) {
zend_emit_op(NULL, ZEND_CHECK_VAR, result, NULL);
}

if (UNEXPECTED(Z_TYPE_P(zv) != IS_STRING)) {
zend_string_release_ex(name, 0);
}
Expand Down Expand Up @@ -2994,7 +3000,7 @@ static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t t
result->op_type = IS_TMP_VAR;
}
return opline;
} else if (zend_try_compile_cv(result, ast) == FAILURE) {
} else if (zend_try_compile_cv(result, ast, type) == FAILURE) {
return zend_compile_simple_var_no_cv(result, ast, type, delayed);
}
return NULL;
Expand Down Expand Up @@ -3420,7 +3426,7 @@ static void zend_compile_expr_with_potential_assign_to_self(
/* $a[0] = $a should evaluate the right $a first */
znode cv_node;

if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
if (zend_try_compile_cv(&cv_node, expr_ast, BP_VAR_R) == FAILURE) {
zend_compile_simple_var_no_cv(expr_node, expr_ast, BP_VAR_R, 0);
} else {
zend_emit_op_tmp(expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
Expand Down Expand Up @@ -3510,7 +3516,7 @@ static void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
/* list($a, $b) = $a should evaluate the right $a first */
znode cv_node;

if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
if (zend_try_compile_cv(&cv_node, expr_ast, BP_VAR_R) == FAILURE) {
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
} else {
zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
Expand Down Expand Up @@ -3825,7 +3831,7 @@ static uint32_t zend_compile_args(
opcode = ZEND_SEND_VAR_EX;
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
break;
} else if (zend_try_compile_cv(&arg_node, arg) == SUCCESS) {
} else if (zend_try_compile_cv(&arg_node, arg, BP_VAR_FUNC_ARG) == SUCCESS) {
opcode = ZEND_SEND_VAR_EX;
break;
}
Expand Down Expand Up @@ -5423,7 +5429,7 @@ static void zend_compile_global_var(zend_ast *ast) /* {{{ */
// TODO(GLOBALS) Forbid "global $GLOBALS"?
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) {
} else if (zend_try_compile_cv(&result, var_ast, BP_VAR_W) == SUCCESS) {
zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node);
opline->extended_value = zend_alloc_cache_slot();
} else {
Expand Down Expand Up @@ -5549,7 +5555,7 @@ static void zend_compile_unset(zend_ast *ast) /* {{{ */
case ZEND_AST_VAR:
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) {
} else if (zend_try_compile_cv(&var_node, var_ast, BP_VAR_UNSET) == SUCCESS) {
opline = zend_emit_op(NULL, ZEND_UNSET_CV, &var_node, NULL);
} else {
opline = zend_compile_simple_var_no_cv(NULL, var_ast, BP_VAR_UNSET, 0);
Expand Down Expand Up @@ -6074,7 +6080,7 @@ static void zend_compile_foreach(zend_ast *ast) /* {{{ */
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) {
zend_try_compile_cv(&value_node, value_ast, BP_VAR_W) == SUCCESS) {
SET_NODE(opline->op2, &value_node);
} else {
opline->op2_type = IS_VAR;
Expand Down Expand Up @@ -10664,7 +10670,7 @@ static void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
if (is_this_fetch(var_ast)) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
} else if (zend_try_compile_cv(&var_node, var_ast, BP_VAR_IS) == SUCCESS) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_CV, &var_node, NULL);
} else {
opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS, 0);
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ static zend_always_inline uint32_t zend_visibility_to_set_visibility(uint32_t vi
#define ZEND_SHORT_CIRCUITING_CHAIN_EMPTY 2

// Must not clash with ZEND_SHORT_CIRCUITING_CHAIN_MASK
// FIXME: Can we get rid of this? CHECK_VAR instruction should be inserted now instead.
#define ZEND_JMP_NULL_BP_VAR_IS 4

char *zend_visibility_string(uint32_t fn_flags);
Expand Down
16 changes: 5 additions & 11 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,19 +348,15 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(uint32_t var EXECUTE_D
{
zval *ret = EX_VAR(var);

if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
return zval_undefined_cv(var EXECUTE_DATA_CC);
}
ZEND_ASSERT(Z_TYPE_P(ret) != IS_UNDEF);
return ret;
}

static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_R(uint32_t var EXECUTE_DATA_DC)
{
zval *ret = EX_VAR(var);

if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
return zval_undefined_cv(var EXECUTE_DATA_CC);
}
ZEND_ASSERT(Z_TYPE_P(ret) != IS_UNDEF);
ZVAL_DEREF(ret);
return ret;
}
Expand All @@ -376,11 +372,7 @@ static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(uint32_t var EXECUTE_
{
zval *ret = EX_VAR(var);

if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) {
zval_undefined_cv(var EXECUTE_DATA_CC);
ZVAL_NULL(ret);
return ret;
}
ZEND_ASSERT(Z_TYPE_P(ret) != IS_UNDEF);
return ret;
}

Expand Down Expand Up @@ -2045,6 +2037,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim,
/* The string may be destroyed while throwing the notice.
* Temporarily increase the refcount to detect this situation. */
GC_ADDREF(s);
// FIXME: Still needed?
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC);
}
Expand Down Expand Up @@ -3641,6 +3634,7 @@ static zend_never_inline zval* zend_fetch_static_property_address_ex(zend_proper
name = Z_STR_P(varname);
tmp_name = NULL;
} else {
// FIXME: Still needed?
if (op1_type == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) {
zval_undefined_cv(opline->op1.var EXECUTE_DATA_CC);
}
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,8 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
#define ZVAL_DEREF(z) do { \
if (UNEXPECTED(Z_ISREF_P(z))) { \
(z) = Z_REFVAL_P(z); \
/* FIXME: Verify this is beneficial. */ \
ZEND_ASSERT(Z_TYPE_P(z) != IS_UNDEF && Z_TYPE_P(z) != IS_REFERENCE); \
} \
} while (0)

Expand Down
Loading
Loading