Subject: Bug in gnumalloc
To: None <tech-userlevel@netbsd.org>
From: Stuart Brooks <Stuartb@cat.co.za>
List: tech-userlevel
Date: 06/07/2002 13:40:39
I have picked up what I am pretty sure is a bug in the gnumalloc library. It
is reproducable and I have identified the point in the code at which it
occurs. I can't believe it hasn't been seen before.

If this is not the correct place to post, please let me know and I will
forward it accordingly. In any case, what would be the best course of
action. A description of the bug follows below ...

Stuart

--------------------

In the malloc function (malloc.c in /usr/src/gnu/lib/libmalloc/) the
following code fragment exists ....

>>>>

/* Need to get more from the system.  Check to see if
   the new core will be contiguous with the final free
   block; if so we don't need to get as much.  */

...

1: if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
2:    (*__morecore) (0) == ADDRESS (block + lastblocks) &&
3:    (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
4: {
5:   _heapinfo[block].free.size = blocks;
6:   _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
7:   continue;
8: }

>>>>

The purpose of it is to allocate more core memory for the heap in the
special case where the end of the existing heap consists of a free block. So
obviously the intention is to allocate more core memory and combine it with
the free block at the end of the old heap.

However (and herein lies the problem) the call to morecore might need to add
space for new indices, and this results in the old indices being freed via a
call to _free_internal() in free.c. This is not normally a problem, except
in the case where the old indices lay directly before the last free block.
If this is the case, then _free_internal frees the old indices and combines
it with last free block to produces a *new* free block whose starting point
is no longer _heapinfo[block] (line 5: above). This means that we think we
are updating part of the free chain, whereas in actual fact we are updating
a now unused block.

This can result in memory which is assigned overlapping supposedly free
blocks. I have 2 examples below...


Example 1.
Normal operation where the indices are NOT just before the last free block.
This one works fine:

Initial:
 |--------|--INDICES--|----|--FREE--|

After the morecore

|-------------------------|--FREE--|........UNSET..........|--NEW_INDICES--|

After updating the free chain in 5:

|-------------------------|------------FREE----------------|--NEW_INDICES--|


Example 2.
Problem operation, indices are directly before the last free block. The bug.

Initial:
 |-------------|--INDICES--|--FREE--|

After the morecore

|-------------|--FREE--------------|........UNSET..........|--NEW_INDICES--|
                            ^
                            This is the point referenced in line 5:

Final, after memory has been assigned (the assigned memory and the free
space overlap) :

|-------------|--FREE--------------|........UNSET..........|--NEW_INDICES--|
                           |-----------memory assigned------|



I have code which performs 2 consecutive mallocs and the memory allocated
overlaps, but from looking at the gnumalloc source it appears that this is
the problem, what should I do about it?