Skip to content

Encode string offset error reason in extended_value #7599

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

Closed
wants to merge 1 commit into from
Closed
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
50 changes: 36 additions & 14 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -2723,7 +2723,7 @@ static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node)
}
/* }}} */

static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type, bool by_ref)
{
if (ast->attr == ZEND_DIM_ALTERNATIVE_SYNTAX) {
zend_error(E_COMPILE_ERROR, "Array and string offset access syntax with curly braces is no longer supported");
Expand Down Expand Up @@ -2751,8 +2751,15 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t
} else {
zend_short_circuiting_mark_inner(var_ast);
opline = zend_delayed_compile_var(&var_node, var_ast, type, 0);
if (opline && type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
opline->extended_value |= ZEND_FETCH_DIM_WRITE;
if (opline) {
if (type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
opline->extended_value |= ZEND_FETCH_DIM_WRITE;
} else if (opline->opcode == ZEND_FETCH_DIM_W
|| opline->opcode == ZEND_FETCH_DIM_RW
|| opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
|| opline->opcode == ZEND_FETCH_DIM_UNSET) {
opline->extended_value = ZEND_FETCH_DIM_DIM;
}
}
}

Expand All @@ -2772,18 +2779,20 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t

opline = zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node);
zend_adjust_for_fetch_type(opline, result, type);
if (by_ref) {
opline->extended_value = ZEND_FETCH_DIM_REF;
}

if (dim_node.op_type == IS_CONST) {
zend_handle_numeric_dim(opline, &dim_node);
}
return opline;
}
/* }}} */

static zend_op *zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
static zend_op *zend_compile_dim(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
{
uint32_t offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, ast, type);
zend_delayed_compile_dim(result, ast, type, by_ref);
return zend_delayed_compile_end(offset);
}
/* }}} */
Expand All @@ -2810,6 +2819,13 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
} else {
zend_short_circuiting_mark_inner(obj_ast);
opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
if (opline && (opline->opcode == ZEND_FETCH_DIM_W
|| opline->opcode == ZEND_FETCH_DIM_RW
|| opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
|| opline->opcode == ZEND_FETCH_DIM_UNSET)) {
opline->extended_value = ZEND_FETCH_DIM_OBJ;
}

zend_separate_if_call_and_write(&obj_node, obj_ast, type);
if (nullsafe) {
/* We will push to the short_circuiting_opnums stack in zend_delayed_compile_end(). */
Expand Down Expand Up @@ -3113,7 +3129,7 @@ static void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
return;
case ZEND_AST_DIM:
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_W);
zend_delayed_compile_dim(result, var_ast, BP_VAR_W, /* by_ref */ false);

if (zend_is_assign_to_self(var_ast, expr_ast)
&& !is_this_fetch(expr_ast)) {
Expand Down Expand Up @@ -3296,7 +3312,7 @@ static void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
return;
case ZEND_AST_DIM:
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_RW);
zend_delayed_compile_dim(result, var_ast, BP_VAR_RW, /* by_ref */ false);
zend_compile_expr(&expr_node, expr_ast);

opline = zend_delayed_compile_end(offset);
Expand Down Expand Up @@ -4709,7 +4725,7 @@ static void zend_compile_unset(zend_ast *ast) /* {{{ */
}
return;
case ZEND_AST_DIM:
opline = zend_compile_dim(NULL, var_ast, BP_VAR_UNSET);
opline = zend_compile_dim(NULL, var_ast, BP_VAR_UNSET, /* by_ref */ false);
opline->opcode = ZEND_UNSET_DIM;
return;
case ZEND_AST_PROP:
Expand Down Expand Up @@ -8681,7 +8697,10 @@ static void zend_compile_post_incdec(znode *result, zend_ast *ast) /* {{{ */
zend_make_tmp_result(result, opline);
} else {
znode var_node;
zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
zend_op *opline = zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
if (opline && opline->opcode == ZEND_FETCH_DIM_RW) {
opline->extended_value = ZEND_FETCH_DIM_INCDEC;
}
zend_emit_op_tmp(result, ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC,
&var_node, NULL);
}
Expand All @@ -8707,7 +8726,10 @@ static void zend_compile_pre_incdec(znode *result, zend_ast *ast) /* {{{ */
result->op_type = IS_TMP_VAR;
} else {
znode var_node;
zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
zend_op *opline = zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
if (opline && opline->opcode == ZEND_FETCH_DIM_RW) {
opline->extended_value = ZEND_FETCH_DIM_INCDEC;
}
zend_emit_op_tmp(result, ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC,
&var_node, NULL);
}
Expand Down Expand Up @@ -9154,7 +9176,7 @@ static void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
}
break;
case ZEND_AST_DIM:
opline = zend_compile_dim(result, var_ast, BP_VAR_IS);
opline = zend_compile_dim(result, var_ast, BP_VAR_IS, /* by_ref */ false);
opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
break;
case ZEND_AST_PROP:
Expand Down Expand Up @@ -10114,7 +10136,7 @@ static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t ty
case ZEND_AST_VAR:
return zend_compile_simple_var(result, ast, type, 0);
case ZEND_AST_DIM:
return zend_compile_dim(result, ast, type);
return zend_compile_dim(result, ast, type, by_ref);
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
return zend_compile_prop(result, ast, type, by_ref);
Expand Down Expand Up @@ -10158,7 +10180,7 @@ static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t
case ZEND_AST_VAR:
return zend_compile_simple_var(result, ast, type, 1);
case ZEND_AST_DIM:
return zend_delayed_compile_dim(result, ast, type);
return zend_delayed_compile_dim(result, ast, type, by_ref);
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
{
Expand Down
7 changes: 7 additions & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,13 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
#define ZEND_FETCH_DIM_WRITE 2
#define ZEND_FETCH_OBJ_FLAGS 3

/* Used to mark what kind of operation a writing FETCH_DIM is used in,
* to produce a more precise error on incorrect string offset use. */
#define ZEND_FETCH_DIM_REF 1
#define ZEND_FETCH_DIM_DIM 2
#define ZEND_FETCH_DIM_OBJ 3
#define ZEND_FETCH_DIM_INCDEC 4

#define ZEND_ISEMPTY (1<<0)

#define ZEND_LAST_CATCH (1<<0)
Expand Down
77 changes: 17 additions & 60 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1530,7 +1530,6 @@ ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void)
const char *msg = NULL;
const zend_execute_data *execute_data = EG(current_execute_data);
const zend_op *opline = execute_data->opline;
uint32_t var;

if (UNEXPECTED(EG(exception) != NULL)) {
return;
Expand All @@ -1540,69 +1539,27 @@ ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void)
case ZEND_ASSIGN_DIM_OP:
msg = "Cannot use assign-op operators with string offsets";
break;
case ZEND_FETCH_LIST_W:
msg = "Cannot create references to/from string offsets";
break;
case ZEND_FETCH_DIM_W:
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
case ZEND_FETCH_LIST_W:
/* TODO: Encode the "reason" into opline->extended_value??? */
var = opline->result.var;
opline++;
ZEND_ASSERT(opline < execute_data->func->op_array.opcodes +
execute_data->func->op_array.last);
if (opline->op1_type == IS_VAR && opline->op1.var == var) {
switch (opline->opcode) {
case ZEND_FETCH_OBJ_W:
case ZEND_FETCH_OBJ_RW:
case ZEND_FETCH_OBJ_FUNC_ARG:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_OBJ_OP:
case ZEND_ASSIGN_OBJ_REF:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
case ZEND_UNSET_OBJ:
msg = "Cannot use string offset as an object";
break;
case ZEND_FETCH_DIM_W:
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
case ZEND_FETCH_LIST_W:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_DIM_OP:
case ZEND_UNSET_DIM:
msg = "Cannot use string offset as an array";
break;
case ZEND_PRE_INC:
case ZEND_PRE_DEC:
case ZEND_POST_INC:
case ZEND_POST_DEC:
msg = "Cannot increment/decrement string offsets";
break;
case ZEND_ASSIGN_REF:
case ZEND_ADD_ARRAY_ELEMENT:
case ZEND_INIT_ARRAY:
case ZEND_MAKE_REF:
case ZEND_RETURN_BY_REF:
case ZEND_VERIFY_RETURN_TYPE:
case ZEND_YIELD:
case ZEND_SEND_REF:
case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG:
case ZEND_FE_RESET_RW:
msg = "Cannot create references to/from string offsets";
break;
EMPTY_SWITCH_DEFAULT_CASE();
}
break;
}
if (opline->op2_type == IS_VAR && opline->op2.var == var) {
ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
msg = "Cannot create references to/from string offsets";
break;
switch (opline->extended_value) {
case ZEND_FETCH_DIM_REF:
msg = "Cannot create references to/from string offsets";
break;
case ZEND_FETCH_DIM_DIM:
msg = "Cannot use string offset as an array";
break;
case ZEND_FETCH_DIM_OBJ:
msg = "Cannot use string offset as an object";
break;
case ZEND_FETCH_DIM_INCDEC:
msg = "Cannot increment/decrement string offsets";
break;
EMPTY_SWITCH_DEFAULT_CASE();
}
break;
EMPTY_SWITCH_DEFAULT_CASE();
Expand Down