@@ -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,9 @@ 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
1471+ || (opline -> op1_type == IS_CV && !(OP1_INFO () & MAY_BE_REF )))) {
14491472 tmp -> min = OP2_MIN_RANGE ();
14501473 tmp -> max = OP2_MAX_RANGE ();
14511474 tmp -> underflow = OP2_RANGE_UNDERFLOW ();
@@ -4879,6 +4902,174 @@ static void zend_mark_cv_references(const zend_op_array *op_array, const zend_sc
48794902 free_alloca (worklist , use_heap );
48804903}
48814904
4905+ static uint32_t zend_inference_numeric_operand_type (
4906+ const zend_op_array * op_array , const zend_ssa * ssa , const zend_op * opline ,
4907+ uint8_t op_type , znode_op op , int use )
4908+ {
4909+ if (op_type == IS_CONST ) {
4910+ uint8_t type = Z_TYPE_P (CRT_CONSTANT (op ));
4911+ return type == IS_CONSTANT_AST ? MAY_BE_ANY : 1U << type ;
4912+ }
4913+ return get_ssa_var_info (ssa , use ) & (MAY_BE_ANY | MAY_BE_UNDEF );
4914+ }
4915+
4916+ static uint32_t zend_inference_numeric_type (zend_type type )
4917+ {
4918+ uint32_t mask = ZEND_TYPE_PURE_MASK (type );
4919+ return !ZEND_TYPE_IS_COMPLEX (type ) && mask && !(mask & ~(MAY_BE_LONG | MAY_BE_DOUBLE ))
4920+ ? mask : MAY_BE_ANY ;
4921+ }
4922+
4923+ static uint32_t zend_inference_calc_numeric_type (
4924+ const zend_op_array * op_array , const zend_ssa * ssa , int var , zend_long optimization_level )
4925+ {
4926+ const zend_ssa_var * ssa_var = & ssa -> vars [var ];
4927+ if (ssa_var -> definition_phi ) {
4928+ const zend_ssa_phi * phi = ssa_var -> definition_phi ;
4929+ if (phi -> pi >= 0 ) {
4930+ uint32_t type = ssa -> var_info [phi -> sources [0 ]].type ;
4931+ return phi -> has_range_constraint ? type : type & phi -> constraint .type .type_mask ;
4932+ }
4933+ uint32_t type = 0 ;
4934+ for (uint32_t i = 0 ; i < ssa -> cfg .blocks [phi -> block ].predecessors_count ; i ++ ) {
4935+ type |= ssa -> var_info [phi -> sources [i ]].type ;
4936+ }
4937+ return type ;
4938+ }
4939+ if (ssa_var -> definition < 0 ) {
4940+ return MAY_BE_ANY ;
4941+ }
4942+
4943+ const zend_op * opline = & op_array -> opcodes [ssa_var -> definition ];
4944+ const zend_ssa_op * ssa_op = & ssa -> ops [ssa_var -> definition ];
4945+ uint32_t t1 = zend_inference_numeric_operand_type (
4946+ op_array , ssa , opline , opline -> op1_type , opline -> op1 , ssa_op -> op1_use );
4947+ uint32_t t2 = zend_inference_numeric_operand_type (
4948+ op_array , ssa , opline , opline -> op2_type , opline -> op2 , ssa_op -> op2_use );
4949+
4950+ switch (opline -> opcode ) {
4951+ case ZEND_ADD :
4952+ case ZEND_SUB :
4953+ case ZEND_MUL :
4954+ case ZEND_DIV :
4955+ case ZEND_MOD :
4956+ case ZEND_SL :
4957+ case ZEND_SR :
4958+ case ZEND_BW_OR :
4959+ case ZEND_BW_AND :
4960+ case ZEND_BW_XOR :
4961+ if (ssa_op -> result_def == var ) {
4962+ return binary_op_result_type (ssa , opline -> opcode , t1 , t2 , -1 , optimization_level );
4963+ }
4964+ break ;
4965+ case ZEND_BW_NOT :
4966+ if (ssa_op -> result_def == var && !(t1 & (MAY_BE_STRING | MAY_BE_OBJECT ))) {
4967+ return MAY_BE_LONG ;
4968+ }
4969+ break ;
4970+ case ZEND_ASSIGN_OP :
4971+ if (opline -> extended_value != ZEND_CONCAT && opline -> extended_value != ZEND_POW
4972+ && !(OP1_INFO () & MAY_BE_REF )
4973+ && (ssa_op -> op1_def == var || ssa_op -> result_def == var )) {
4974+ return binary_op_result_type (ssa , opline -> extended_value , t1 , t2 , -1 , optimization_level );
4975+ }
4976+ break ;
4977+ case ZEND_CAST :
4978+ if (ssa_op -> result_def == var ) {
4979+ return 1U << opline -> extended_value ;
4980+ }
4981+ ZEND_FALLTHROUGH ;
4982+ case ZEND_QM_ASSIGN :
4983+ case ZEND_JMP_SET :
4984+ case ZEND_COALESCE :
4985+ case ZEND_COPY_TMP :
4986+ case ZEND_SEND_VAR :
4987+ case ZEND_UNSET_DIM :
4988+ case ZEND_UNSET_OBJ :
4989+ case ZEND_OP_DATA :
4990+ return t1 ;
4991+ case ZEND_POST_INC :
4992+ case ZEND_POST_DEC :
4993+ if (ssa_op -> result_def == var ) {
4994+ return t1 ;
4995+ }
4996+ ZEND_FALLTHROUGH ;
4997+ case ZEND_PRE_INC :
4998+ case ZEND_PRE_DEC :
4999+ return (t1 & ~(MAY_BE_LONG | MAY_BE_DOUBLE )) ? MAY_BE_ANY
5000+ : t1 ? t1 | MAY_BE_DOUBLE : 0 ;
5001+ case ZEND_ASSIGN :
5002+ if (ssa_op -> op2_def == var
5003+ || (opline -> op1_type == IS_CV && !(OP1_INFO () & MAY_BE_REF ))) {
5004+ return t2 ;
5005+ }
5006+ break ;
5007+ case ZEND_RECV :
5008+ case ZEND_RECV_INIT :
5009+ if (op_array -> arg_info && opline -> op1 .num <= op_array -> num_args ) {
5010+ return zend_inference_numeric_type (op_array -> arg_info [opline -> op1 .num - 1 ].type );
5011+ }
5012+ break ;
5013+ case ZEND_STRLEN :
5014+ case ZEND_COUNT :
5015+ case ZEND_FUNC_NUM_ARGS :
5016+ return MAY_BE_LONG ;
5017+ case ZEND_DO_FCALL :
5018+ case ZEND_DO_ICALL :
5019+ case ZEND_DO_UCALL :
5020+ case ZEND_DO_FCALL_BY_NAME :
5021+ case ZEND_FRAMELESS_ICALL_0 :
5022+ case ZEND_FRAMELESS_ICALL_1 :
5023+ case ZEND_FRAMELESS_ICALL_2 :
5024+ case ZEND_FRAMELESS_ICALL_3 : {
5025+ const zend_func_info * func_info = ZEND_FUNC_INFO (op_array );
5026+ if (ssa_op -> result_def != var || !func_info || !func_info -> call_map ) {
5027+ break ;
5028+ }
5029+ const zend_call_info * call_info = func_info -> call_map [ssa_var -> definition ];
5030+ if (!call_info || call_info -> is_prototype ) {
5031+ break ;
5032+ }
5033+ const zend_function * func = call_info -> callee_func ;
5034+ if ((func -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE )
5035+ && !(func -> common .fn_flags & (ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_GENERATOR ))) {
5036+ return zend_inference_numeric_type (func -> common .arg_info [-1 ].type );
5037+ }
5038+ break ;
5039+ }
5040+ default :
5041+ break ;
5042+ }
5043+ return MAY_BE_ANY ;
5044+ }
5045+
5046+ static void zend_infer_numeric_types (
5047+ const zend_op_array * op_array , const zend_ssa * ssa , zend_long optimization_level )
5048+ {
5049+ uint32_t len = zend_bitset_len (ssa -> vars_count );
5050+ ALLOCA_FLAG (use_heap );
5051+ zend_bitset worklist = ZEND_BITSET_ALLOCA (len , use_heap );
5052+ zend_bitset_clear (worklist , len );
5053+ for (int i = op_array -> last_var ; i < ssa -> vars_count ; i ++ ) {
5054+ zend_bitset_incl (worklist , i );
5055+ }
5056+
5057+ int var ;
5058+ WHILE_WORKLIST (worklist , len , var ) {
5059+ if (ssa -> var_info [var ].type & MAY_BE_REF ) {
5060+ continue ;
5061+ }
5062+ uint32_t type = ssa -> vars [var ].alias ? MAY_BE_ANY
5063+ : zend_inference_calc_numeric_type (op_array , ssa , var , optimization_level );
5064+ type = (type & (MAY_BE_ANY | MAY_BE_UNDEF )) | ssa -> var_info [var ].type ;
5065+ if (type != ssa -> var_info [var ].type ) {
5066+ ssa -> var_info [var ].type = type ;
5067+ add_usages (op_array , ssa , worklist , var );
5068+ }
5069+ } WHILE_WORKLIST_END ();
5070+ free_alloca (worklist , use_heap );
5071+ }
5072+
48825073ZEND_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 ) /* {{{ */
48835074{
48845075 zend_ssa_var_info * ssa_var_info ;
@@ -4910,7 +5101,13 @@ ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array
49105101
49115102 zend_mark_cv_references (op_array , script , ssa );
49125103
5104+ zend_infer_numeric_types (op_array , ssa , optimization_level );
49135105 zend_infer_ranges (op_array , ssa );
5106+ for (i = op_array -> last_var ; i < ssa -> vars_count ; i ++ ) {
5107+ if (!(ssa_var_info [i ].type & MAY_BE_REF )) {
5108+ ssa_var_info [i ].type = 0 ;
5109+ }
5110+ }
49145111
49155112 if (zend_infer_types (op_array , script , ssa , optimization_level ) == FAILURE ) {
49165113 return FAILURE ;
0 commit comments