[patch] Broken CLEAR_BITMAP() macro

From: Matthew Dobson (colpatch@us.ibm.com)
Date: Thu Feb 06 2003 - 17:44:19 EST


Hello all,
        It appears that the CLEAR_BITMAP() macro in include/linux/types.h is
broken.

(Examples done with BITS_PER_LONG == 32, but would work with == 64, or
anything but 8 for that matter! :)

>#define DECLARE_BITMAP(name,bits) \
> unsigned long name[((bits)+BITS_PER_LONG-1)/BITS_PER_LONG]
>#define CLEAR_BITMAP(name,bits) \
> memset(name, 0, ((bits)+BITS_PER_LONG-1)/8)

If, for example, we DECLARE_BITMAP(foo, 64), we're going to get:
        unsigned long foo[((64)+32-1)/32] =>
        unsigned long foo[95/32] =>
        unsigned long foo[2]

Now, that's all well and good (and correct! ;) But, look at what
happens if we do a CLEAR_BITMAP(foo, 64):
        memset(foo, 0, ((64)+32-1)/8) =>
        memset(foo, 0, 95/8) =>
        memset(foo, 0, 11)

So the memset is going to try and clear 11 bytes starting at foo, which
will overflow the foo array by 3 bytes. This is bad.

What CLEAR_BITMAP wants to be doing is this:
  #define CLEAR_BITMAP(name,bits) \
          memset(name, 0,
(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long))

Attatched is a patch that creates a macro BITS_TO_LONGS that just rounds
a number of bits up to the closest number of unsigned longs. This makes
the DECLARE & CLEAR _BITMAP macros more readable. I also modify the
CLEAR_BITMAP macro to work correctly.

Cheers!

-Matt

diff -Nur --exclude-from=/usr/src/.dontdiff linux-2.5.59-vanilla/include/linux/types.h linux-2.5.59-bitmap_fix/include/linux/types.h
--- linux-2.5.59-vanilla/include/linux/types.h Thu Jan 16 18:22:41 2003
+++ linux-2.5.59-bitmap_fix/include/linux/types.h Thu Feb 6 13:51:23 2003
@@ -4,10 +4,12 @@
 #ifdef __KERNEL__
 #include <linux/config.h>
 
+#define BITS_TO_LONGS(bits) \
+ (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
 #define DECLARE_BITMAP(name,bits) \
- unsigned long name[((bits)+BITS_PER_LONG-1)/BITS_PER_LONG]
+ unsigned long name[BITS_TO_LONGS(bits)]
 #define CLEAR_BITMAP(name,bits) \
- memset(name, 0, ((bits)+BITS_PER_LONG-1)/8)
+ memset(name, 0, BITS_TO_LONGS(bits)*sizeof(unsigned long))
 #endif
 
 #include <linux/posix_types.h>

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Feb 07 2003 - 22:00:22 EST