summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.h
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r--Zend/zend_operators.h73
1 files changed, 65 insertions, 8 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index a404b79c1c..7fc11cc144 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -35,13 +35,10 @@
#include <ieeefp.h>
#endif
+#include "zend_portability.h"
#include "zend_strtod.h"
#include "zend_multiply.h"
-#if 0&&HAVE_BCMATH
-#include "ext/bcmath/libbcmath/src/bcmath.h"
-#endif
-
#define LONG_SIGN_MASK (((zend_long)1) << (8*sizeof(zend_long)-1))
BEGIN_EXTERN_C()
@@ -444,7 +441,23 @@ ZEND_API void zend_update_current_locale(void);
static zend_always_inline void fast_long_increment_function(zval *op1)
{
-#if defined(__GNUC__) && defined(__i386__)
+#if PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+ long lresult;
+ if (UNEXPECTED(__builtin_saddl_overflow(Z_LVAL_P(op1), 1, &lresult))) {
+ /* switch to double */
+ ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
+ } else {
+ Z_LVAL_P(op1) = lresult;
+ }
+#elif PHP_HAVE_BUILTIN_SADDLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
+ long long llresult;
+ if (UNEXPECTED(__builtin_saddll_overflow(Z_LVAL_P(op1), 1, &llresult))) {
+ /* switch to double */
+ ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
+ } else {
+ Z_LVAL_P(op1) = llresult;
+ }
+#elif defined(__GNUC__) && defined(__i386__)
__asm__(
"incl (%0)\n\t"
"jno 0f\n\t"
@@ -482,7 +495,23 @@ static zend_always_inline void fast_long_increment_function(zval *op1)
static zend_always_inline void fast_long_decrement_function(zval *op1)
{
-#if defined(__GNUC__) && defined(__i386__)
+#if PHP_HAVE_BUILTIN_SSUBL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+ long lresult;
+ if (UNEXPECTED(__builtin_ssubl_overflow(Z_LVAL_P(op1), 1, &lresult))) {
+ /* switch to double */
+ ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
+ } else {
+ Z_LVAL_P(op1) = lresult;
+ }
+#elif PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
+ long long llresult;
+ if (UNEXPECTED(__builtin_ssubll_overflow(Z_LVAL_P(op1), 1, &llresult))) {
+ /* switch to double */
+ ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
+ } else {
+ Z_LVAL_P(op1) = llresult;
+ }
+#elif defined(__GNUC__) && defined(__i386__)
__asm__(
"decl (%0)\n\t"
"jno 0f\n\t"
@@ -520,7 +549,21 @@ static zend_always_inline void fast_long_decrement_function(zval *op1)
static zend_always_inline void fast_long_add_function(zval *result, zval *op1, zval *op2)
{
-#if defined(__GNUC__) && defined(__i386__) \
+#if PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+ long lresult;
+ if (UNEXPECTED(__builtin_saddl_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, lresult);
+ }
+#elif PHP_HAVE_BUILTIN_SADDLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
+ long long llresult;
+ if (UNEXPECTED(__builtin_saddll_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, llresult);
+ }
+#elif defined(__GNUC__) && defined(__i386__) \
&& !(4 == __GNUC__ && 8 == __GNUC_MINOR__) \
&& !(4 == __GNUC__ && 9 == __GNUC_MINOR__ && (defined(__PIC__) || defined(__PIE__)))
/* Position-independent builds fail with gcc-4.9.x */
@@ -609,7 +652,21 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o
static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, zval *op2)
{
-#if defined(__GNUC__) && defined(__i386__) && \
+#if PHP_HAVE_BUILTIN_SSUBL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+ long lresult;
+ if (UNEXPECTED(__builtin_ssubl_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, lresult);
+ }
+#elif PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
+ long long llresult;
+ if (UNEXPECTED(__builtin_ssubll_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, llresult);
+ }
+#elif defined(__GNUC__) && defined(__i386__) && \
!(4 == __GNUC__ && 8 == __GNUC_MINOR__) && \
!(4 == __GNUC__ && 9 == __GNUC_MINOR__ && (defined(__PIC__) || defined(__PIE__)))
/* Position-independent builds fail with gcc-4.9.x */