From 3bbcd84e2fd96ec15df21b87aed534a0434a151e Mon Sep 17 00:00:00 2001 From: Thomas Punt Date: Tue, 12 Jan 2016 07:07:51 +0100 Subject: [PATCH] re-apply patch for github PR #1695 --- ext/standard/array.c | 86 ++++++++++++-------- ext/standard/tests/array/range_bug71132.phpt | 10 +++ ext/standard/tests/array/range_bug71197.phpt | 8 ++ 3 files changed, 72 insertions(+), 32 deletions(-) create mode 100644 ext/standard/tests/array/range_bug71132.phpt create mode 100644 ext/standard/tests/array/range_bug71197.phpt diff --git a/ext/standard/array.c b/ext/standard/array.c index 30ca0508a9..4152cc4b1f 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -81,8 +81,6 @@ #define INTERSECT_COMP_DATA_USER 1 #define INTERSECT_COMP_KEY_INTERNAL 0 #define INTERSECT_COMP_KEY_USER 1 - -#define DOUBLE_DRIFT_FIX 0.000000000000001 /* }}} */ ZEND_DECLARE_MODULE_GLOBALS(array) @@ -2061,13 +2059,25 @@ PHP_FUNCTION(array_fill_keys) } /* }}} */ -#define RANGE_CHECK_INIT_ARRAY(start, end) do { \ +#define RANGE_CHECK_DOUBLE_INIT_ARRAY(start, end) do { \ double __calc_size = ((start - end) / step) + 1; \ - if (fabs(__calc_size) >= (double)HT_MAX_SIZE) { \ - php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%0.0f end=%0.0f", start > end ? end : start, start > end ? start : end); \ + if (__calc_size >= (double)HT_MAX_SIZE) { \ + php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%0.0f end=%0.0f", end, start); \ + RETURN_FALSE; \ + } \ + size = (uint32_t)__calc_size; \ + array_init_size(return_value, size); \ + zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \ + } while (0) + +#define RANGE_CHECK_LONG_INIT_ARRAY(start, end) do { \ + zend_ulong __calc_size = (start - end) / lstep; \ + if (__calc_size >= HT_MAX_SIZE - 1) { \ + php_error_docref(NULL, E_WARNING, "The supplied range exceeds the maximum array size: start=%pd end=%pd", end, start); \ RETURN_FALSE; \ } \ - array_init_size(return_value, (uint32_t)fabs(__calc_size)); \ + size = (uint32_t)(__calc_size + 1); \ + array_init_size(return_value, size); \ zend_hash_real_init(Z_ARRVAL_P(return_value), 1); \ } while (0) @@ -2167,12 +2177,11 @@ PHP_FUNCTION(range) zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp); } } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) { - double low, high, value; - zend_long i; + double low, high; + uint32_t i, size; double_str: low = zval_get_double(zlow); high = zval_get_double(zhigh); - i = 0; if (zend_isinf(high) || zend_isinf(low)) { php_error_docref(NULL, E_WARNING, "Invalid range supplied: start=%0.0f end=%0.0f", low, high); @@ -2186,12 +2195,13 @@ double_str: goto err; } - RANGE_CHECK_INIT_ARRAY(low, high); + RANGE_CHECK_DOUBLE_INIT_ARRAY(low, high); + ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { - for (value = low; value >= (high - DOUBLE_DRIFT_FIX); value = low - (++i * step)) { - Z_DVAL(tmp) = value; - ZEND_HASH_FILL_ADD(&tmp); - } + for (i = 0; i < size; ++i) { + Z_DVAL(tmp) = low - (i * step); + ZEND_HASH_FILL_ADD(&tmp); + } } ZEND_HASH_FILL_END(); } else if (high > low) { /* Positive steps */ if (high - low < step || step <= 0) { @@ -2199,10 +2209,11 @@ double_str: goto err; } - RANGE_CHECK_INIT_ARRAY(high, low); + RANGE_CHECK_DOUBLE_INIT_ARRAY(high, low); + ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { - for (value = low; value <= (high + DOUBLE_DRIFT_FIX); value = low + (++i * step)) { - Z_DVAL(tmp) = value; + for (i = 0; i < size; ++i) { + Z_DVAL(tmp) = low + (i * step); ZEND_HASH_FILL_ADD(&tmp); } } ZEND_HASH_FILL_END(); @@ -2212,43 +2223,53 @@ double_str: 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 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(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 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(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 { 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); } } @@ -2260,7 +2281,8 @@ err: } /* }}} */ -#undef RANGE_CHECK_INIT_ARRAY +#undef RANGE_CHECK_DOUBLE_INIT_ARRAY +#undef RANGE_CHECK_LONG_INIT_ARRAY static void php_array_data_shuffle(zval *array) /* {{{ */ { diff --git a/ext/standard/tests/array/range_bug71132.phpt b/ext/standard/tests/array/range_bug71132.phpt new file mode 100644 index 0000000000..5e3bcc8f31 --- /dev/null +++ b/ext/standard/tests/array/range_bug71132.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #71132 (range function produces 2 segfaults with long integers) +--FILE-- + +--EXPECT-- +int(514) +int(514) diff --git a/ext/standard/tests/array/range_bug71197.phpt b/ext/standard/tests/array/range_bug71197.phpt new file mode 100644 index 0000000000..2031ec7c09 --- /dev/null +++ b/ext/standard/tests/array/range_bug71197.phpt @@ -0,0 +1,8 @@ +--TEST-- +Bug #71197 (range function produces another 2 segfaults with long integers) +--FILE-- + +--EXPECT-- -- 2.40.0