This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Segfault during stack unwinding & patch (2nd try)
- To: egcs at cygnus dot com
- Subject: Segfault during stack unwinding & patch (2nd try)
- From: Kriang Lerdsuwanakij <lerdsuwa at scf-fs dot usc dot edu>
- Date: Mon, 09 Mar 1998 22:14:05 -0800
Hi
I played with exception handling and found that egcs has trouble dealing
with bad_alloc. FDE functions allocate memory and build sorted array of
pointers to FDEs but fail to test whether malloc(...) returns NULL.
This causes segmentation fault when we only have a limit amount of
memory, such as when bad_alloc is thrown.
Here I add a fallback function that uses a slower sequential search when
the original method fails. The solution is not 100% perfect though
as __eh_alloc and __cp_push_exception still need to allocate a couple
bytes.
Below are a test program and a patch. You may have to tweak the number
in the test program so that __eh_alloc succeeds but FDE code fails. :)
--Kriang
=======================================================================
// Test program:
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <new>
int main() {
struct rlimit r;
r.rlim_cur = 10500;
r.rlim_max = 10500;
if (setrlimit(RLIMIT_DATA,&r)) {
printf("test not working\n");
return 3;
}
char *c;
try {
for ( ; ; )
c = new char[1000];
}
catch (bad_alloc &) {
printf("ok\n");
return 0;
}
catch (...) {
printf("wrong object\n");
return 2;
}
if (c == 0) {
printf("no exception thrown\n");
return 1;
}
else {
printf("test not working\n");
return 3;
}
}
========================================================================
ChangeLog:
* frame.c (start_fde_sort): Change the return type of function
to int. Check the return values from malloc.
(frame_init): Exit immediately if start_fde_sort returns true.
(find_fde_low_mem): New function.
(find_fde): Use it.
(execute_cfa_insn): Abort if malloc returns NULL.
*** frame.c 1998/03/05 09:16:10 1.1
--- frame.c 1998/03/07 06:37:40
*************** typedef struct fde_accumulator
*** 218,230 ****
fde_vector erratic;
} fde_accumulator;
! static inline void
start_fde_sort (fde_accumulator *accu, size_t count)
{
accu->linear.array = (fde **) malloc (sizeof (fde *) * count);
accu->erratic.array = (fde **) malloc (sizeof (fde *) * count);
accu->linear.count = 0;
accu->erratic.count = 0;
}
static inline void
--- 218,243 ----
fde_vector erratic;
} fde_accumulator;
! static inline int
start_fde_sort (fde_accumulator *accu, size_t count)
{
+ #define FREE_FDE_ARRAY(p) if (p) { free (p); p = 0; }
+
accu->linear.array = (fde **) malloc (sizeof (fde *) * count);
accu->erratic.array = (fde **) malloc (sizeof (fde *) * count);
accu->linear.count = 0;
accu->erratic.count = 0;
+
+ if (!accu->linear.array || !accu->erratic.array)
+ {
+ FREE_FDE_ARRAY (accu->linear.array);
+ FREE_FDE_ARRAY (accu->erratic.array);
+ return 1;
+ }
+
+ return 0;
+
+ #undef FREE_FDE_ARRAY
}
static inline void
*************** frame_init (struct object* ob)
*** 430,436 ****
ob->count = count;
! start_fde_sort (&accu, count);
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
--- 443,451 ----
ob->count = count;
! if (start_fde_sort (&accu, count))
! return;
!
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
*************** frame_init (struct object* ob)
*** 448,453 ****
--- 463,506 ----
ob->pc_end = pc_end;
}
+ /* Return a pointer to the FDE for the function containing PC in
+ the object OB. This function is used when there is not enough
+ memory for a sorted array of FDE pointers. */
+
+ static fde *
+ find_fde_low_mem (struct object *ob, void *pc)
+ {
+ if (ob->fde_array)
+ {
+ fde **p = ob->fde_array;
+ fde *f = *p;
+ for (; *p; ++p, f = *p)
+ for (; f->length != 0; f = next_fde (f))
+ {
+ /* Skip CIEs and linked once FDE entries. */
+ if (f->CIE_delta == 0 || f->pc_begin == 0)
+ continue;
+
+ if (pc >= f->pc_begin && pc < f->pc_begin + f->pc_range)
+ return f;
+ }
+ }
+ else
+ {
+ fde *f = ob->fde_begin;
+ for (; f->length != 0; f = next_fde (f))
+ {
+ /* Skip CIEs and linked once FDE entries. */
+ if (f->CIE_delta == 0 || f->pc_begin == 0)
+ continue;
+
+ if (pc >= f->pc_begin && pc < f->pc_begin + f->pc_range)
+ return f;
+ }
+ }
+ return 0;
+ }
+
/* Return a pointer to the FDE for the function containing PC. */
static fde *
*************** find_fde (void *pc)
*** 462,468 ****
{
if (ob->pc_begin == 0)
frame_init (ob);
! if (pc >= ob->pc_begin && pc < ob->pc_end)
break;
}
--- 515,528 ----
{
if (ob->pc_begin == 0)
frame_init (ob);
! if (ob->pc_begin == 0)
! {
! /* This indicates memory allocation failure in frame_init. */
! fde *f = find_fde_low_mem (ob, pc);
! if (f)
! return f;
! }
! else if (pc >= ob->pc_begin && pc < ob->pc_end)
break;
}
*************** execute_cfa_insn (void *p, struct frame_
*** 630,635 ****
--- 690,697 ----
struct frame_state_internal *save =
(struct frame_state_internal *)
malloc (sizeof (struct frame_state_internal));
+ if (!save)
+ abort ();
memcpy (save, state, sizeof (struct frame_state_internal));
state->saved_state = save;
}