Question

I am working with a mix of C90 and C99 (cannot fully use C99 for reasons I better don't discuss, because they aren't good for my blood pressure and would endanger the life of the person preventing us from moving our code base into the current millennium). Still I am going to quote the C99 standard.

I have code that is roughly like this, when condensed to the bare minimum (test.c):

#include <stdio.h>

unsigned int foo(unsigned int n)
{
    unsigned int x, y;
    n = n - 264;
    x = (n >> 2) + 1;
    y = 1U << (x + 2U);
    return y;
}

int main(void)
{
    printf("%u\n", foo(384));
    return 0;
}

Of course the value passed to foo() can conceivably be bigger than the value given here. Still 384 is the lowest value that will trigger the Clang static analyzer (3.4 compiled from the release tag) to spit a warning:

$ clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -analyzer-checker=core -internal-isystem /usr/local/include -internal-isystem $HOME/bin/LLVM/bin/../lib/clang/3.4/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -x c test.c
test.c:8:9: warning: The result of the '<<' expression is undefined
        y = 1U << (x + 2U);
            ~~~^~~~~~~~~~~
1 warning generated.

Now going through the lines one by one:

// n == 384
n = n - 264;        // n := 384 - 264
// n == 120
x = (n >> 2) + 1;   // x := (120 div 4) + 1
// x == 31
y = 1U << (x + 2U); // y := 1 << 33

So, alright it pushes all the meaningful bits out of the integer, and from my understanding of the following (from here) this should give me simply zero:

6.5.7 Bitwise shift operators

...

4

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

From how I read this, an undefined result can only occur ever, if signed values are involved. However, I took care that all of the values are unsigned, even made it explicit on the literals.

Am I wrong or is the Clang static analyzer overly zealous?


The original incarnation of this code is from Jonathan Bennetts JB01 implementation (version 1.40a) in C++.

Was it helpful?

Solution

In the C99 standard, right before your quoted part:

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.

unsigned int in most machines today has 32 bits, that makes left shift 33, undefined behavior.

OTHER TIPS

That same paragraph also says, before the part you quoted, in paragraph 6.5.7.3:

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.

Thus, clang is doing a fine job since the behavior is indeed undefined once you shift more bits than the promoted left operand can hold.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top