bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [patch #3346] GNUMach: ifdef DEBUG -> ifndef NDEBUG


From: Alfred M. Szmidt
Subject: Re: [patch #3346] GNUMach: ifdef DEBUG -> ifndef NDEBUG
Date: Tue, 30 Nov 2004 15:27:35 +0100

   Sounds like it might be this [1] patch.

Thanks, I inlined it.

Roland, OK to commit?  Then I can commit the previous patch with a
good concious; after I test it obviously...


Summary:  Double free and memory loss probing partition table

Original Submission: While GNU Mach reads the partition table, the
second assert in linux/dev/glue:free_pages is triggered. This
particular assert checks for double frees.  I have traced the problem
back to getblk and __brelse: if linux_auto_config is true (which it is
when partitions are being probed), a static buffer is used to hold the
BH structure. If getblk is called a second time (i.e. before the first
block is released), the buffer is overriden.  This results in a double
free, a memory leak (as the buffer in the first BH is never released)
and a consistency problem as code which uses the first buffer will now
see different data. This is the case in
linux/dev/drivers/block/genhd.c:msdos_partition which calls bread
then, before freeing the block, calls extended_partition which also
calls bread. In reality, there is no reason to not use kalloc and
kfree here. In kern/statup.c:setup_main, we see that vm_mem_bootstrap
which calls kmem_init is called long before
linux/dev/init/main.c:linux_init is invoked by
i386/i386at/machine_init:machine_init.

This attached patch changes getblk and __brelse to always use kalloc
and kfree and adds asserts to kern/kalloc.c to make sure that kalloc,
kfree and kget are only called after kmem_init has been called.

Apply the patch using -p0

2004-09-07  Neal H. Walfield  <neal@cs.uml.edu>

        * linux/dev/glue/block.c (__brelse): Unconditionally kfree BH.
        (getblk): Unconditionally kalloc BH.

        * kern/kalloc.c [!NDEBUG] (kalloc_init_called): New static
        variable.
        (kalloc_init): Assert that kalloc_init_called is zero.
        [! NDEBUG] Set kalloc_init_called to 1 on success.
        (kalloc): Assert that kalloc_init_called is non-zero.
        (kget): Likewise.
        (kfree): Likewise.

Index: linux/dev/glue/block.c
===================================================================
RCS file: /cvsroot/hurd/gnumach/linux/dev/glue/Attic/block.c,v
retrieving revision 1.8.2.2
diff -u -p -r1.8.2.2 block.c
--- linux/dev/glue/block.c      19 Jan 2004 01:44:31 -0000      1.8.2.2
+++ linux/dev/glue/block.c      7 Sep 2004 15:08:17 -0000
@@ -354,22 +354,17 @@ struct buffer_head *
 getblk (kdev_t dev, int block, int size)
 {
   struct buffer_head *bh;
-  static struct buffer_head bhead;
 
   assert (size <= PAGE_SIZE);
 
-  if (! linux_auto_config)
-    bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head));
-  else
-    bh = &bhead;
+  bh = (struct buffer_head *) kalloc (sizeof (struct buffer_head));
   if (bh)
     {
       memset (bh, 0, sizeof (struct buffer_head));
       bh->b_data = alloc_buffer (size);
       if (! bh->b_data)
        {
-         if (! linux_auto_config)
-           kfree ((vm_offset_t) bh, sizeof (struct buffer_head));
+         kfree ((vm_offset_t) bh, sizeof (struct buffer_head));
          return NULL;
        }
       bh->b_dev = dev;
@@ -385,8 +380,7 @@ void
 __brelse (struct buffer_head *bh)
 {
   free_buffer (bh->b_data, bh->b_size);
-  if (! linux_auto_config)
-    kfree ((vm_offset_t) bh, sizeof (*bh));
+  kfree ((vm_offset_t) bh, sizeof (*bh));
 }
 
 /* Allocate a buffer of SIZE bytes and fill it with data
Index: kern/kalloc.c
===================================================================
RCS file: /cvsroot/hurd/gnumach/kern/kalloc.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 kalloc.c
--- kern/kalloc.c       25 Feb 1997 21:28:23 -0000      1.1.1.1
+++ kern/kalloc.c       7 Sep 2004 15:08:17 -0000
@@ -106,12 +106,18 @@ unsigned long k_zone_max[16] = {
  *     This initializes all of the zones.
  */
 
+#ifndef NDEBUG
+static int kalloc_init_called;
+#endif
+
 void kalloc_init()
 {
        vm_offset_t min, max;
        vm_size_t size;
        register int i;
 
+       assert (! kalloc_init_called);
+
        kalloc_map = kmem_suballoc(kernel_map, &min, &max,
                                   kalloc_map_size, FALSE);
 
@@ -142,6 +148,10 @@ void kalloc_init()
                                  size >= PAGE_SIZE ? ZONE_COLLECTABLE : 0,
                                  k_zone_name[i]);
        }
+
+#ifndef NDEBUG
+       kalloc_init_called = 1;
+#endif
 }
 
 vm_offset_t kalloc(size)
@@ -153,6 +163,8 @@ vm_offset_t kalloc(size)
 
        /* compute the size of the block that we will actually allocate */
 
+       assert (kalloc_init_called);
+
        allocsize = size;
        if (size < kalloc_max) {
                allocsize = MINSIZE;
@@ -185,6 +197,8 @@ vm_offset_t kget(size)
        register vm_size_t allocsize;
        vm_offset_t addr;
 
+       assert (kalloc_init_called);
+
        /* compute the size of the block that we will actually allocate */
 
        allocsize = size;
@@ -219,6 +233,8 @@ kfree(data, size)
        register int zindex;
        register vm_size_t freesize;
 
+       assert (kalloc_init_called);
+
        freesize = size;
        if (size < kalloc_max) {
                freesize = MINSIZE;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]