expr_without_variable:
T_LIST '(' { do_list_init(CLS_C); } assignment_list ')' '=' expr { do_list_end(&$$, &$7 CLS_CC); }
- | cvar '=' expr { do_end_variable_parse(BP_VAR_W CLS_CC); do_assign(&$$, &$1, &$3 CLS_CC); }
- | cvar '=' '&' w_cvar { do_end_variable_parse(BP_VAR_W CLS_CC); do_assign_ref(&$$, &$1, &$4 CLS_CC); }
+ | cvar '=' expr { do_end_variable_parse(BP_VAR_W, 0 CLS_CC); do_assign(&$$, &$1, &$3 CLS_CC); }
+ | cvar '=' '&' w_cvar { do_end_variable_parse(BP_VAR_W, 0 CLS_CC); do_assign_ref(&$$, &$1, &$4 CLS_CC); }
| T_NEW class_name { do_extended_fcall_begin(CLS_C); do_begin_new_object(&$1, &$2 CLS_CC); } ctor_arguments { do_end_new_object(&$$, &$2, &$1, &$4 CLS_CC); do_extended_fcall_end(CLS_C);}
- | cvar T_PLUS_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 CLS_CC); }
- | cvar T_MINUS_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 CLS_CC); }
- | cvar T_MUL_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 CLS_CC); }
- | cvar T_DIV_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_DIV, &$$, &$1, &$3 CLS_CC); }
- | cvar T_CONCAT_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_CONCAT, &$$, &$1, &$3 CLS_CC); }
- | cvar T_MOD_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_MOD, &$$, &$1, &$3 CLS_CC); }
- | cvar T_AND_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_BW_AND, &$$, &$1, &$3 CLS_CC); }
- | cvar T_OR_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_BW_OR, &$$, &$1, &$3 CLS_CC); }
- | cvar XT_OR_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_BW_XOR, &$$, &$1, &$3 CLS_CC); }
- | cvar T_SL_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SL, &$$, &$1, &$3 CLS_CC); }
- | cvar T_SR_EQUAL expr { do_end_variable_parse(BP_VAR_RW CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SR, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_PLUS_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_MINUS_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_MUL_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_DIV_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_DIV, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_CONCAT_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_CONCAT, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_MOD_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_MOD, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_AND_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_BW_AND, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_OR_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_BW_OR, &$$, &$1, &$3 CLS_CC); }
+ | cvar XT_OR_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_BW_XOR, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_SL_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SL, &$$, &$1, &$3 CLS_CC); }
+ | cvar T_SR_EQUAL expr { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); do_binary_assign_op(ZEND_ASSIGN_SR, &$$, &$1, &$3 CLS_CC); }
| rw_cvar T_INC { do_post_incdec(&$$, &$1, ZEND_POST_INC CLS_CC); }
| T_INC rw_cvar { do_pre_incdec(&$$, &$2, ZEND_PRE_INC CLS_CC); }
| rw_cvar T_DEC { do_post_incdec(&$$, &$1, ZEND_POST_DEC CLS_CC); }
r_cvar:
- cvar { do_end_variable_parse(BP_VAR_R CLS_CC); $$ = $1; }
+ cvar { do_end_variable_parse(BP_VAR_R, 0 CLS_CC); $$ = $1; }
;
w_cvar:
- cvar { do_end_variable_parse(BP_VAR_W CLS_CC); $$ = $1; }
+ cvar { do_end_variable_parse(BP_VAR_W, 0 CLS_CC); $$ = $1; }
;
rw_cvar:
- cvar { do_end_variable_parse(BP_VAR_RW CLS_CC); $$ = $1; }
+ cvar { do_end_variable_parse(BP_VAR_RW, 0 CLS_CC); $$ = $1; }
;
scalar_object_property:
T_STRING { $$ = $1; }
| '{' expr '}' { $$ = $2; }
- | cvar_without_objects { do_end_variable_parse(BP_VAR_R CLS_CC); $$ = $1; }
+ | cvar_without_objects { do_end_variable_parse(BP_VAR_R, 0 CLS_CC); $$ = $1; }
;
encaps_list:
- encaps_list encaps_var { do_end_variable_parse(BP_VAR_R CLS_CC); do_add_variable(&$$, &$1, &$2 CLS_CC); }
+ encaps_list encaps_var { do_end_variable_parse(BP_VAR_R, 0 CLS_CC); do_add_variable(&$$, &$1, &$2 CLS_CC); }
| encaps_list T_STRING { do_add_string(&$$, &$1, &$2 CLS_CC); }
| encaps_list T_NUM_STRING { do_add_string(&$$, &$1, &$2 CLS_CC); }
| encaps_list T_ENCAPSED_AND_WHITESPACE { do_add_string(&$$, &$1, &$2 CLS_CC); }
}
-void do_end_variable_parse(int type CLS_DC)
+void do_end_variable_parse(int type, int arg_offset CLS_DC)
{
zend_llist *fetch_list_ptr;
zend_llist_element *le;
break;
case BP_VAR_IS:
opline->opcode += 6; /* 3+3 */
+ break;
+ case BP_VAR_FUNC_ARG:
+ opline->opcode += 9; /* 3+3+3 */
+ opline->extended_value = arg_offset;
+ break;
}
le = le->next;
}
switch(op) {
case ZEND_SEND_VAR:
if (function_ptr) {
- do_end_variable_parse(BP_VAR_R CLS_CC);
+ do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
} else {
- do_end_variable_parse(BP_VAR_W CLS_CC);
+ do_end_variable_parse(BP_VAR_FUNC_ARG, offset CLS_CC);
}
break;
case ZEND_SEND_REF:
- do_end_variable_parse(BP_VAR_W CLS_CC);
+ do_end_variable_parse(BP_VAR_W, 0 CLS_CC);
break;
}
}
{
int i;
- do_end_variable_parse(BP_VAR_R CLS_CC);
+ do_end_variable_parse(BP_VAR_R, 0 CLS_CC);
for (i=1; i<num_references->u.constant.value.lval; i++) {
fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R CLS_CC);
*variable = *result;
{
zend_op *opline;
- do_end_variable_parse(BP_VAR_IS CLS_CC);
+ do_end_variable_parse(BP_VAR_IS, 0 CLS_CC);
opline = get_next_op(CG(active_op_array) CLS_CC);
opline->opcode = ZEND_ISSET_ISEMPTY;
void do_post_incdec(znode *result, znode *op1, int op CLS_DC);
void do_begin_variable_parse(CLS_D);
-void do_end_variable_parse(int type CLS_DC);
+void do_end_variable_parse(int type, int arg_offset CLS_DC);
void do_free(znode *op1 CLS_DC);
#define ZEND_EXIT 77
-/* the following 12 opcodes are 4 groups of 3 opcodes each, and must
+/* the following 12 opcodes are 5 groups of 3 opcodes each, and must
* remain in that order!
*/
#define ZEND_FETCH_R 78
#define ZEND_FETCH_IS 87
#define ZEND_FETCH_DIM_IS 88
#define ZEND_FETCH_OBJ_IS 89
+#define ZEND_FETCH_FUNC_ARG 90
+#define ZEND_FETCH_DIM_FUNC_ARG 91
+#define ZEND_FETCH_OBJ_FUNC_ARG 92
-#define ZEND_FETCH_DIM_TMP_VAR 90
-#define ZEND_FETCH_CONSTANT 91
+#define ZEND_FETCH_DIM_TMP_VAR 93
+#define ZEND_FETCH_CONSTANT 94
-#define ZEND_DECLARE_FUNCTION_OR_CLASS 92
+#define ZEND_DECLARE_FUNCTION_OR_CLASS 95
-#define ZEND_EXT_STMT 93
-#define ZEND_EXT_FCALL_BEGIN 94
-#define ZEND_EXT_FCALL_END 95
-#define ZEND_EXT_NOP 96
+#define ZEND_EXT_STMT 96
+#define ZEND_EXT_FCALL_BEGIN 97
+#define ZEND_EXT_FCALL_END 98
+#define ZEND_EXT_NOP 99
/* end of block */
#define ZEND_FETCH_STATIC 2
/* var status for backpatching */
-#define BP_VAR_R 0
-#define BP_VAR_W 1
-#define BP_VAR_RW 2
-#define BP_VAR_IS 3
-#define BP_VAR_NA 4 /* if not applicable */
+#define BP_VAR_R 0
+#define BP_VAR_W 1
+#define BP_VAR_RW 2
+#define BP_VAR_IS 3
+#define BP_VAR_NA 4 /* if not applicable */
+#define BP_VAR_FUNC_ARG 5
#define ZEND_INTERNAL_FUNCTION 1
static void zend_extension_fcall_end_handler(zend_extension *extension, zend_op_array *op_array);
+#define ARG_SHOULD_BE_SENT_BY_REF(offset) \
+ (function_being_called \
+ && function_being_called->common.arg_types \
+ && offset<=function_being_called->common.arg_types[0] \
+ && function_being_called->common.arg_types[offset]==BYREF_FORCE)
+
+
static inline zval *_get_zval_ptr(znode *node, temp_variable *Ts, int *should_free ELS_DC)
{
switch(node->op_type) {
case ZEND_FETCH_RW:
zend_fetch_var_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_RW ELS_CC);
break;
+ case ZEND_FETCH_FUNC_ARG:
+ if (ARG_SHOULD_BE_SENT_BY_REF(opline->extended_value)) {
+ /* Behave like FETCH_W */
+ zend_fetch_var_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_W ELS_CC);
+ } else {
+ /* Behave like FETCH_R */
+ zend_fetch_var_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_R ELS_CC);
+ AI_USE_PTR(Ts[opline->result.u.var].var);
+ }
+ break;
case ZEND_FETCH_IS:
zend_fetch_var_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_IS ELS_CC);
break;
case ZEND_FETCH_DIM_IS:
zend_fetch_dimension_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_IS ELS_CC);
break;
+ case ZEND_FETCH_DIM_FUNC_ARG:
+ if (ARG_SHOULD_BE_SENT_BY_REF(opline->extended_value)) {
+ /* Behave like FETCH_DIM_W */
+ zend_fetch_dimension_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_W ELS_CC);
+ } else {
+ /* Behave like FETCH_DIM_R, except for locking used for list() */
+ zend_fetch_dimension_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_R ELS_CC);
+ AI_USE_PTR(Ts[opline->result.u.var].var);
+ }
+ break;
case ZEND_FETCH_OBJ_R:
zend_fetch_property_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_R ELS_CC);
AI_USE_PTR(Ts[opline->result.u.var].var);
case ZEND_FETCH_OBJ_IS:
zend_fetch_property_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_IS ELS_CC);
break;
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ if (ARG_SHOULD_BE_SENT_BY_REF(opline->extended_value)) {
+ /* Behave like FETCH_OBJ_W */
+ zend_fetch_property_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_W ELS_CC);
+ } else {
+ zend_fetch_property_address(&opline->result, &opline->op1, &opline->op2, Ts, BP_VAR_R ELS_CC);
+ AI_USE_PTR(Ts[opline->result.u.var].var);
+ }
+ break;
case ZEND_FETCH_DIM_TMP_VAR:
zend_fetch_dimension_address_from_tmp_var(&opline->result, &opline->op1, &opline->op2, Ts ELS_CC);
AI_USE_PTR(Ts[opline->result.u.var].var);
break;
case ZEND_SEND_VAL:
if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
- && function_being_called
- && function_being_called->common.arg_types
- && opline->op2.u.opline_num<=function_being_called->common.arg_types[0]
- && function_being_called->common.arg_types[opline->op2.u.opline_num]==BYREF_FORCE) {
+ && ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num)) {
zend_error(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.u.opline_num);
}
{
break;
case ZEND_SEND_VAR:
if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
- && function_being_called
- && function_being_called->common.arg_types
- && opline->op2.u.opline_num<=function_being_called->common.arg_types[0]
- && function_being_called->common.arg_types[opline->op2.u.opline_num]==BYREF_FORCE) {
+ && ARG_SHOULD_BE_SENT_BY_REF(opline->op2.u.opline_num)) {
goto send_by_ref;
}
{