This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Segfault during stack unwinding & patch (2nd try)


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;
        }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]