]> granicus.if.org Git - php/commitdiff
Make string size calculation in chunk_split more precise
authorNikita Popov <nikita.ppv@gmail.com>
Sun, 25 Aug 2019 13:32:33 +0000 (15:32 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Sun, 25 Aug 2019 13:34:37 +0000 (15:34 +0200)
The +1 on the string length is unnecessary, as we need the string
length without trailing NUL byte here.

The +1 on the chunks is only necessary if there is a rest. If the
string devides into chunks exactly, we don't need an extra chunk.

This makes the allocations exactly as large as it needs to be.

ext/standard/string.c

index 157bc02a1c808bb2ad181a4824733bd76420a6f7..362ff75df147b915a1875c71f14a3d28fc666334 100644 (file)
@@ -2131,26 +2131,28 @@ static zend_string *php_chunk_split(const char *src, size_t srclen, const char *
 {
        char *q;
        const char *p;
-       size_t chunks; /* complete chunks! */
+       size_t chunks;
        size_t restlen;
        size_t out_len;
        zend_string *dest;
 
        chunks = srclen / chunklen;
        restlen = srclen - chunks * chunklen; /* srclen % chunklen */
-
-       if (chunks > INT_MAX - 1) {
-               return NULL;
+       if (restlen) {
+               /* We want chunks to be rounded up rather than rounded down.
+                * Increment can't overflow because chunks <= SIZE_MAX/2 at this point. */
+               chunks++;
        }
-       out_len = chunks + 1;
+
+       out_len = chunks;
        if (endlen !=0 && out_len > INT_MAX/endlen) {
                return NULL;
        }
        out_len *= endlen;
-       if (out_len > INT_MAX - srclen - 1) {
+       if (out_len > INT_MAX - srclen) {
                return NULL;
        }
-       out_len += srclen + 1;
+       out_len += srclen;
 
        dest = zend_string_alloc(out_len * sizeof(char), 0);
 
@@ -2170,7 +2172,7 @@ static zend_string *php_chunk_split(const char *src, size_t srclen, const char *
        }
 
        *q = '\0';
-       ZSTR_LEN(dest) = q - ZSTR_VAL(dest);
+       ZEND_ASSERT(q - ZSTR_VAL(dest) == ZSTR_LEN(dest));
 
        return dest;
 }