Skip to contentSkip to conversation

deflate stack usage in lib/inflate.c

PATCH New Jeremy Fitzhardinge 6 participants 16 messages Apr 12, 2007 – Apr 16, 2007

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 deflate stack usage in lib/inflate.c

inflate_fixed() and huft_build() together use around 2.7k of stack. When using 4k stacks, I saw stack overflows from interrupts arriving while unpacking the root initrd:

do_IRQ: stack overflow: 384

 [<c0106b64>] show_trace_log_lvl+0x1a/0x30
 [<c01075e6>] show_trace+0x12/0x14
 [<c010763f>] dump_stack+0x16/0x18
 [<c0107ca4>] do_IRQ+0x6d/0xd9
 [<c010202b>] xen_evtchn_do_upcall+0x6e/0xa2
 [<c0106781>] xen_hypervisor_callback+0x25/0x2c
 [<c010116c>] xen_restore_fl+0x27/0x29
 [<c0330f63>] _spin_unlock_irqrestore+0x4a/0x50
 [<c0117aab>] change_page_attr+0x577/0x584
 [<c0117b45>] kernel_map_pages+0x8d/0xb4
 [<c016a314>] cache_alloc_refill+0x53f/0x632
 [<c016a6c2>] __kmalloc+0xc1/0x10d
 [<c0463d34>] malloc+0x10/0x12
 [<c04641c1>] huft_build+0x2a7/0x5fa
 [<c04645a5>] inflate_fixed+0x91/0x136
 [<c04657e2>] unpack_to_rootfs+0x5f2/0x8c1
 [<c0465acf>] populate_rootfs+0x1e/0xe4

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

This patch mallocs the local variables, thereby reducing the stack usage to sane levels.

lib/inflate.c +49 -17
diff -r 4a30275bd596 lib/inflate.c
@@ -292,7 +292,6 @@ STATIC int INIT huft_build(
    oversubscribed set of lengths), and three if not enough memory. */
 {
   unsigned a;                   /* counter for codes of length k */
-  unsigned c[BMAX+1];           /* bit length count table */
   unsigned f;                   /* i repeats in table every f entries */
   int g;                        /* maximum code length */
   int h;                        /* table level */
@@ -303,18 +302,33 @@ STATIC int INIT huft_build(
   register unsigned *p;         /* pointer into c[], b[], or v[] */
   register struct huft *q;      /* points to current table */
   struct huft r;                /* table entry for structure assignment */
-  struct huft *u[BMAX];         /* table stack */
-  unsigned v[N_MAX];            /* values in order of bit length */
   register int w;               /* bits before this table == (l * h) */
-  unsigned x[BMAX+1];           /* bit offsets, then code stack */
   unsigned *xp;                 /* pointer into x */
   int y;                        /* number of dummy codes added */
   unsigned z;                   /* number of entries in current table */
+  struct {
+    unsigned c[BMAX+1];           /* bit length count table */
+    struct huft *u[BMAX];         /* table stack */
+    unsigned v[N_MAX];            /* values in order of bit length */
+    unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  } *stk;    
+  unsigned *c, *v, *x;
+  struct huft **u;
+  int ret;
 
 DEBG("huft1 ");
 
+  stk = malloc(sizeof(*stk));
+  if (stk == NULL)
+    return 3;			/* out of memory */
+
+  c = stk->c;
+  v = stk->v;
+  x = stk->x;
+  u = stk->u;
+
   /* Generate counts for each bit length */
-  memzero(c, sizeof(c));
+  memzero(stk->c, sizeof(stk->c));
   p = b;  i = n;
   do {
     Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), 
@@ -326,7 +340,8 @@ DEBG("huft1 ");
   {
     *t = (struct huft *)NULL;
     *m = 0;
-    return 2;
+    ret = 2;
+    goto out;
   }
 
 DEBG("huft2 ");
@@ -351,10 +366,14 @@ DEBG("huft3 ");
 
   /* Adjust last length count to fill out codes, if needed */
   for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return 2;                 /* bad input: more codes than bits */
-  if ((y -= c[i]) < 0)
-    return 2;
+    if ((y -= c[j]) < 0) {
+      ret = 2;                 /* bad input: more codes than bits */
+      goto out;
+    }
+  if ((y -= c[i]) < 0) {
+    ret = 2;
+    goto out;
+  }
   c[i] += y;
 
 DEBG("huft4 ");
@@ -428,7 +447,8 @@ DEBG1("3 ");
         {
           if (h)
             huft_free(u[0]);
-          return 3;             /* not enough memory */
+          ret = 3;             /* not enough memory */
+	  goto out;
         }
 DEBG1("4 ");
         hufts += z + 1;         /* track memory usage */
@@ -492,7 +512,11 @@ DEBG("huft7 ");
 DEBG("huft7 ");
 
   /* Return true (1) if we were given an incomplete table */
-  return y != 0 && g != 1;
+  ret = y != 0 && g != 1;
+
+  out:
+  free(stk);
+  return ret;
 }
 
 
@@ -705,9 +729,13 @@ STATIC int noinline INIT inflate_fixed(v
   struct huft *td;      /* distance code table */
   int bl;               /* lookup bits for tl */
   int bd;               /* lookup bits for td */
-  unsigned l[288];      /* length list for huft_build */
+  unsigned *l;          /* length list for huft_build */
 
 DEBG("<fix");
+
+  l = malloc(sizeof(*l) * 288);
+  if (l == NULL)
+    return 3;			/* out of memory */
 
   /* set up literal table */
   for (i = 0; i < 144; i++)
@@ -719,9 +747,10 @@ DEBG("<fix");
   for (; i < 288; i++)          /* make a complete, but wrong code set */
     l[i] = 8;
   bl = 7;
-  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+    free(l);
     return i;
-
+  }
 
   /* set up distance table */
   for (i = 0; i < 30; i++)      /* make an incomplete code set */
@@ -730,6 +759,7 @@ DEBG("<fix");
   if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
   {
     huft_free(tl);
+    free(l);
 
     DEBG(">");
     return i;
@@ -737,11 +767,13 @@ DEBG("<fix");
 
 
   /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
+  if (inflate_codes(tl, td, bl, bd)) {
+    free(l);
     return 1;
-
+  }
 
   /* free the decoding tables, return */
+  free(l);
   huft_free(tl);
   huft_free(td);
   return 0;
#1 lore raw

PATCH 1/1 deflate stack usage in lib/inflate.c

Subject: deflate stack usage in lib/inflate.c

inflate_fixed and huft_build together use around 2.7k of stack. When using 4k stacks, I saw stack overflows from interrupts arriving while unpacking the root initrd:

do_IRQ: stack overflow: 384

 [<c0106b64>] show_trace_log_lvl+0x1a/0x30
 [<c01075e6>] show_trace+0x12/0x14
 [<c010763f>] dump_stack+0x16/0x18
 [<c0107ca4>] do_IRQ+0x6d/0xd9
 [<c010202b>] xen_evtchn_do_upcall+0x6e/0xa2
 [<c0106781>] xen_hypervisor_callback+0x25/0x2c
 [<c010116c>] xen_restore_fl+0x27/0x29
 [<c0330f63>] _spin_unlock_irqrestore+0x4a/0x50
 [<c0117aab>] change_page_attr+0x577/0x584
 [<c0117b45>] kernel_map_pages+0x8d/0xb4
 [<c016a314>] cache_alloc_refill+0x53f/0x632
 [<c016a6c2>] __kmalloc+0xc1/0x10d
 [<c0463d34>] malloc+0x10/0x12
 [<c04641c1>] huft_build+0x2a7/0x5fa
 [<c04645a5>] inflate_fixed+0x91/0x136
 [<c04657e2>] unpack_to_rootfs+0x5f2/0x8c1
 [<c0465acf>] populate_rootfs+0x1e/0xe4

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

This patch mallocs the local variables, thereby reducing the stack usage to sane levels.

Also, up the heap size for the kernel decompressor to deal with the extra allocation.

---
 lib/inflate.c |   66 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 17 deletions(-)
arch/i386/boot/compressed/misc.c +1 -1
diff -r 9b72ff6b8c17 arch/i386/boot/compressed/misc.c
@@ -189,7 +189,7 @@ static unsigned long free_mem_ptr;
 static unsigned long free_mem_ptr;
 static unsigned long free_mem_end_ptr;
 
-#define HEAP_SIZE             0x3000
+#define HEAP_SIZE             0x4000
 
 static char *vidmem = (char *)0xb8000;
 static int vidport;
lib/inflate.c +49 -17

140 lines not on this page · raw message

#2 lore raw
Quoted 3 lines

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

Hmm, does Xen perhaps not use interrupt stacks? Normally 2.7k should be still green as long as there are not too many functions above/below it.

-Andi

#3 lore raw
Quoted 3 lines · Andi Kleen

Hmm, does Xen perhaps not use interrupt stacks? Normally 2.7k should be still green as long as there are not too many functions above/below it.

That's a good point, I'll need to check that. Still, nearly 3k of stack!

J

#4 lore raw
Quoted 5 lines · Jeremy Fitzhardinge
Quoted 2 lines · Andi Kleen

Hmm, does Xen perhaps not use interrupt stacks? Normally 2.7k should be still green as long as there are not too many functions above/below it.

That's a good point, I'll need to check that. Still, nearly 3k of stack!

I bite. Would compressing the vmlinux binary with LZO or LZMA make an improvement to the bootstrap uncompress stack usage?

Jan

#5 lore raw
Quoted 4 lines · Jan Engelhardt
Quoted 2 lines · Jeremy Fitzhardinge

Andi Kleen wrote:

Quoted 9 lines
Quoted 5 lines
Quoted 3 lines

Hmm, does Xen perhaps not use interrupt stacks? Normally 2.7k should be still green as long as there are not too many functions above/below it.

That's a good point, I'll need to check that. Still, nearly 3k of stack!

I bite. Would compressing the vmlinux binary with LZO or LZMA make an improvement to the bootstrap uncompress stack usage?

Well, the thread started with my patch to fix inflate. The stack usage of LZO or LZMA decompressors will primarily depend on how they're implemented rather than any inherent property of the algorithms.

J

#6 lore raw
In reply to Jan Engelhardt
Quoted 10 lines · On Friday 13 April 2007 01:20:40 Jan Engelhardt wrote:
Quoted 5 lines · Jeremy Fitzhardinge
Quoted 2 lines · Andi Kleen

Hmm, does Xen perhaps not use interrupt stacks? Normally 2.7k should be still green as long as there are not too many functions above/below it.

That's a good point, I'll need to check that. Still, nearly 3k of stack!

I bite. Would compressing the vmlinux binary with LZO or LZMA make an improvement to the bootstrap uncompress stack usage?

We don't care about the stack usage, as long as it doesn't overflow. It's a very limited piece of code that doesn't run on top or below other subsystems.

-Andi

#7 lore raw
In reply to Andi Kleen
Quoted 5 lines · Andi Kleen
Quoted 3 lines

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

Hmm, does Xen perhaps not use interrupt stacks?

Looks like that's all done in do_IRQ, so it should be independent of whether its Xen or not. And the stack overflow check is performed on the main stack, before switching to the interrupt stack.

J

#8 lore raw
Quoted 10 lines · On Friday 13 April 2007 00:56:56 Jeremy Fitzhardinge wrote:
Quoted 5 lines · Andi Kleen
Quoted 3 lines

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

Hmm, does Xen perhaps not use interrupt stacks?

Looks like that's all done in do_IRQ, so it should be independent of whether its Xen or not. And the stack overflow check is performed on the main stack, before switching to the interrupt stack.

Yes, but then we should have seen more frequently, shouldn't we? I always run with the stack overflow check enabled and I don't think I ever saw warnings in inflate.

Something must be different in the Xen setup. Dunno if it's a bug, but such differences could cause more problems later.

-Andi

#9 lore raw
Quoted 4 lines · Andi Kleen

Yes, but then we should have seen more frequently, shouldn't we? I always run with the stack overflow check enabled and I don't think I ever saw warnings in inflate.

I guess the window is just while decompressing the root filesystem. Interrupts under Xen might be using a little more stack (~40-50 bytes?), but its not a qualitative difference. It might have more to do with different timing.

J

#10 lore raw
In reply to Jeremy Fitzhardinge
Quoted 10 lines · Jeremy Fitzhardinge
Quoted 4 lines · Andi Kleen
Quoted 3 lines

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

Hmm, does Xen perhaps not use interrupt stacks?

Looks like that's all done in do_IRQ, so it should be independent of whether its Xen or not. And the stack overflow check is performed on the main stack, before switching to the interrupt stack.

Yeah, the do_IRQ thing is misleading because it makes you think the interrupt caused an overflow when all it did was detect a near-overflow condition. (The number printed is the amount of space left.)

#11 lore raw
In reply to Jeremy Fitzhardinge

arch/i386/boot/compressed/misc.c static unsigned long free_mem_ptr; · line 192

Quoted 2 lines · Jeremy Fitzhardinge
arch/i386/boot/compressed/misc.c +1 -1
-#define HEAP_SIZE             0x3000
+#define HEAP_SIZE             0x4000

There are a bunch more of these that'll need fixing.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#12 lore raw
Quoted 8 lines · Matt Mackall

Review

Quoted 3 lines · Jeremy Fitzhardinge
(quoted diff) +1 -1
-#define HEAP_SIZE             0x3000
+#define HEAP_SIZE             0x4000

There are a bunch more of these that'll need fixing.

Like this?

arch/alpha/boot/misc.c +1 -1
diff -r 2ad8a0729f26 arch/alpha/boot/misc.c
@@ -98,7 +98,7 @@ static ulg free_mem_ptr;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
 
 #include "../../../lib/inflate.c"
 
arch/arm/boot/compressed/misc.c +1 -1
diff -r 2ad8a0729f26 arch/arm/boot/compressed/misc.c
@@ -239,7 +239,7 @@ static ulg free_mem_ptr;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
 
 #include "../../../../lib/inflate.c"
 
arch/arm26/boot/compressed/misc.c +1 -1
diff -r 2ad8a0729f26 arch/arm26/boot/compressed/misc.c
@@ -182,7 +182,7 @@ static ulg free_mem_ptr;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
 
 #include "../../../../lib/inflate.c"
 
arch/x86_64/boot/compressed/misc.c +1 -1
diff -r 2ad8a0729f26 arch/x86_64/boot/compressed/misc.c
@@ -189,7 +189,7 @@ static long free_mem_ptr;
 static long free_mem_ptr;
 static long free_mem_end_ptr;
 
-#define HEAP_SIZE             0x6000
+#define HEAP_SIZE             0x7000
 
 static char *vidmem = (char *)0xb8000;
 static int vidport;
Acked-by
#13 lore raw
Quoted 11 lines · Jeremy Fitzhardinge
Quoted 8 lines · Matt Mackall

Review

Quoted 3 lines · Jeremy Fitzhardinge
(quoted diff) +1 -1
-#define HEAP_SIZE             0x3000
+#define HEAP_SIZE             0x4000

There are a bunch more of these that'll need fixing.

Like this?

I'm not sure what the story is with the platforms that bump this to 0x10000, but this does get the rest of them.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#14 lore raw
In reply to Jeremy Fitzhardinge

arch/arm/boot/compressed/misc.c static ulg free_mem_ptr; · line 242

Quoted 9 lines · Jeremy Fitzhardinge

diff -r 2ad8a0729f26 arch/arm/boot/compressed/misc.c

arch/arm/boot/compressed/misc.c +1 -1
@@ -239,7 +239,7 @@ static ulg free_mem_ptr;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000

Not used on ARM, this macro can be deleted. For the record, the space available to the decompressor on ARM is 64K.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:
#15 lore raw
In reply to Jeremy Fitzhardinge
Quoted 25 lines · Jeremy Fitzhardinge

Subject: deflate stack usage in lib/inflate.c

inflate_fixed and huft_build together use around 2.7k of stack. When using 4k stacks, I saw stack overflows from interrupts arriving while unpacking the root initrd:

do_IRQ: stack overflow: 384

 [<c0106b64>] show_trace_log_lvl+0x1a/0x30
 [<c01075e6>] show_trace+0x12/0x14
 [<c010763f>] dump_stack+0x16/0x18
 [<c0107ca4>] do_IRQ+0x6d/0xd9
 [<c010202b>] xen_evtchn_do_upcall+0x6e/0xa2
 [<c0106781>] xen_hypervisor_callback+0x25/0x2c
 [<c010116c>] xen_restore_fl+0x27/0x29
 [<c0330f63>] _spin_unlock_irqrestore+0x4a/0x50
 [<c0117aab>] change_page_attr+0x577/0x584
 [<c0117b45>] kernel_map_pages+0x8d/0xb4
 [<c016a314>] cache_alloc_refill+0x53f/0x632
 [<c016a6c2>] __kmalloc+0xc1/0x10d
 [<c0463d34>] malloc+0x10/0x12
 [<c04641c1>] huft_build+0x2a7/0x5fa
 [<c04645a5>] inflate_fixed+0x91/0x136
 [<c04657e2>] unpack_to_rootfs+0x5f2/0x8c1
 [<c0465acf>] populate_rootfs+0x1e/0xe4
Quoted 8 lines

(This was under Xen, but there's no reason it couldn't happen on bare
hardware.)

This patch mallocs the local variables, thereby reducing the stack usage to sane levels.

Also, up the heap size for the kernel decompressor to deal with the extra allocation.

Lost the non-x86 bits again.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.