]> granicus.if.org Git - php/commitdiff
Add ARM optimized versions of safe_address()
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Tue, 5 Feb 2013 11:14:55 +0000 (12:14 +0100)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Tue, 5 Feb 2013 11:14:55 +0000 (12:14 +0100)
The function safe_address() uses inline assembler to detect
overflow in size/offset calculations, as detecting this in
plain C is a lot more work.

Zend/zend_alloc.c

index 1cc2c678334f96b13e0e1ee656e11a9c054a59b9..fea94dec3118622d42bd9cc7c43955469dceb805 100644 (file)
@@ -2494,6 +2494,46 @@ static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
         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;
+        unsigned long overflow;
+
+        __asm__ ("umull %0,%1,%2,%3\n\tadds %0,%4\n\tadc %1,%1"
+             : "=&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 defined(__GNUC__) && defined(__aarch64__)
+
+static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
+{
+        size_t res;
+        unsigned long overflow;
+
+        __asm__ ("mul %0,%2,%3\n\tumulh %1,%2,%3\n\tadds %0,%0,%4\n\tadc %1,%1,%1"
+             : "=&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)