Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -2067,6 +2067,17 @@ PHP_FUNCTION(array_fill_keys)
zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \
} while (0)

#define RANGE_CHECK_LONG_INIT_ARRAY(start, end) do { \
__calc_size = (end - start) / lstep; \
if (__calc_size >= HT_MAX_SIZE) { \
php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%pd end=%pd", start, end); \
RETURN_FALSE; \
} \
size = (uint32_t)(__calc_size + 1); \
array_init_size(return_value, size); \
zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \
} while (0)

/* {{{ proto array range(mixed low, mixed high[, int step])
Create an array containing the range of integers or characters from low to high (inclusive) */
PHP_FUNCTION(range)
Expand Down Expand Up @@ -2208,43 +2219,53 @@ PHP_FUNCTION(range)
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
} else {
double low, high;
zend_long lstep;
zend_long low, high;
/* lstep is a ulong so that comparisons to it don't overflow, i.e. low - high < lstep */
zend_ulong __calc_size, lstep;
uint32_t i, size;
long_str:
low = zval_get_double(zlow);
high = zval_get_double(zhigh);
lstep = (zend_long) step;
low = zval_get_long(zlow);
high = zval_get_long(zhigh);

if (step <= 0) {
err = 1;
goto err;
}

lstep = step;

Z_TYPE_INFO(tmp) = IS_LONG;
if (low > high) { /* Negative steps */
if (low - high < lstep || lstep <= 0) {
if (low - high < lstep) {
err = 1;
goto err;
}

RANGE_CHECK_INIT_ARRAY(low, high);
RANGE_CHECK_LONG_INIT_ARRAY(high, low);

ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
for (; low >= high; low -= lstep) {
Z_LVAL(tmp) = (zend_long)low;
for (i = 0; i < size; ++i) {
Z_LVAL(tmp) = low - (i * lstep);
ZEND_HASH_FILL_ADD(&tmp);
}
} ZEND_HASH_FILL_END();
} else if (high > low) { /* Positive steps */
if (high - low < lstep || lstep <= 0) {
if (high - low < lstep) {
err = 1;
goto err;
}

RANGE_CHECK_INIT_ARRAY(high, low);
RANGE_CHECK_LONG_INIT_ARRAY(low, high);

ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
for (; low <= high; low += lstep) {
Z_LVAL(tmp) = (zend_long)low;
for (i = 0; i < size; ++i) {
Z_LVAL(tmp) = low + (i * lstep);
ZEND_HASH_FILL_ADD(&tmp);
}
} ZEND_HASH_FILL_END();
} else {
array_init(return_value);
Z_LVAL(tmp) = (zend_long)low;
Z_LVAL(tmp) = low;
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
}
Expand All @@ -2257,6 +2278,7 @@ PHP_FUNCTION(range)
/* }}} */

#undef RANGE_CHECK_INIT_ARRAY
#undef RANGE_CHECK_LONG_INIT_ARRAY

static void php_array_data_shuffle(zval *array) /* {{{ */
{
Expand Down
10 changes: 10 additions & 0 deletions ext/standard/tests/array/range_bug71132.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Bug #71132 (range function produces 2 segfaults with long integers)
--FILE--
<?php
var_dump(count(range(PHP_INT_MIN + 513, PHP_INT_MIN)));
var_dump(count(range(PHP_INT_MIN, PHP_INT_MIN + 513)));
?>
--EXPECT--
int(514)
int(514)