diff mbox

libgcc: unwind-ia64.c without malloc/free

Message ID HE1PR07MB090538F853ADD846DD1F3626E4EF0@HE1PR07MB0905.eurprd07.prod.outlook.com
State New
Headers show

Commit Message

Bernd Edlinger Dec. 16, 2015, 11:17 p.m. UTC
Hi,

this is just an idea, how to avoid use of malloc in unwind-ia64.c.

I can compile this with my cross-compiler, but can not test anything.

If you find it interesting, then someone should continue this work and test
and/or fix it until it really works.

The idea is, I can use alloca instead of malloc: this is re-entrant, and
works also with zero free memory.  The allocations have to be done
in the main loop, and the state machine, is always guaranteed to have
at least one available memory block.  What do you think?


Regards,
Bernd.

Comments

Bernd Schmidt Dec. 17, 2015, 1:17 p.m. UTC | #1
On 12/17/2015 12:17 AM, Bernd Edlinger wrote:
> this is just an idea, how to avoid use of malloc in unwind-ia64.c.
[...]
> What do you think?

Not worth worrying about IMO. I think ia64 is dead and best left to rest 
in maintenance mode.


Bernd
Jeff Law Dec. 17, 2015, 2:01 p.m. UTC | #2
On 12/17/2015 06:17 AM, Bernd Schmidt wrote:
> On 12/17/2015 12:17 AM, Bernd Edlinger wrote:
>> this is just an idea, how to avoid use of malloc in unwind-ia64.c.
> [...]
>> What do you think?
>
> Not worth worrying about IMO. I think ia64 is dead and best left to rest
> in maintenance mode.
Agreed.  And in general using alloca is a problem waiting to happen 
unless you can prove there's no way to blow out the stack.   I can't 
count the number of problems of that nature we've fixed in glibc over 
the last 5 years when the hackers realized that was a great attack vector.

jeff
diff mbox

Patch

Index: libgcc/config/ia64/unwind-ia64.c
===================================================================
--- libgcc/config/ia64/unwind-ia64.c	(revision 231696)
+++ libgcc/config/ia64/unwind-ia64.c	(working copy)
@@ -129,6 +129,14 @@  struct unw_labeled_state {
   struct unw_reg_state saved_state;
 };
 
+struct unw_alloc_context
+{
+  struct unw_reg_state     *avail_reg_state;
+  struct unw_labeled_state *avail_labeled_state;
+  struct unw_reg_state     **dup_state_result;
+  struct unw_reg_state     *dup_state_param;
+};
+
 typedef struct unw_state_record
 {
   unsigned int first_region : 1;	/* is this the first region? */
@@ -152,9 +160,10 @@  typedef struct unw_state_record
 
   struct unw_labeled_state *labeled_states;	/* list of all labeled states */
   struct unw_reg_state curr;	/* current state */
+  struct unw_alloc_context ac;
 
   _Unwind_Personality_Fn personality;
-  
+
 } _Unwind_FrameState;
 
 enum unw_nat_type
@@ -237,128 +246,44 @@  static unsigned char const save_order[] =
 
 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
 
-/* MASK is a bitmap describing the allocation state of emergency buffers,
-   with bit set indicating free. Return >= 0 if allocation is successful;
-   < 0 if failure.  */
-
-static inline int
-atomic_alloc (unsigned int *mask)
-{
-  unsigned int old = *mask, ret, new;
-
-  while (1)
-    {
-      if (old == 0)
-	return -1;
-      ret = old & -old;
-      new = old & ~ret;
-      new = __sync_val_compare_and_swap (mask, old, new);
-      if (old == new)
-	break;
-      old = new;
-    }
-
-  return __builtin_ffs (ret) - 1;
-}
-
-/* Similarly, free an emergency buffer.  */
-
-static inline void
-atomic_free (unsigned int *mask, int bit)
-{
-  __sync_xor_and_fetch (mask, 1 << bit);
-}
-
-
-#define SIZE(X)		(sizeof(X) / sizeof(*(X)))
-#define MASK_FOR(X)	((2U << (SIZE (X) - 1)) - 1)
-#define PTR_IN(X, P)	((P) >= (X) && (P) < (X) + SIZE (X))
-
-static struct unw_reg_state emergency_reg_state[32];
-static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
-
-static struct unw_labeled_state emergency_labeled_state[8];
-static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
-
-#ifdef ENABLE_MALLOC_CHECKING
-static int reg_state_alloced;
-static int labeled_state_alloced;
-#endif
-
 /* Allocation and deallocation of structures.  */
 
 static struct unw_reg_state *
-alloc_reg_state (void)
+alloc_reg_state (struct unw_alloc_context *ac)
 {
   struct unw_reg_state *rs;
 
-#ifdef ENABLE_MALLOC_CHECKING
-  reg_state_alloced++;
-#endif
+  rs = ac->avail_reg_state;
+  if (rs)
+    ac->avail_reg_state = rs->next;
 
-  rs = malloc (sizeof (struct unw_reg_state));
-  if (!rs)
-    {
-      int n = atomic_alloc (&emergency_reg_state_free);
-      if (n >= 0)
-	rs = &emergency_reg_state[n];
-    }
-
   return rs;
 }
 
 static void
-free_reg_state (struct unw_reg_state *rs)
+free_reg_state (struct unw_reg_state *rs, struct unw_alloc_context *ac)
 {
-#ifdef ENABLE_MALLOC_CHECKING
-  reg_state_alloced--;
-#endif
-
-  if (PTR_IN (emergency_reg_state, rs))
-    atomic_free (&emergency_reg_state_free, rs - emergency_reg_state);
-  else
-    free (rs);
+  rs->next = ac->avail_reg_state;
+  ac->avail_reg_state = rs;
 }
 
 static struct unw_labeled_state *
-alloc_label_state (void)
+alloc_label_state (struct unw_alloc_context *ac)
 {
   struct unw_labeled_state *ls;
 
-#ifdef ENABLE_MALLOC_CHECKING
-  labeled_state_alloced++;
-#endif
+  ls = ac->avail_labeled_state;
+  ac->avail_labeled_state = NULL;
 
-  ls = malloc(sizeof(struct unw_labeled_state));
-  if (!ls)
-    {
-      int n = atomic_alloc (&emergency_labeled_state_free);
-      if (n >= 0)
-	ls = &emergency_labeled_state[n];
-    }
-
   return ls;
 }
 
-static void
-free_label_state (struct unw_labeled_state *ls)
-{
-#ifdef ENABLE_MALLOC_CHECKING
-  labeled_state_alloced--;
-#endif
-
-  if (PTR_IN (emergency_labeled_state, ls))
-    atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls);
-  else
-    free (ls);
-}
-
 /* Routines to manipulate the state stack.  */
 
 static void
 push (struct unw_state_record *sr)
 {
-  struct unw_reg_state *rs = alloc_reg_state ();
+  struct unw_reg_state *rs = alloc_reg_state (&sr->ac);
   memcpy (rs, &sr->curr, sizeof (*rs));
   sr->curr.next = rs;
 }
@@ -371,34 +296,40 @@  pop (struct unw_state_record *sr)
   if (!rs)
     abort ();
   memcpy (&sr->curr, rs, sizeof(*rs));
-  free_reg_state (rs);
+  free_reg_state (rs, &sr->ac);
 }
 
 /* Make a copy of the state stack.  Non-recursive to avoid stack overflows.  */
 
-static struct unw_reg_state *
-dup_state_stack (struct unw_reg_state *rs)
+static void
+dup_state_stack (struct unw_reg_state **result, struct unw_reg_state *rs,
+		 struct unw_alloc_context *ac)
 {
-  struct unw_reg_state *copy, *prev = NULL, *first = NULL;
+  struct unw_reg_state *copy;
 
   while (rs)
     {
-      copy = alloc_reg_state ();
+      copy = alloc_reg_state (ac);
+      if (!copy)
+	{
+	  ac->dup_state_result = result;
+	  ac->dup_state_param = rs;
+	  return;
+	}
       memcpy (copy, rs, sizeof(*copy));
-      if (first)
-	prev->next = copy;
-      else
-	first = copy;
+      *result = copy;
+      result = &copy->next;
       rs = rs->next;
-      prev = copy;
     }
 
-  return first;
+  *result = NULL;
+  ac->dup_state_result = NULL;
+  ac->dup_state_param = NULL;
 }
 
 /* Free all stacked register states (but not RS itself).  */
 static void
-free_state_stack (struct unw_reg_state *rs)
+free_state_stack (struct unw_reg_state *rs, struct unw_alloc_context *ac)
 {
   struct unw_reg_state *p, *next;
 
@@ -405,26 +336,10 @@  static void
   for (p = rs->next; p != NULL; p = next)
     {
       next = p->next;
-      free_reg_state (p);
+      free_reg_state (p, ac);
     }
   rs->next = NULL;
 }
-
-/* Free all labeled states.  */
-
-static void
-free_label_states (struct unw_labeled_state *ls)
-{
-  struct unw_labeled_state *next;
-
-  for (; ls ; ls = next)
-    {
-      next = ls->next;
-
-      free_state_stack (&ls->saved_state);
-      free_label_state (ls);
-    }
-}
 
 /* Unwind decoder routines */
 
@@ -823,10 +738,10 @@  desc_copy_state (unw_word label, struct unw_state_
   for (ls = sr->labeled_states; ls; ls = ls->next)
     {
       if (ls->label == label)
-        {
-	  free_state_stack (&sr->curr);
+	{
+	  free_state_stack (&sr->curr, &sr->ac);
    	  memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
-	  sr->curr.next = dup_state_stack (ls->saved_state.next);
+	  dup_state_stack (&sr->curr.next, ls->saved_state.next, &sr->ac);
 	  return;
 	}
     }
@@ -836,11 +751,11 @@  desc_copy_state (unw_word label, struct unw_state_
 static inline void
 desc_label_state (unw_word label, struct unw_state_record *sr)
 {
-  struct unw_labeled_state *ls = alloc_label_state ();
+  struct unw_labeled_state *ls = alloc_label_state (&sr->ac);
 
   ls->label = label;
   memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
-  ls->saved_state.next = dup_state_stack (sr->curr.next);
+  dup_state_stack (&ls->saved_state.next, sr->curr.next, &sr->ac);
 
   /* Insert into list of labeled states.  */
   ls->next = sr->labeled_states;
@@ -1061,7 +976,7 @@  unw_decode_uleb128 (unsigned char **dpp)
 static unsigned char *
 unw_decode_x1 (unsigned char *dp,
 	       unsigned char code __attribute__((unused)),
-	       void *arg)
+	       struct unw_state_record *arg)
 {
   unsigned char byte1, abreg;
   unw_word t, off;
@@ -1080,7 +995,7 @@  unw_decode_x1 (unsigned char *dp,
 static unsigned char *
 unw_decode_x2 (unsigned char *dp,
 	       unsigned char code __attribute__((unused)),
-	       void *arg)
+	       struct unw_state_record *arg)
 {
   unsigned char byte1, byte2, abreg, x, ytreg;
   unw_word t;
@@ -1100,7 +1015,7 @@  unw_decode_x2 (unsigned char *dp,
 static unsigned char *
 unw_decode_x3 (unsigned char *dp,
 	       unsigned char code __attribute__((unused)),
-	       void *arg)
+	       struct unw_state_record *arg)
 {
   unsigned char byte1, byte2, abreg, qp;
   unw_word t, off;
@@ -1122,7 +1037,7 @@  unw_decode_x3 (unsigned char *dp,
 static unsigned char *
 unw_decode_x4 (unsigned char *dp,
 	       unsigned char code __attribute__((unused)),
-	       void *arg)
+	       struct unw_state_record *arg)
 {
   unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
   unw_word t;
@@ -1143,7 +1058,8 @@  unw_decode_x4 (unsigned char *dp,
 }
 
 static unsigned char *
-unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_r1 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   int body = (code & 0x20) != 0;
   unw_word rlen;
@@ -1154,7 +1070,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_r2 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   unsigned char byte1, mask, grsave;
   unw_word rlen;
@@ -1169,7 +1086,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_r3 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   unw_word rlen;
 
@@ -1179,7 +1097,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p1 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   unsigned char brmask = (code & 0x1f);
 
@@ -1188,7 +1107,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p2_p5 (unsigned char *dp, unsigned char code,
+		  struct unw_state_record *arg)
 {
   if ((code & 0x10) == 0)
     {
@@ -1237,7 +1157,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p6 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   int gregs = (code & 0x10) != 0;
   unsigned char mask = (code & 0x0f);
@@ -1250,7 +1171,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p7_p10 (unsigned char *dp, unsigned char code,
+		   struct unw_state_record *arg)
 {
   unsigned char r, byte1, byte2;
   unw_word t, size;
@@ -1349,7 +1271,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_b1 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   unw_word label = (code & 0x1f);
 
@@ -1361,7 +1284,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_b2 (unsigned char *dp, unsigned char code,
+	       struct unw_state_record *arg)
 {
   unw_word t;
 
@@ -1371,7 +1295,8 @@  static unsigned char *
 }
 
 static unsigned char *
-unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_b3_x4 (unsigned char *dp, unsigned char code,
+		  struct unw_state_record *arg)
 {
   unw_word t, ecount, label;
 
@@ -1401,7 +1326,8 @@  static unsigned char *
   return dp;
 }
 
-typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
+typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char,
+				       struct unw_state_record *arg);
 
 static const unw_decoder unw_decode_table[2][8] =
 {
@@ -1432,7 +1358,8 @@  static const unw_decoder unw_decode_table[2][8] =
  * Decode one descriptor and return address of next descriptor.
  */
 static inline unsigned char *
-unw_decode (unsigned char *dp, int inside_body, void *arg)
+unw_decode (unsigned char *dp, int inside_body,
+	    struct unw_state_record *arg)
 {
   unw_decoder decoder;
   unsigned char code;
@@ -1845,16 +1772,24 @@  uw_frame_state_for (struct _Unwind_Context *contex
   insn = (unsigned char *) (unw + 1);
   insn_end = (unsigned char *) (unw + 1 + length);
   while (!fs->done && insn < insn_end)
-    insn = unw_decode (insn, fs->in_body, fs);
+    {
+      if (fs->ac.avail_reg_state == NULL)
+	{
+	  fs->ac.avail_reg_state = alloca (sizeof (struct unw_reg_state));
+	  fs->ac.avail_reg_state->next = NULL;
+	}
+      if (fs->ac.avail_labeled_state == NULL)
+	fs->ac.avail_labeled_state = alloca (sizeof (struct unw_labeled_state));
+      insn = unw_decode (insn, fs->in_body, fs);
+      while (fs->ac.dup_state_result != NULL)
+	{
+	  fs->ac.avail_reg_state = alloca (sizeof (struct unw_reg_state));
+	  fs->ac.avail_reg_state->next = NULL;
+	  dup_state_stack (fs->ac.dup_state_result,
+			   fs->ac.dup_state_param, &fs->ac);
+	}
+    }
 
-  free_label_states (fs->labeled_states);
-  free_state_stack (&fs->curr);
-
-#ifdef ENABLE_MALLOC_CHECKING
-  if (reg_state_alloced || labeled_state_alloced)
-    abort ();
-#endif
-
   /* If we're in the epilogue, sp has been restored and all values
      on the memory stack below psp also have been restored.  */
   if (fs->when_target > fs->epilogue_start)