From: Dmitry Stogov Date: Thu, 18 Sep 2014 09:31:25 +0000 (+0400) Subject: Expose zend_safe_address() and use it in zend_arena_calloc() X-Git-Tag: POST_NATIVE_TLS_MERGE^2~231 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e439349e589e122487131d845f6d3c4d4229d758;p=php Expose zend_safe_address() and use it in zend_arena_calloc() --- diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 8b6a105e98..751497978a 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -57,6 +57,7 @@ #include "zend_alloc.h" #include "zend_globals.h" #include "zend_operators.h" +#include "zend_multiply.h" #ifdef HAVE_SIGNAL_H # include @@ -2121,124 +2122,17 @@ ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE return zend_mm_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } -#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) - -static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) +static zend_always_inline size_t safe_address(size_t nmemb, size_t size, size_t offset) { - size_t res = nmemb; - zend_ulong overflow = 0; - - __asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1" - : "=&a"(res), "=&d" (overflow) - : "%0"(res), - "rm"(size), - "rm"(offset)); + int overflow; + size_t ret = zend_safe_address(nmemb, size, offset, &overflow); if (UNEXPECTED(overflow)) { zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); return 0; } - return res; -} - -#elif defined(__GNUC__) && defined(__x86_64__) - -static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) -{ - size_t res = nmemb; - zend_ulong 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" (overflow) - : "%0"(res), - "rm"(size), - "rm"(offset)); - -#undef LP_SUFF - if (UNEXPECTED(overflow)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return res; -} - -#elif defined(__GNUC__) && defined(__arm__) - -static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) -{ - size_t res; - zend_ulong overflow; - - __asm__ ("umlal %0,%1,%2,%3" - : "=r"(res), "=r"(overflow) - : "r"(nmemb), - "r"(size), - "0"(offset), - "1"(0)); - - if (UNEXPECTED(overflow)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return res; -} - -#elif defined(__GNUC__) && defined(__aarch64__) - -static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) -{ - size_t res; - zend_ulong overflow; - - __asm__ ("mul %0,%2,%3\n\tumulh %1,%2,%3\n\tadds %0,%0,%4\n\tadc %1,%1,xzr" - : "=&r"(res), "=&r"(overflow) - : "r"(nmemb), - "r"(size), - "r"(offset)); - - if (UNEXPECTED(overflow)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return res; -} - -#elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64) - -static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) -{ - zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset; - - if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return (size_t) res; -} - -#else - -static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) -{ - size_t res = nmemb * size + offset; - double _d = (double)nmemb * (double)size + (double)offset; - double _delta = (double)res - _d; - - if (UNEXPECTED((_d + _delta ) != _d)) { - zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); - return 0; - } - return res; + return ret; } -#endif ZEND_API void* ZEND_FASTCALL _safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) diff --git a/Zend/zend_arena.h b/Zend/zend_arena.h index 96e18a6910..64fde19619 100644 --- a/Zend/zend_arena.h +++ b/Zend/zend_arena.h @@ -80,14 +80,14 @@ static zend_always_inline void* zend_arena_alloc(zend_arena **arena_ptr, size_t static zend_always_inline void* zend_arena_calloc(zend_arena **arena_ptr, size_t count, size_t unit_size) { - zend_long overflow; - double d; + int overflow; size_t size; void *ret; - (void)d; - ZEND_SIGNED_MULTIPLY_LONG(unit_size, count, size, d, overflow); - ZEND_ASSERT(overflow == 0); + size = zend_safe_address(unit_size, count, 0, &overflow); + if (UNEXPECTED(overflow)) { + zend_error(E_ERROR, "Possible integer overflow in zend_arena_calloc() (%zu * %zu)", unit_size, count); + } ret = zend_arena_alloc(arena_ptr, size); memset(ret, 0, size); return ret; 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: + */