From: Eli Zaretskii Date: Fri, 24 Aug 2012 08:26:46 +0000 (+0300) Subject: Fix bug #12242 with crashes in ralloc.c on OpenBSD. X-Git-Tag: emacs-24.2~1 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=36c46f8e09d5cb0cb8d2b19b9d3ad4826b5e163c;p=emacs.git 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. --- diff --git a/src/ChangeLog b/src/ChangeLog index 7da25a856e6..e5adbedd567 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2012-08-24 Eli Zaretskii + + * 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 * Version 24.2 released. diff --git a/src/ralloc.c b/src/ralloc.c index b1a5982574f..fdcee7c7ef4 100644 --- a/src/ralloc.c +++ b/src/ralloc.c @@ -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 ();