sparse' is a tool for spotting bad variable uses in the Linux kernel It allows pointers, etc., to be annotated as to whether they point to user space or kernel space, whether I/O or whatever. Running make C=1 enables sparse checking.
On 15 September, Linux wrote this about some new features:
On Wed, 15 Sep 2004, Roland Dreier wrote:
>
> Linus, while we're on the subject of new sparse checks, could you give
> a quick recap of the semantics of the new __leXX types (and what
> __bitwise means to sparse)? I don't think I've ever seen this stuff
> described on LKML.
[ The bitwise checks are actually by Al Viro, but I'll explain the basic
idea. Al is Cc'd so that he can add any corrections or extensions. ]
Sparse allows a number of extra type qualifiers, including address spaces and various random extra restrictions on what you can do with them. There are context bits that allow you to use a symbol or type only in certain contexts, for example, and there are type qualifiers like noderef that just say that a pointer cannot be dereferenced (it looks exactly like a pointer in all other respects, but trying to actually access anything through it will cause a sparse warning).
The bitwise attribute is very much like the noderef one, in that it restricts how you can use an expression of that type. Unlike noderef, it's designed for integer types, though. In fact, sparse will refuse to apply the bitwise attribute to non-integer types.
As the name suggests, a bitwise expression is one that is restricted to only a certain bitwise operations that make sense within that class. In particular, you can't mix a bitwise class with a normal integer expression (the constant zero happens to be special, since it's safe for all bitwise ops), and in fact you can't even mix it with another bitwise expression of a different type.
And when I say "different"', I mean even slightly different. Each typedef creates a type of its own, and will thus create a bitwise type that is not compatible with anything else. So if you declare
int __bitwise i; int __bitwise j;
the two variables i and j are not compatible, simply because they were declared separately, while in the case of
int __bitwise i, j;
they are compatible. The above is a horribly contrived example, as it shows an extreme case that doesn't make much sense, but it shows how bitwise always creates its own new class.
Normally you'd always use __bitwise in a typedef, which effectively makes that particular typedef one single bitwise class. After that, you can obviously declare any number of variables in that class.
Now apart from the classes having to match, bitwise as its name suggests, also restricts all operations within that class to a subset of bit-safe operations. For example, addition isn't bit-safe, since clearly the carry-chain moves bits around. But you can do normal bit-wise operations, and you can compare the values against other values in the same class, since those are all bit-safe.
Oh, as an example of something that isn't obviously bit-safe: look out for things like bit negation: doing a ~ is ok on a bitwise int type, but it is not ok on a bitwise short or char. Why? Because on a bitwise int you actually stay within the type. But doing the same thing on a short or char will move outside the type by virtue of setting the high bits (normal C semantics: a short gets promoted to an int, so doing a bitwise negation on a short will actually set the high bits).
So as far as sparse is concerned, a bitwise type is not really so much about endianness as it is about making sure bits are never lost or moved around.
For example, you can use the bitwise operation to verify the __GFP_XXX mask bits. Right now they are just regular integers, which means that you can write
kmalloc(GFP_KERNEL, size);
and the compiler will not notice anything wrong. But something is seriously wrong: the GFP_KERNEL should be the second argument. If we mark it to be a bitwise type (which it is), that bug would have been noticed immediately, and you could still do all the operations that are valid of GFP_xxx values.
See the usage?
In the byte-order case, what we have is:
typedef __u16 __bitwise __le16; typedef __u16 __bitwise __be16; typedef __u32 __bitwise __le32; typedef __u32 __bitwise __be32; typedef __u64 __bitwise __le64; typedef __u64 __bitwise __be64;
and if you think about the above rules about what is acceptable for bitwise types, you'll likely immediately notice that it automatically means
you can never assign a __le16 type to any other integer type or any other bitwise type. You'd get a warning about incompatible types. Makes sense, no?
you can only do operations that are safe within that byte order. For example, it is safe to do a bitwise "&" on two __le16 values. Clearly the result is meaningful.
if you want to go outside that bitwise type, you have to convert it properly first. For example, if you want to add a constant to a __le16 type, you can do so, but you have to use the proper sequence:
__le16 sum, a, b; sum = a + b; /* INVALID! "warning: incompatible types for operation \ (+)" */ sum = cpu_to_le16(le16_to_cpu(a) + le16_to_cpu(b)); /* Ok */
See?
In short, bitwise is about more than just byte-order, but the semantics of bitwise-restricted ops happen to be the semantics that are valid for byte-order operations too.
Oh, btw, right now you only get the warnings from sparse if you use -Wbitwise on the command line. Without that, sparse will ignore the bitwise attribute.
- Linus
