@@ -785,6 +785,15 @@ static bool zend_inference_calc_binary_op_range(
785785 const zend_op_array * op_array , const zend_ssa * ssa ,
786786 const zend_op * opline , const zend_ssa_op * ssa_op , uint8_t opcode , zend_ssa_range * tmp ) {
787787 zend_long op1_min , op2_min , op1_max , op2_max , t1 , t2 , t3 , t4 ;
788+ uint32_t allowed_types = MAY_BE_LONG ;
789+
790+ if (opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_DIV ) {
791+ allowed_types |= MAY_BE_DOUBLE ;
792+ }
793+ if ((OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF ) & ~allowed_types )
794+ || (OP2_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF ) & ~allowed_types )) {
795+ return 0 ;
796+ }
788797
789798 switch (opcode ) {
790799 case ZEND_ADD :
@@ -1066,6 +1075,12 @@ static bool zend_inference_calc_binary_op_range(
10661075 return 0 ;
10671076}
10681077
1078+ static bool zend_inference_has_integer_range (const zend_ssa * ssa , int var )
1079+ {
1080+ return ssa -> var_info [var ].has_range
1081+ && (ssa -> var_info [var ].type & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF )) == MAY_BE_LONG ;
1082+ }
1083+
10691084static bool zend_inference_calc_range (const zend_op_array * op_array , const zend_ssa * ssa , int var , int widening , bool narrowing , zend_ssa_range * tmp )
10701085{
10711086 uint32_t line ;
@@ -1164,7 +1179,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, const zend_
11641179 tmp -> underflow = constraint -> range .underflow && tmp -> underflow ;
11651180 tmp -> min = MAX (constraint -> range .min , tmp -> min );
11661181#ifdef SYM_RANGE
1167- } else if (narrowing && ssa -> var_info [ constraint -> min_ssa_var ]. has_range ) {
1182+ } else if (narrowing && zend_inference_has_integer_range ( ssa , constraint -> min_ssa_var ) ) {
11681183 tmp -> underflow = ssa -> var_info [constraint -> min_ssa_var ].range .underflow && tmp -> underflow ;
11691184 if (!add_will_overflow (ssa -> var_info [constraint -> min_ssa_var ].range .min , constraint -> range .min )) {
11701185 tmp -> min = MAX (ssa -> var_info [constraint -> min_ssa_var ].range .min + constraint -> range .min , tmp -> min );
@@ -1175,7 +1190,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, const zend_
11751190 tmp -> max = MIN (constraint -> range .max , tmp -> max );
11761191 tmp -> overflow = constraint -> range .overflow && tmp -> overflow ;
11771192#ifdef SYM_RANGE
1178- } else if (narrowing && ssa -> var_info [ constraint -> max_ssa_var ]. has_range ) {
1193+ } else if (narrowing && zend_inference_has_integer_range ( ssa , constraint -> max_ssa_var ) ) {
11791194 if (!add_will_overflow (ssa -> var_info [constraint -> max_ssa_var ].range .max , constraint -> range .max )) {
11801195 tmp -> max = MIN (ssa -> var_info [constraint -> max_ssa_var ].range .max + constraint -> range .max , tmp -> max );
11811196 }
@@ -1187,7 +1202,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, const zend_
11871202 tmp -> underflow = constraint -> range .underflow ;
11881203 tmp -> min = constraint -> range .min ;
11891204#ifdef SYM_RANGE
1190- } else if (narrowing && ssa -> var_info [ constraint -> min_ssa_var ]. has_range ) {
1205+ } else if (narrowing && zend_inference_has_integer_range ( ssa , constraint -> min_ssa_var ) ) {
11911206 if (add_will_overflow (ssa -> var_info [constraint -> min_ssa_var ].range .min , constraint -> range .min )) {
11921207 tmp -> underflow = 1 ;
11931208 tmp -> min = ZEND_LONG_MIN ;
@@ -1204,7 +1219,7 @@ static bool zend_inference_calc_range(const zend_op_array *op_array, const zend_
12041219 tmp -> max = constraint -> range .max ;
12051220 tmp -> overflow = constraint -> range .overflow ;
12061221#ifdef SYM_RANGE
1207- } else if (narrowing && ssa -> var_info [ constraint -> max_ssa_var ]. has_range ) {
1222+ } else if (narrowing && zend_inference_has_integer_range ( ssa , constraint -> max_ssa_var ) ) {
12081223 if (add_will_overflow (ssa -> var_info [constraint -> max_ssa_var ].range .max , constraint -> range .max )) {
12091224 tmp -> overflow = 1 ;
12101225 tmp -> max = ZEND_LONG_MAX ;
@@ -1269,7 +1284,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
12691284
12701285 case ZEND_BW_NOT :
12711286 if (ssa_op -> result_def == var ) {
1272- if (OP1_HAS_RANGE ()) {
1287+ if (OP1_HAS_RANGE ()
1288+ && (OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF )) == MAY_BE_LONG ) {
12731289 if (OP1_RANGE_UNDERFLOW () ||
12741290 OP1_RANGE_OVERFLOW ()) {
12751291 tmp -> min = ZEND_LONG_MIN ;
@@ -1297,7 +1313,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
12971313 }
12981314 } else if (ssa_op -> result_def == var ) {
12991315 if (opline -> extended_value == IS_LONG ) {
1300- if (OP1_HAS_RANGE ()) {
1316+ if (OP1_HAS_RANGE ()
1317+ && (OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF )) == MAY_BE_LONG ) {
13011318 tmp -> min = OP1_MIN_RANGE ();
13021319 tmp -> max = OP1_MAX_RANGE ();
13031320 return 1 ;
@@ -1349,7 +1366,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
13491366 break ;
13501367 case ZEND_PRE_INC :
13511368 if (ssa_op -> op1_def == var || ssa_op -> result_def == var ) {
1352- if (OP1_HAS_RANGE ()) {
1369+ if (OP1_HAS_RANGE ()
1370+ && !(OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF ) & ~(MAY_BE_LONG | MAY_BE_DOUBLE ))) {
13531371 tmp -> min = OP1_MIN_RANGE ();
13541372 tmp -> max = OP1_MAX_RANGE ();
13551373 tmp -> underflow = OP1_RANGE_UNDERFLOW ();
@@ -1368,7 +1386,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
13681386 break ;
13691387 case ZEND_PRE_DEC :
13701388 if (ssa_op -> op1_def == var || ssa_op -> result_def == var ) {
1371- if (OP1_HAS_RANGE ()) {
1389+ if (OP1_HAS_RANGE ()
1390+ && !(OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF ) & ~(MAY_BE_LONG | MAY_BE_DOUBLE ))) {
13721391 tmp -> min = OP1_MIN_RANGE ();
13731392 tmp -> max = OP1_MAX_RANGE ();
13741393 tmp -> underflow = OP1_RANGE_UNDERFLOW ();
@@ -1387,7 +1406,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
13871406 break ;
13881407 case ZEND_POST_INC :
13891408 if (ssa_op -> op1_def == var || ssa_op -> result_def == var ) {
1390- if (OP1_HAS_RANGE ()) {
1409+ if (OP1_HAS_RANGE ()
1410+ && !(OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF ) & ~(MAY_BE_LONG | MAY_BE_DOUBLE ))) {
13911411 tmp -> min = OP1_MIN_RANGE ();
13921412 tmp -> max = OP1_MAX_RANGE ();
13931413 tmp -> underflow = OP1_RANGE_UNDERFLOW ();
@@ -1409,7 +1429,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
14091429 break ;
14101430 case ZEND_POST_DEC :
14111431 if (ssa_op -> op1_def == var || ssa_op -> result_def == var ) {
1412- if (OP1_HAS_RANGE ()) {
1432+ if (OP1_HAS_RANGE ()
1433+ && !(OP1_INFO () & (MAY_BE_ANY | MAY_BE_UNDEF | MAY_BE_REF ) & ~(MAY_BE_LONG | MAY_BE_DOUBLE ))) {
14131434 tmp -> min = OP1_MIN_RANGE ();
14141435 tmp -> max = OP1_MAX_RANGE ();
14151436 tmp -> underflow = OP1_RANGE_UNDERFLOW ();
@@ -1445,7 +1466,8 @@ ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, cons
14451466 break ;
14461467 case ZEND_ASSIGN :
14471468 if (ssa_op -> op1_def == var || ssa_op -> op2_def == var || ssa_op -> result_def == var ) {
1448- if (OP2_HAS_RANGE ()) {
1469+ if (OP2_HAS_RANGE ()
1470+ && (ssa_op -> op2_def == var || !(OP1_INFO () & MAY_BE_REF ))) {
14491471 tmp -> min = OP2_MIN_RANGE ();
14501472 tmp -> max = OP2_MAX_RANGE ();
14511473 tmp -> underflow = OP2_RANGE_UNDERFLOW ();
@@ -4879,6 +4901,173 @@ static void zend_mark_cv_references(const zend_op_array *op_array, const zend_sc
48794901 free_alloca (worklist , use_heap );
48804902}
48814903
4904+ static uint32_t zend_inference_numeric_operand_type (
4905+ const zend_op_array * op_array , const zend_ssa * ssa , const zend_op * opline ,
4906+ uint8_t op_type , znode_op op , int use )
4907+ {
4908+ if (op_type == IS_CONST ) {
4909+ uint8_t type = Z_TYPE_P (CRT_CONSTANT (op ));
4910+ return type == IS_CONSTANT_AST ? MAY_BE_ANY : 1U << type ;
4911+ }
4912+ return get_ssa_var_info (ssa , use ) & (MAY_BE_ANY | MAY_BE_UNDEF );
4913+ }
4914+
4915+ static uint32_t zend_inference_numeric_type (zend_type type )
4916+ {
4917+ uint32_t mask = ZEND_TYPE_PURE_MASK (type );
4918+ return !ZEND_TYPE_IS_COMPLEX (type ) && mask && !(mask & ~(MAY_BE_LONG | MAY_BE_DOUBLE ))
4919+ ? mask : MAY_BE_ANY ;
4920+ }
4921+
4922+ static uint32_t zend_inference_calc_numeric_type (
4923+ const zend_op_array * op_array , const zend_ssa * ssa , int var , zend_long optimization_level )
4924+ {
4925+ const zend_ssa_var * ssa_var = & ssa -> vars [var ];
4926+ if (ssa_var -> definition_phi ) {
4927+ const zend_ssa_phi * phi = ssa_var -> definition_phi ;
4928+ if (phi -> pi >= 0 ) {
4929+ uint32_t type = ssa -> var_info [phi -> sources [0 ]].type ;
4930+ return phi -> has_range_constraint ? type : type & phi -> constraint .type .type_mask ;
4931+ }
4932+ uint32_t type = 0 ;
4933+ for (uint32_t i = 0 ; i < ssa -> cfg .blocks [phi -> block ].predecessors_count ; i ++ ) {
4934+ type |= ssa -> var_info [phi -> sources [i ]].type ;
4935+ }
4936+ return type ;
4937+ }
4938+ if (ssa_var -> definition < 0 ) {
4939+ return MAY_BE_ANY ;
4940+ }
4941+
4942+ const zend_op * opline = & op_array -> opcodes [ssa_var -> definition ];
4943+ const zend_ssa_op * ssa_op = & ssa -> ops [ssa_var -> definition ];
4944+ uint32_t t1 = zend_inference_numeric_operand_type (
4945+ op_array , ssa , opline , opline -> op1_type , opline -> op1 , ssa_op -> op1_use );
4946+ uint32_t t2 = zend_inference_numeric_operand_type (
4947+ op_array , ssa , opline , opline -> op2_type , opline -> op2 , ssa_op -> op2_use );
4948+
4949+ switch (opline -> opcode ) {
4950+ case ZEND_ADD :
4951+ case ZEND_SUB :
4952+ case ZEND_MUL :
4953+ case ZEND_DIV :
4954+ case ZEND_MOD :
4955+ case ZEND_SL :
4956+ case ZEND_SR :
4957+ case ZEND_BW_OR :
4958+ case ZEND_BW_AND :
4959+ case ZEND_BW_XOR :
4960+ if (ssa_op -> result_def == var ) {
4961+ return binary_op_result_type (ssa , opline -> opcode , t1 , t2 , -1 , optimization_level );
4962+ }
4963+ break ;
4964+ case ZEND_BW_NOT :
4965+ if (ssa_op -> result_def == var && !(t1 & (MAY_BE_STRING | MAY_BE_OBJECT ))) {
4966+ return MAY_BE_LONG ;
4967+ }
4968+ break ;
4969+ case ZEND_ASSIGN_OP :
4970+ if (opline -> extended_value != ZEND_CONCAT && opline -> extended_value != ZEND_POW
4971+ && !(OP1_INFO () & MAY_BE_REF )
4972+ && (ssa_op -> op1_def == var || ssa_op -> result_def == var )) {
4973+ return binary_op_result_type (ssa , opline -> extended_value , t1 , t2 , -1 , optimization_level );
4974+ }
4975+ break ;
4976+ case ZEND_CAST :
4977+ if (ssa_op -> result_def == var ) {
4978+ return 1U << opline -> extended_value ;
4979+ }
4980+ ZEND_FALLTHROUGH ;
4981+ case ZEND_QM_ASSIGN :
4982+ case ZEND_JMP_SET :
4983+ case ZEND_COALESCE :
4984+ case ZEND_COPY_TMP :
4985+ case ZEND_SEND_VAR :
4986+ case ZEND_UNSET_DIM :
4987+ case ZEND_UNSET_OBJ :
4988+ case ZEND_OP_DATA :
4989+ return t1 ;
4990+ case ZEND_POST_INC :
4991+ case ZEND_POST_DEC :
4992+ if (ssa_op -> result_def == var ) {
4993+ return t1 ;
4994+ }
4995+ ZEND_FALLTHROUGH ;
4996+ case ZEND_PRE_INC :
4997+ case ZEND_PRE_DEC :
4998+ return (t1 & ~(MAY_BE_LONG | MAY_BE_DOUBLE )) ? MAY_BE_ANY
4999+ : t1 ? t1 | MAY_BE_DOUBLE : 0 ;
5000+ case ZEND_ASSIGN :
5001+ if (ssa_op -> op2_def == var || !(OP1_INFO () & MAY_BE_REF )) {
5002+ return t2 ;
5003+ }
5004+ break ;
5005+ case ZEND_RECV :
5006+ case ZEND_RECV_INIT :
5007+ if (op_array -> arg_info && opline -> op1 .num <= op_array -> num_args ) {
5008+ return zend_inference_numeric_type (op_array -> arg_info [opline -> op1 .num - 1 ].type );
5009+ }
5010+ break ;
5011+ case ZEND_STRLEN :
5012+ case ZEND_COUNT :
5013+ case ZEND_FUNC_NUM_ARGS :
5014+ return MAY_BE_LONG ;
5015+ case ZEND_DO_FCALL :
5016+ case ZEND_DO_ICALL :
5017+ case ZEND_DO_UCALL :
5018+ case ZEND_DO_FCALL_BY_NAME :
5019+ case ZEND_FRAMELESS_ICALL_0 :
5020+ case ZEND_FRAMELESS_ICALL_1 :
5021+ case ZEND_FRAMELESS_ICALL_2 :
5022+ case ZEND_FRAMELESS_ICALL_3 : {
5023+ const zend_func_info * func_info = ZEND_FUNC_INFO (op_array );
5024+ if (ssa_op -> result_def != var || !func_info || !func_info -> call_map ) {
5025+ break ;
5026+ }
5027+ const zend_call_info * call_info = func_info -> call_map [ssa_var -> definition ];
5028+ if (!call_info || call_info -> is_prototype ) {
5029+ break ;
5030+ }
5031+ const zend_function * func = call_info -> callee_func ;
5032+ if ((func -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE )
5033+ && !(func -> common .fn_flags & (ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_GENERATOR ))) {
5034+ return zend_inference_numeric_type (func -> common .arg_info [-1 ].type );
5035+ }
5036+ break ;
5037+ }
5038+ default :
5039+ break ;
5040+ }
5041+ return MAY_BE_ANY ;
5042+ }
5043+
5044+ static void zend_infer_numeric_types (
5045+ const zend_op_array * op_array , const zend_ssa * ssa , zend_long optimization_level )
5046+ {
5047+ uint32_t len = zend_bitset_len (ssa -> vars_count );
5048+ ALLOCA_FLAG (use_heap );
5049+ zend_bitset worklist = ZEND_BITSET_ALLOCA (len , use_heap );
5050+ zend_bitset_clear (worklist , len );
5051+ for (int i = op_array -> last_var ; i < ssa -> vars_count ; i ++ ) {
5052+ zend_bitset_incl (worklist , i );
5053+ }
5054+
5055+ int var ;
5056+ WHILE_WORKLIST (worklist , len , var ) {
5057+ if (ssa -> var_info [var ].type & MAY_BE_REF ) {
5058+ continue ;
5059+ }
5060+ uint32_t type = ssa -> vars [var ].alias ? MAY_BE_ANY
5061+ : zend_inference_calc_numeric_type (op_array , ssa , var , optimization_level );
5062+ type = (type & (MAY_BE_ANY | MAY_BE_UNDEF )) | ssa -> var_info [var ].type ;
5063+ if (type != ssa -> var_info [var ].type ) {
5064+ ssa -> var_info [var ].type = type ;
5065+ add_usages (op_array , ssa , worklist , var );
5066+ }
5067+ } WHILE_WORKLIST_END ();
5068+ free_alloca (worklist , use_heap );
5069+ }
5070+
48825071ZEND_API zend_result zend_ssa_inference (zend_arena * * arena , const zend_op_array * op_array , const zend_script * script , zend_ssa * ssa , zend_long optimization_level ) /* {{{ */
48835072{
48845073 zend_ssa_var_info * ssa_var_info ;
@@ -4910,7 +5099,13 @@ ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array
49105099
49115100 zend_mark_cv_references (op_array , script , ssa );
49125101
5102+ zend_infer_numeric_types (op_array , ssa , optimization_level );
49135103 zend_infer_ranges (op_array , ssa );
5104+ for (i = op_array -> last_var ; i < ssa -> vars_count ; i ++ ) {
5105+ if (!(ssa_var_info [i ].type & MAY_BE_REF )) {
5106+ ssa_var_info [i ].type = 0 ;
5107+ }
5108+ }
49145109
49155110 if (zend_infer_types (op_array , script , ssa , optimization_level ) == FAILURE ) {
49165111 return FAILURE ;
0 commit comments