summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2013-12-10 12:07:46 +0100
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2013-12-11 08:50:20 +0100
commit8f1fee61e2f0c24fd46d0ecbc6ded5c68bae7d6e (patch)
tree9828626e734c737996434e7947f47d71c2a448d8
parentb1b23abc868e25f9ee083e8837c37867516ee380 (diff)
downloadphp-git-8f1fee61e2f0c24fd46d0ecbc6ded5c68bae7d6e.tar.gz
Zend: fix overflow handling bug in non-x86 fast_add_function()
The 'result' argument of fast_add_function() may alias with either of its operands (or both). Take care not to write to 'result' before reading op1 and op2.
-rw-r--r--Zend/zend_operators.h9
1 files changed, 7 insertions, 2 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index 700b578e7f..815ef27340 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -593,13 +593,18 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o
"r"(op2)
: "rax");
#else
- Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2);
+ /*
+ * 'result' may alias with op1 or op2, so we need to
+ * ensure that 'result' is not updated until after we
+ * have read the values of op1 and op2.
+ */
if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
- && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) {
+ && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) {
Z_DVAL_P(result) = (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2);
Z_TYPE_P(result) = IS_DOUBLE;
} else {
+ Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2);
Z_TYPE_P(result) = IS_LONG;
}
#endif