--- Begin Message ---
Subject: |
Malloc dereferences a NULL pointer when it runs out of memory |
Date: |
Mon, 10 Jun 2002 18:58:13 -0400 |
>Submitter-Id: net
>Originator: Michael Meissner
>Organization:
Michael Meissner, Red Hat, Inc.
3 Lan Drive, Westford, Massachusetts 01886, USA
Work: address@hidden phone: +1 978-692-3113 x23241
>
>Confidential: no
>Synopsis: Malloc dereferences a NULL pointer when it runs out of memory
>Severity: serious
>Priority: high
>Category: libc
>Class: sw-bug
>Release: libc-2.2.90
>Environment:
Host type: i686-pc-linux-gnu
System: Linux hungry-tiger 2.4.9-31 #1 Tue Feb 26 07:11:02 EST 2002 i686 unknown
Architecture: i686
Addons: linuxthreads
Build CC: gcc
Compiler version: 2.96 20000731 (Red Hat Linux 7.1 2.96-98)
Kernel headers: 2.4.9-31
Symbol versioning: yes
Build static: yes
Build shared: yes
Build pic-default: no
Build profile: yes
Build omitfp: no
Build bounded: no
Build static-nss: no
Stdio: @stdio@
>Description:
If you allocate enough memory so that eventually malloc would normally return
NULL because it can't allocate any more memory, the current version of malloc
from cvs will cause a segmentation violation (on systems that trap access to
NULL). This is due to the fact that new_heap returns NULL when it can't
allocate a new heap. The January 29th rewrite of malloc introduced the bug.
>How-To-Repeat:
Compile and run the following program:
#include <stdio.h>
#include <stdlib.h>
/* Test program to get malloc to crash if it can't allocate enough
memory. */
#ifndef SIZE
#define SIZE ((1024 * 1024 * 64) - (8 * sizeof (void *)))
#endif
main (int argc, char *argv[])
{
void *ptr;
unsigned long max_mem = 0;
setvbuf (stdout, (char *)0, _IOLBF, BUFSIZ);
do
{
ptr = malloc ((size_t)SIZE);
if (ptr)
max_mem += SIZE;
printf("\nmalloc pointer: %12lu (0x%.8lx)\n", (unsigned
long)ptr, (unsigned long)ptr);
}
while (ptr);
printf ("\nDone, allocated %12lu (0x%.8lx) bytes\n", max_mem,
max_mem);
return 0;
}
>Fix:
The following patch that I wrote fixes the problem.
*** libc/malloc/malloc.c.~1~ Tue May 14 17:51:33 2002
--- libc/malloc/malloc.c Mon Jun 10 18:28:11 2002
*************** static Void_t* sYSMALLOc(nb, av) INTERNA
*** 2764,2779 ****
} else {
/* A new heap must be created. */
heap = new_heap(nb + (MINSIZE + sizeof(*heap)), mp_.top_pad);
! if(heap) {
! heap->ar_ptr = av;
! heap->prev = old_heap;
! av->system_mem += heap->size;
! arena_mem += heap->size;
#if 0
! if((unsigned long)(mmapped_mem + arena_mem + sbrked_mem) >
max_total_mem)
! max_total_mem = mmapped_mem + arena_mem + sbrked_mem;
#endif
- }
/* Set up the new top. */
top(av) = chunk_at_offset(heap, sizeof(*heap));
--- 2764,2780 ----
} else {
/* A new heap must be created. */
heap = new_heap(nb + (MINSIZE + sizeof(*heap)), mp_.top_pad);
! if (!heap)
! return 0;
!
! heap->ar_ptr = av;
! heap->prev = old_heap;
! av->system_mem += heap->size;
! arena_mem += heap->size;
#if 0
! if((unsigned long)(mmapped_mem + arena_mem + sbrked_mem) >
max_total_mem)
! max_total_mem = mmapped_mem + arena_mem + sbrked_mem;
#endif
/* Set up the new top. */
top(av) = chunk_at_offset(heap, sizeof(*heap));
--- End Message ---