Fix bug #12242 with crashes in ralloc.c on OpenBSD.

src/ralloc.c (free_bloc): Don't dereference a 'heap' structure if it
 is not one of the heaps we manage.
This commit is contained in:
Eli Zaretskii 2012-08-24 11:26:46 +03:00
parent db148c21a9
commit 36c46f8e09
2 changed files with 37 additions and 13 deletions

View file

@ -1,3 +1,8 @@
2012-08-24 Eli Zaretskii <eliz@gnu.org>
* ralloc.c (free_bloc): Don't dereference a 'heap' structure if it
is not one of the heaps we manage. (Bug#12242)
2012-08-15 Chong Yidong <cyd@gnu.org>
* Version 24.2 released.

View file

@ -686,6 +686,7 @@ static void
free_bloc (bloc_ptr bloc)
{
heap_ptr heap = bloc->heap;
heap_ptr h;
if (r_alloc_freeze_level)
{
@ -715,20 +716,38 @@ free_bloc (bloc_ptr bloc)
bloc->prev->next = bloc->next;
}
/* Update the records of which blocs are in HEAP. */
if (heap->first_bloc == bloc)
/* Sometimes, 'heap' obtained from bloc->heap above is not really a
'heap' structure. It can even be beyond the current break point,
which will cause crashes when we dereference it below (see
bug#12242). Evidently, the reason is bloc allocations done while
use_relocatable_buffers was non-positive, because additional
memory we get then is not recorded in the heaps we manage. If
bloc->heap records such a "heap", we cannot (and don't need to)
update its records. So we validate the 'heap' value by making
sure it is one of the heaps we manage via the heaps linked list,
and don't touch a 'heap' that isn't found there. This avoids
accessing memory we know nothing about. */
for (h = first_heap; h != NIL_HEAP; h = h->next)
if (heap == h)
break;
if (h)
{
if (bloc->next != 0 && bloc->next->heap == heap)
heap->first_bloc = bloc->next;
else
heap->first_bloc = heap->last_bloc = NIL_BLOC;
}
if (heap->last_bloc == bloc)
{
if (bloc->prev != 0 && bloc->prev->heap == heap)
heap->last_bloc = bloc->prev;
else
heap->first_bloc = heap->last_bloc = NIL_BLOC;
/* Update the records of which blocs are in HEAP. */
if (heap->first_bloc == bloc)
{
if (bloc->next != 0 && bloc->next->heap == heap)
heap->first_bloc = bloc->next;
else
heap->first_bloc = heap->last_bloc = NIL_BLOC;
}
if (heap->last_bloc == bloc)
{
if (bloc->prev != 0 && bloc->prev->heap == heap)
heap->last_bloc = bloc->prev;
else
heap->first_bloc = heap->last_bloc = NIL_BLOC;
}
}
relinquish ();