From 39974dd65d1399d917fda591b864bc09eb53b6c0 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 18 Feb 2018 15:13:14 +0100 Subject: [PATCH 1/2] Disable negative range inference The negative range inference implementation does not work correctly, and it's not clear right now how it can be fixed. As such, disable it entirely for now. --- ext/opcache/Optimizer/zend_inference.c | 3 ++- ext/opcache/tests/neg_range_inference.phpt | 26 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/neg_range_inference.phpt diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 1bfd395dd08..b5488c4dc00 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -39,7 +39,8 @@ #define SYM_RANGE /* Whether to handle negative range constraints */ -#define NEG_RANGE +/* Negative range inference is buggy, so disabled for now */ +#undef NEG_RANGE /* Number of warmup passes to use prior to widening */ #define RANGE_WARMUP_PASSES 16 diff --git a/ext/opcache/tests/neg_range_inference.phpt b/ext/opcache/tests/neg_range_inference.phpt new file mode 100644 index 00000000000..b3dd4a72bed --- /dev/null +++ b/ext/opcache/tests/neg_range_inference.phpt @@ -0,0 +1,26 @@ +--TEST-- +Incorrect negative range inference +--FILE-- + +--EXPECT-- +int(1) +int(1) +int(1) +int(1) +int(1) +int(0) +int(0) +int(0) +int(0) From ae837db8cfa8062d96867a4e5cf030d4b0d0f7af Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 18 Feb 2018 15:27:53 +0100 Subject: [PATCH 2/2] Handle overloaded GMP operators in type inference --- ext/opcache/Optimizer/zend_inference.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index b5488c4dc00..121d7a8ba3e 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2055,6 +2055,14 @@ static uint32_t binary_op_result_type( uint32_t tmp = 0; uint32_t t1_type = (t1 & MAY_BE_ANY) | (t1 & MAY_BE_UNDEF ? MAY_BE_NULL : 0); uint32_t t2_type = (t2 & MAY_BE_ANY) | (t2 & MAY_BE_UNDEF ? MAY_BE_NULL : 0); + + /* Handle potentially overloaded operators. + * This could be made more precise by checking the class type, if known. */ + if ((t1_type & MAY_BE_OBJECT) || (t2_type & MAY_BE_OBJECT)) { + /* This is somewhat GMP specific. */ + tmp |= MAY_BE_OBJECT | MAY_BE_FALSE | MAY_BE_RC1; + } + switch (opcode) { case ZEND_ADD: if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) { @@ -2109,7 +2117,7 @@ static uint32_t binary_op_result_type( * handling */ break; case ZEND_MOD: - tmp = MAY_BE_LONG; + tmp |= MAY_BE_LONG; /* Division by zero results in an exception, so it doesn't need any special handling */ break; case ZEND_BW_OR: @@ -2124,7 +2132,7 @@ static uint32_t binary_op_result_type( break; case ZEND_SL: case ZEND_SR: - tmp = MAY_BE_LONG; + tmp |= MAY_BE_LONG; break; case ZEND_CONCAT: case ZEND_FAST_CONCAT: @@ -2252,6 +2260,10 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t1 & (MAY_BE_ANY-MAY_BE_STRING)) { tmp |= MAY_BE_LONG; } + if (t1 & MAY_BE_OBJECT) { + /* Potentially overloaded operator. */ + tmp |= MAY_BE_OBJECT | MAY_BE_RC1; + } UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); break; case ZEND_BEGIN_SILENCE: