Skip to content

Commit cc3ecb9

Browse files
committed
Store long step and see if float step is compatible with long
This changes the values of e.g. range(1, 5, 2.0); from being floats to ints.
1 parent f807414 commit cc3ecb9

File tree

2 files changed

+37
-29
lines changed

2 files changed

+37
-29
lines changed

ext/standard/array.c

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,8 +2655,8 @@ PHP_FUNCTION(array_fill_keys)
26552655
zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); \
26562656
} while (0)
26572657

2658-
#define RANGE_CHECK_LONG_INIT_ARRAY(start, end) do { \
2659-
zend_ulong __calc_size = ((zend_ulong) start - end) / lstep; \
2658+
#define RANGE_CHECK_LONG_INIT_ARRAY(start, end, _step) do { \
2659+
zend_ulong __calc_size = ((zend_ulong) start - end) / (_step); \
26602660
if (__calc_size >= HT_MAX_SIZE - 1) { \
26612661
zend_value_error(\
26622662
"The supplied range exceeds the maximum array size: start=" ZEND_LONG_FMT " end=" ZEND_LONG_FMT, end, start); \
@@ -2673,6 +2673,7 @@ PHP_FUNCTION(range)
26732673
zval *zlow, *zhigh, *user_step = NULL, tmp;
26742674
bool err = 0, is_step_double = false;
26752675
double step_double = 1.0;
2676+
zend_long step = 1;
26762677

26772678
ZEND_PARSE_PARAMETERS_START(2, 3)
26782679
Z_PARAM_NUMBER_OR_STR(zlow)
@@ -2684,25 +2685,32 @@ PHP_FUNCTION(range)
26842685
if (user_step) {
26852686
if (UNEXPECTED(Z_TYPE_P(user_step) == IS_DOUBLE)) {
26862687
step_double = Z_DVAL_P(user_step);
2687-
is_step_double = true;
2688+
/* We only want positive step values. */
2689+
if (step_double < 0.0) {
2690+
step_double *= -1;
2691+
}
2692+
step = zend_dval_to_lval(step_double);
2693+
if (!zend_is_long_compatible(step_double, step)) {
2694+
is_step_double = true;
2695+
}
26882696
} else {
2689-
step_double = (double) Z_LVAL_P(user_step);
2697+
step = Z_LVAL_P(user_step);
2698+
/* We only want positive step values. */
2699+
if (step < 0) {
2700+
step *= -1;
2701+
}
2702+
step_double = (double) step;
26902703
}
26912704
if (step_double == 0.0) {
26922705
zend_argument_value_error(3, "cannot be 0");
26932706
RETURN_THROWS();
26942707
}
2695-
/* We only want positive step values. */
2696-
if (step_double < 0.0) {
2697-
step_double *= -1;
2698-
}
26992708
}
27002709

27012710
/* If the range is given as strings, generate an array of characters. */
27022711
if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
27032712
int type1, type2;
27042713
unsigned char low, high;
2705-
zend_long lstep = (zend_long) step_double;
27062714

27072715
type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
27082716
type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
@@ -2717,34 +2725,34 @@ PHP_FUNCTION(range)
27172725
high = (unsigned char)Z_STRVAL_P(zhigh)[0];
27182726

27192727
if (low > high) { /* Negative Steps */
2720-
if (low - high < lstep) {
2728+
if (low - high < step) {
27212729
err = 1;
27222730
goto err;
27232731
}
27242732
/* Initialize the return_value as an array. */
2725-
array_init_size(return_value, (uint32_t)(((low - high) / lstep) + 1));
2733+
array_init_size(return_value, (uint32_t)(((low - high) / step) + 1));
27262734
zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
27272735
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2728-
for (; low >= high; low -= (unsigned int)lstep) {
2736+
for (; low >= high; low -= (unsigned int)step) {
27292737
ZEND_HASH_FILL_SET_INTERNED_STR(ZSTR_CHAR(low));
27302738
ZEND_HASH_FILL_NEXT();
2731-
if (((signed int)low - lstep) < 0) {
2739+
if (((signed int)low - step) < 0) {
27322740
break;
27332741
}
27342742
}
27352743
} ZEND_HASH_FILL_END();
27362744
} else if (high > low) { /* Positive Steps */
2737-
if (high - low < lstep) {
2745+
if (high - low < step) {
27382746
err = 1;
27392747
goto err;
27402748
}
2741-
array_init_size(return_value, (uint32_t)(((high - low) / lstep) + 1));
2749+
array_init_size(return_value, (uint32_t)(((high - low) / step) + 1));
27422750
zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
27432751
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
2744-
for (; low <= high; low += (unsigned int)lstep) {
2752+
for (; low <= high; low += (unsigned int)step) {
27452753
ZEND_HASH_FILL_SET_INTERNED_STR(ZSTR_CHAR(low));
27462754
ZEND_HASH_FILL_NEXT();
2747-
if (((signed int)low + lstep) > 255) {
2755+
if (((signed int)low + step) > 255) {
27482756
break;
27492757
}
27502758
}
@@ -2801,40 +2809,40 @@ PHP_FUNCTION(range)
28012809
}
28022810
} else {
28032811
zend_long low, high;
2804-
/* lstep is a zend_ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
2805-
zend_ulong lstep;
2812+
/* unsigned_step is a zend_ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
2813+
zend_ulong unsigned_step;
28062814
uint32_t i, size;
28072815
long_str:
28082816
low = zval_get_long(zlow);
28092817
high = zval_get_long(zhigh);
28102818

2811-
lstep = (zend_ulong)step_double;
2819+
unsigned_step = (zend_ulong)step;
28122820

28132821
if (low > high) { /* Negative steps */
2814-
if ((zend_ulong)low - high < lstep) {
2822+
if ((zend_ulong)low - high < unsigned_step) {
28152823
err = 1;
28162824
goto err;
28172825
}
28182826

2819-
RANGE_CHECK_LONG_INIT_ARRAY(low, high);
2827+
RANGE_CHECK_LONG_INIT_ARRAY(low, high, unsigned_step);
28202828

28212829
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
28222830
for (i = 0; i < size; ++i) {
2823-
ZEND_HASH_FILL_SET_LONG(low - (i * lstep));
2831+
ZEND_HASH_FILL_SET_LONG(low - (i * unsigned_step));
28242832
ZEND_HASH_FILL_NEXT();
28252833
}
28262834
} ZEND_HASH_FILL_END();
28272835
} else if (high > low) { /* Positive steps */
2828-
if ((zend_ulong)high - low < lstep) {
2836+
if ((zend_ulong)high - low < unsigned_step) {
28292837
err = 1;
28302838
goto err;
28312839
}
28322840

2833-
RANGE_CHECK_LONG_INIT_ARRAY(high, low);
2841+
RANGE_CHECK_LONG_INIT_ARRAY(high, low, unsigned_step);
28342842

28352843
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
28362844
for (i = 0; i < size; ++i) {
2837-
ZEND_HASH_FILL_SET_LONG(low + (i * lstep));
2845+
ZEND_HASH_FILL_SET_LONG(low + (i * unsigned_step));
28382846
ZEND_HASH_FILL_NEXT();
28392847
}
28402848
} ZEND_HASH_FILL_END();

ext/standard/tests/array/range/range_inputs_int_with_float_step.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ var_dump( range(1, 5, 2.0) );
99
--EXPECT--
1010
array(3) {
1111
[0]=>
12-
float(1)
12+
int(1)
1313
[1]=>
14-
float(3)
14+
int(3)
1515
[2]=>
16-
float(5)
16+
int(5)
1717
}

0 commit comments

Comments
 (0)