@@ -789,14 +789,10 @@ static bool can_ct_eval_func_call(zend_function *func, zend_string *name, uint32
789789/* The functions chosen here are simple to implement and either likely to affect a branch,
790790 * or just happened to be commonly used with constant operands in WP (need to test other
791791 * applications as well, of course). */
792- static inline zend_result ct_eval_func_call (
793- zend_op_array * op_array , zval * result , zend_string * name , uint32_t num_args , zval * * args ) {
792+ static inline zend_result ct_eval_func_call_ex (
793+ zend_op_array * op_array , zval * result , zend_function * func , uint32_t num_args , zval * * args ) {
794794 uint32_t i ;
795- zend_function * func = zend_hash_find_ptr (CG (function_table ), name );
796- if (!func || func -> type != ZEND_INTERNAL_FUNCTION ) {
797- return FAILURE ;
798- }
799-
795+ zend_string * name = func -> common .function_name ;
800796 if (num_args == 1 && Z_TYPE_P (args [0 ]) == IS_STRING &&
801797 zend_optimizer_eval_special_func_call (result , name , Z_STR_P (args [0 ])) == SUCCESS ) {
802798 return SUCCESS ;
@@ -855,6 +851,15 @@ static inline zend_result ct_eval_func_call(
855851 return retval ;
856852}
857853
854+ static inline zend_result ct_eval_func_call (
855+ zend_op_array * op_array , zval * result , zend_string * name , uint32_t num_args , zval * * args ) {
856+ zend_function * func = zend_hash_find_ptr (CG (function_table ), name );
857+ if (!func || func -> type != ZEND_INTERNAL_FUNCTION ) {
858+ return FAILURE ;
859+ }
860+ return ct_eval_func_call_ex (op_array , result , func , num_args , args );
861+ }
862+
858863#define SET_RESULT (op , zv ) do { \
859864 if (ssa_op->op##_def >= 0) { \
860865 set_value(scdf, ctx, ssa_op->op##_def, zv); \
@@ -1708,6 +1713,51 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
17081713 SET_RESULT_BOT (result );
17091714 break ;
17101715 }
1716+ case ZEND_FRAMELESS_ICALL_0 :
1717+ case ZEND_FRAMELESS_ICALL_1 :
1718+ case ZEND_FRAMELESS_ICALL_2 :
1719+ case ZEND_FRAMELESS_ICALL_3 : {
1720+ /* We already know it can't be evaluated, don't bother checking again */
1721+ if (ssa_op -> result_def < 0 || IS_BOT (& ctx -> values [ssa_op -> result_def ])) {
1722+ break ;
1723+ }
1724+
1725+ zval * args [3 ] = {NULL };
1726+ zend_function * func = ZEND_FLF_FUNC (opline );
1727+ uint32_t num_args = ZEND_FLF_NUM_ARGS (opline -> opcode );
1728+
1729+ switch (num_args ) {
1730+ case 3 : {
1731+ zend_op * op_data = opline + 1 ;
1732+ args [2 ] = get_op1_value (ctx , op_data , & ctx -> scdf .ssa -> ops [op_data - ctx -> scdf .op_array -> opcodes ]);
1733+ ZEND_FALLTHROUGH ;
1734+ }
1735+ case 2 :
1736+ args [1 ] = get_op2_value (ctx , opline , & ctx -> scdf .ssa -> ops [opline - ctx -> scdf .op_array -> opcodes ]);
1737+ ZEND_FALLTHROUGH ;
1738+ case 1 :
1739+ args [0 ] = get_op1_value (ctx , opline , & ctx -> scdf .ssa -> ops [opline - ctx -> scdf .op_array -> opcodes ]);
1740+ break ;
1741+ }
1742+ for (uint32_t i = 0 ; i < num_args ; i ++ ) {
1743+ if (!args [i ]) {
1744+ SET_RESULT_BOT (result );
1745+ return ;
1746+ } else if (IS_BOT (args [i ]) || IS_PARTIAL_ARRAY (args [i ])) {
1747+ SET_RESULT_BOT (result );
1748+ return ;
1749+ } else if (IS_TOP (args [i ])) {
1750+ return ;
1751+ }
1752+ }
1753+ if (ct_eval_func_call_ex (scdf -> op_array , & zv , func , num_args , args ) == SUCCESS ) {
1754+ SET_RESULT (result , & zv );
1755+ zval_ptr_dtor_nogc (& zv );
1756+ break ;
1757+ }
1758+ SET_RESULT_BOT (result );
1759+ break ;
1760+ }
17111761 default :
17121762 {
17131763 /* If we have no explicit implementation return BOT */
@@ -2155,7 +2205,13 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var,
21552205 if (opline -> opcode == ZEND_DO_ICALL ) {
21562206 removed_ops = remove_call (ctx , opline , ssa_op ) - 1 ;
21572207 } else {
2208+ bool has_op_data = opline -> opcode == ZEND_FRAMELESS_ICALL_3 ;
21582209 zend_ssa_remove_instr (ssa , opline , ssa_op );
2210+ removed_ops ++ ;
2211+ if (has_op_data ) {
2212+ zend_ssa_remove_instr (ssa , opline + 1 , ssa_op + 1 );
2213+ removed_ops ++ ;
2214+ }
21592215 }
21602216 ssa_op -> result_def = var_num ;
21612217 opline -> opcode = ZEND_QM_ASSIGN ;
@@ -2191,8 +2247,13 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var,
21912247 if (opline -> opcode == ZEND_DO_ICALL ) {
21922248 removed_ops = remove_call (ctx , opline , ssa_op );
21932249 } else {
2250+ bool has_op_data = opline -> opcode == ZEND_FRAMELESS_ICALL_3 ;
21942251 zend_ssa_remove_instr (ssa , opline , ssa_op );
21952252 removed_ops ++ ;
2253+ if (has_op_data ) {
2254+ zend_ssa_remove_instr (ssa , opline + 1 , ssa_op + 1 );
2255+ removed_ops ++ ;
2256+ }
21962257 }
21972258 }
21982259 } else if (ssa_op -> op1_def == var_num ) {
0 commit comments