Re: [PATCH] avoid negative shifts in radix-tree.c

From: Christoph Hellwig
Date: Mon Aug 27 2007 - 09:29:04 EST


On Sat, Aug 25, 2007 at 04:26:07PM +0200, Peter Firefly Lund wrote:
> (linux-vax@xxxxxxxxxxxxxxx only bcc'ed because it's subscribers only,
> Lameter addressed because I think he touched the code last, Velikov and
> Hellwig because they touched the code first.)
>
> The current code in __max_index() will shift by a negative amount first
> and only then fix the situation by ignoring the result if the shift
> amount would have been negative. This happens to work on almost any
> architecture despite not being valid C.
>
> Chapter and verse from the (draft) ISO C99 standard, "6.5.7 Bitwise
> shift operators", paragraph 3:
>
> "The integer promotions are performed on each of the operands. The
> type of the result is that of the promoted left operand. If the
> value of the right operand is negative or is greater than or equal
> to the width of the promoted left operand, the behavior is
> undefined."
>
> Right-shifting by a negative amount causes a "reserved operand fault" on
> the VAX with some gcc versions.
>
>
> Applies to 2.6.22.
> Boot tested lightly on an emulated VAX.
>
> (The function is called 7 times on booth with the values 0..6 -- I
> checked that the return values were the same + that it returns ~0UL for
> height==6 as was clearly the intention.)
>
> -Peter
>
> --- lib/radix-tree-old.c 2007-08-25 15:36:40.000000000 +0200
> +++ lib/radix-tree.c 2007-08-25 15:36:51.000000000 +0200
> @@ -980,12 +980,14 @@ radix_tree_node_ctor(void *node, struct
>
> static __init unsigned long __maxindex(unsigned int height)
> {
> - unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
> - unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1;
> -
> - if (tmp >= RADIX_TREE_INDEX_BITS)
> - index = ~0UL;
> - return index;
> + unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
> + int shift = RADIX_TREE_INDEX_BITS - tmp;
> + unsigned long index;
> +
> + if (shift < 0)
> + return ~0UL;
> + else
> + return ~0UL >> shift;

The conceptual change looks fine to me, but the code looks a little odd,
what about:

static __init unsigned long __maxindex(unsigned int height)
{
unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
int shift = RADIX_TREE_INDEX_BITS - tmp;

if (shift < 0)
return ~0UL;
return ~0UL >> shift;
}

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