bin/79048: realloc() copies data even when the size of allocated memory decrease

Dmitrij Tejblum tejblum at yandex-team.ru
Sun Mar 20 02:10:09 PST 2005


>Number:         79048
>Category:       bin
>Synopsis:       realloc() copies data even when the size of allocated memory decrease
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Mar 20 10:10:07 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Dmitrij Tejblum
>Release:        FreeBSD 5.4-PRERELEASE i386
>Organization:
>Environment:

>Description:

If a program malloc() a large piece of memory (e.g. p = malloc(1024000)) and
then realloc() it to a smaller size (e.g. realloc(p, 512000)) realloc() 
allocate new piece of memory and copy the old piece to new one. The unnecessary
reallocation also sometimes lead to allocation failures. But it is easy to
mark the tail of old memory as free.

>How-To-Repeat:

>Fix:

--- malloc.c	Sun Mar 20 03:11:19 2005
+++ malloc.c	Sun Mar 20 03:13:15 2005
@@ -286,6 +286,7 @@ static int extend_pgdir(u_long index);
 static void *imalloc(size_t size);
 static void ifree(void *ptr);
 static void *irealloc(void *ptr, size_t size);
+static __inline void free_pages(void *ptr, u_long index, struct pginfo const *info);
 
 static void
 wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
@@ -787,10 +788,15 @@ irealloc(void *ptr, size_t size)
 
         if (!malloc_realloc && 			/* Unless we have to, */
 	  size <= osize && 			/* .. or are too small, */
-	  size > (osize - malloc_pagesize)) {	/* .. or can free a page, */
+	  size > malloc_maxsize) {		/* .. or want to allocate a chunk */
 	    if (malloc_junk)
 		memset((u_char *)ptr + size, SOME_JUNK, osize-size);
-	    return (ptr);			/* ..don't do anything else. */
+	    if (size <= (osize - malloc_pagesize)) {    /* have something to free */
+		size_t nsize = pageround(size);
+		void *fptr = (u_char *)ptr + nsize;
+		free_pages(fptr, ptr2index(fptr), MALLOC_FIRST);
+	    }
+	    return (ptr);
 	}
 
     } else if (*mp >= MALLOC_MAGIC) {		/* Chunk allocation */


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list