]> git.sur5r.net Git - openldap/commitdiff
ITS#6437, fixes for stack implementation of slap_sl_realloc():
authorHallvard Furuseth <hallvard@openldap.org>
Sat, 2 Jan 2010 21:39:46 +0000 (21:39 +0000)
committerHallvard Furuseth <hallvard@openldap.org>
Sat, 2 Jan 2010 21:39:46 +0000 (21:39 +0000)
Preserve 2*int alignment on hosts where sizeof(int) == sizeof(ber_len_t).
If realloc of last block falls back to ch_malloc, free last block properly.
Fix range check (ptr + size < endptr) --> (size < endptr - ptr).

servers/slapd/sl_malloc.c

index 6e2db09b694cc63b6728eb8a78d58ccffbe2f530..2e25abfd1ed22e984e40af0367b8cb5ced17e4a8 100644 (file)
@@ -337,7 +337,8 @@ void *
 slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
 {
        struct slab_heap *sh = ctx;
-       ber_len_t *p = (ber_len_t *)ptr, *newptr;
+       ber_len_t oldsize, *p = (ber_len_t *) ptr;
+       void *newptr;
 
        if (ptr == NULL)
                return slap_sl_malloc(size, ctx);
@@ -367,6 +368,8 @@ slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
                return NULL;
        }
 
+       oldsize = p[-1];
+
        if (sh->sh_stack) {
                /* Round up to doubleword boundary, add room for head */
                size = ((size + Align-1) & -Align) + sizeof( ber_len_t );
@@ -374,37 +377,41 @@ slap_sl_realloc(void *ptr, ber_len_t size, void *ctx)
                p--;
 
                /* Never shrink blocks */
-               if (size <= p[0]) {
-                       newptr = ptr;
+               if (size <= oldsize) {
+                       return ptr;
        
-               /* If reallocing the last block, we can grow it */
-               } else if ((char *)ptr + p[0] == sh->sh_last &&
-                       (char *)ptr + size < (char *)sh->sh_end ) {
-                       newptr = ptr;
-                       sh->sh_last = (char *)ptr + size;
-                       p[0] = size;
-                       p[size/sizeof(ber_len_t)] = size;
+               /* If reallocing the last block, try to grow it */
+               } else if ((char *) ptr + oldsize == sh->sh_last) {
+                       if (size < (char *) sh->sh_end - (char *) ptr) {
+                               sh->sh_last = (char *) ptr + size;
+                               p[0] = size;
+                               p[size/sizeof(ber_len_t)] = size;
+                               return ptr;
+                       }
 
                /* Nowhere to grow, need to alloc and copy */
                } else {
-                       newptr = slap_sl_malloc(size-sizeof(ber_len_t), ctx);
-                       AC_MEMCPY(newptr, ptr, p[0]-sizeof(ber_len_t));
-                       /* mark old region as free */
+                       /* Slight optimization of the final realloc variant */
+                       size -= sizeof(ber_len_t);
+                       oldsize -= sizeof(ber_len_t);
+                       newptr = slap_sl_malloc(size, ctx);
+                       AC_MEMCPY(newptr, ptr, oldsize);
+                       /* Not last block, can just mark old region as free */
                        p[p[0]/sizeof(ber_len_t)] |= 1;
+                       return newptr;
                }
-               return newptr;
-       } else {
-               void *newptr2;
 
-               newptr2 = slap_sl_malloc(size, ctx);
-               if (size < p[-1]) {
-                       AC_MEMCPY(newptr2, ptr, size);
-               } else {
-                       AC_MEMCPY(newptr2, ptr, p[-1]);
-               }
-               slap_sl_free(ptr, ctx);
-               return newptr2;
+               size -= sizeof(ber_len_t);
+               oldsize -= sizeof(ber_len_t);
+
+       } else if (oldsize > size) {
+               oldsize = size;
        }
+
+       newptr = slap_sl_malloc(size, ctx);
+       AC_MEMCPY(newptr, ptr, oldsize);
+       slap_sl_free(ptr, ctx);
+       return newptr;
 }
 
 void