Jordan Rose e185d73101 [analyzer] Special-case bitfields when finding sub-region bindings.
Previously we were assuming that we'd never ask for the sub-region bindings
of a bitfield, since a bitfield cannot have subregions. However,
unification of code paths has made that assumption invalid. While we could
take advantage of this by just checking for the single possible binding,
it's probably better to do the right thing, so that if/when we someday
support unions we'll do the right thing there, too.

This fixes a handful of false positives in analyzing LLVM.

<rdar://problem/13325522>

llvm-svn: 176388
2013-03-01 23:03:17 +00:00

126 lines
2.6 KiB
C

// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection %s -analyzer-store=region -verify
void clang_analyzer_eval(int);
unsigned foo();
typedef struct bf { unsigned x:2; } bf;
void bar() {
bf y;
*(unsigned*)&y = foo();
y.x = 1;
}
struct s {
int n;
};
void f() {
struct s a;
int *p = &(a.n) + 1;
}
typedef struct {
int x,y;
} Point;
Point getit(void);
void test() {
Point p;
(void)(p = getit()).x;
}
#define true ((bool)1)
#define false ((bool)0)
typedef _Bool bool;
void testLazyCompoundVal() {
Point p = {42, 0};
Point q;
clang_analyzer_eval((q = p).x == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(q.x == 42); // expected-warning{{TRUE}}
}
struct Bits {
unsigned a : 1;
unsigned b : 2;
unsigned c : 1;
bool x;
struct InnerBits {
bool y;
unsigned d : 16;
unsigned e : 6;
unsigned f : 2;
} inner;
};
void testBitfields() {
struct Bits bits;
if (foo() && bits.b) // expected-warning {{garbage}}
return;
if (foo() && bits.inner.e) // expected-warning {{garbage}}
return;
bits.c = 1;
clang_analyzer_eval(bits.c == 1); // expected-warning {{TRUE}}
if (foo() && bits.b) // expected-warning {{garbage}}
return;
if (foo() && bits.x) // expected-warning {{garbage}}
return;
bits.x = true;
clang_analyzer_eval(bits.x == true); // expected-warning{{TRUE}}
bits.b = 2;
clang_analyzer_eval(bits.x == true); // expected-warning{{TRUE}}
if (foo() && bits.c) // no-warning
return;
bits.inner.e = 50;
if (foo() && bits.inner.e) // no-warning
return;
if (foo() && bits.inner.y) // expected-warning {{garbage}}
return;
if (foo() && bits.inner.f) // expected-warning {{garbage}}
return;
extern struct InnerBits getInner();
bits.inner = getInner();
if (foo() && bits.inner.e) // no-warning
return;
if (foo() && bits.inner.y) // no-warning
return;
if (foo() && bits.inner.f) // no-warning
return;
bits.inner.f = 1;
if (foo() && bits.inner.e) // no-warning
return;
if (foo() && bits.inner.y) // no-warning
return;
if (foo() && bits.inner.f) // no-warning
return;
if (foo() && bits.a) // expected-warning {{garbage}}
return;
}
//-----------------------------------------------------------------------------
// Incorrect behavior
//-----------------------------------------------------------------------------
void testTruncation() {
struct Bits bits;
bits.c = 0x11; // expected-warning{{implicit truncation}}
// FIXME: We don't model truncation of bitfields.
clang_analyzer_eval(bits.c == 1); // expected-warning {{FALSE}}
}