summaryrefslogtreecommitdiff
path: root/Zend/zend_multiply.h
diff options
context:
space:
mode:
authorFlorian MARGAINE <florian@margaine.com>2014-09-20 10:09:21 +0200
committerFlorian MARGAINE <florian@margaine.com>2014-09-20 10:09:21 +0200
commit8eb7e7bf7f63f49e97f112871df47c6d6213e715 (patch)
tree24b9059118cf6abb5fe0837eaa477b4668b18435 /Zend/zend_multiply.h
parent58ed832fc99d5c5aeac7849819bbc4e0dc90d698 (diff)
parent95836a350420cabc2e8e5f5c45131fba46504a3b (diff)
downloadphp-git-8eb7e7bf7f63f49e97f112871df47c6d6213e715.tar.gz
Merge branch 'master' into issue-67910
Conflicts: README.PARAMETER_PARSING_API ext/gmp/tests/001.phpt
Diffstat (limited to 'Zend/zend_multiply.h')
-rw-r--r--Zend/zend_multiply.h138
1 files changed, 138 insertions, 0 deletions
diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h
index 11744c2699..158be22007 100644
--- a/Zend/zend_multiply.h
+++ b/Zend/zend_multiply.h
@@ -19,6 +19,9 @@
/* $Id$ */
+#ifndef ZEND_MULTIPLY_H
+#define ZEND_MULTIPLY_H
+
#if defined(__i386__) && defined(__GNUC__)
#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \
@@ -108,3 +111,138 @@
} while (0)
#endif
+
+#if defined(__GNUC__) && (defined(__native_client__) || defined(i386))
+
+static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow)
+{
+ size_t res = nmemb;
+ zend_ulong m_overflow = 0;
+
+ __asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1"
+ : "=&a"(res), "=&d" (m_overflow)
+ : "%0"(res),
+ "rm"(size),
+ "rm"(offset));
+
+ if (UNEXPECTED(m_overflow)) {
+ *overflow = 1;
+ return 0;
+ }
+ *overflow = 0;
+ return res;
+}
+
+#elif defined(__GNUC__) && defined(__x86_64__)
+
+static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow)
+{
+ size_t res = nmemb;
+ zend_ulong m_overflow = 0;
+
+#ifdef __ILP32__ /* x32 */
+# define LP_SUFF "l"
+#else /* amd64 */
+# define LP_SUFF "q"
+#endif
+
+ __asm__ ("mul" LP_SUFF " %3\n\t"
+ "add %4,%0\n\t"
+ "adc $0,%1"
+ : "=&a"(res), "=&d" (m_overflow)
+ : "%0"(res),
+ "rm"(size),
+ "rm"(offset));
+
+#undef LP_SUFF
+ if (UNEXPECTED(m_overflow)) {
+ *overflow = 1;
+ return 0;
+ }
+ *overflow = 0;
+ return res;
+}
+
+#elif defined(__GNUC__) && defined(__arm__)
+
+static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow)
+{
+ size_t res;
+ zend_ulong m_overflow;
+
+ __asm__ ("umlal %0,%1,%2,%3"
+ : "=r"(res), "=r"(m_overflow)
+ : "r"(nmemb),
+ "r"(size),
+ "0"(offset),
+ "1"(0));
+
+ if (UNEXPECTED(m_overflow)) {
+ *overflow = 1;
+ return 0;
+ }
+ *overflow = 0;
+ return res;
+}
+
+#elif defined(__GNUC__) && defined(__aarch64__)
+
+static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow)
+{
+ size_t res;
+ zend_ulong m_overflow;
+
+ __asm__ ("mul %0,%2,%3\n\tumulh %1,%2,%3\n\tadds %0,%0,%4\n\tadc %1,%1,xzr"
+ : "=&r"(res), "=&r"(m_overflow)
+ : "r"(nmemb),
+ "r"(size),
+ "r"(offset));
+
+ if (UNEXPECTED(m_overflow)) {
+ *overflow = 1;
+ return 0;
+ }
+ *overflow = 0;
+ return res;
+}
+
+#elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
+
+static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow)
+{
+ zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset;
+
+ if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) {
+ *overflow = 1;
+ return 0;
+ }
+ *overflow = 0;
+ return (size_t) res;
+}
+
+#else
+
+static zend_always_inline size_t zend_safe_address(size_t nmemb, size_t size, size_t offset, int *overflow)
+{
+ size_t res = nmemb * size + offset;
+ double _d = (double)nmemb * (double)size + (double)offset;
+ double _delta = (double)res - _d;
+
+ if (UNEXPECTED((_d + _delta ) != _d)) {
+ *overflow = 1;
+ return 0;
+ }
+ *overflow = 0;
+ return res;
+}
+#endif
+
+#endif /* ZEND_MULTIPLY_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */