llvm-project/clang/test/Analysis/unions.cpp

144 lines
3.2 KiB
C++

// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core,unix.Malloc,debug.ExprInspection %s -analyzer-config eagerly-assume=false -verify
extern void clang_analyzer_eval(bool);
extern void clang_analyzer_warnIfReached();
extern "C" char *strdup(const char *s);
namespace PR14054_reduced {
struct Definition;
struct ParseNode {
union {
Definition *lexdef;
ParseNode *data;
} pn_u;
};
struct Definition : public ParseNode { };
void CloneParseTree(ParseNode *opn, ParseNode *pn, ParseNode *x) {
// This used to cause an assertion failure because:
// 1. The implicit operator= for unions assigns all members of the union,
// not just the active one (b/c there's no way to know which is active).
// 2. RegionStore dutifully stored all the variants at the same offset;
// the last one won.
// 3. We asked for the value of the first variant but got back a conjured
// symbol for the second variant.
// 4. We ended up trying to add a base cast to a region of the wrong type.
//
// Now (at the time this test was added), we instead treat all variants of
// a union as different offsets, but only allow one to be active at a time.
*pn = *opn;
x = pn->pn_u.lexdef->pn_u.lexdef;
}
}
namespace PR14054_original {
struct Definition;
struct ParseNode {
union {
struct {
union {}; // expected-warning {{does not declare anything}}
Definition *lexdef;
} name;
class {
int *target;
ParseNode *data;
} xmlpi;
} pn_u;
};
struct Definition : public ParseNode { };
void CloneParseTree(ParseNode *opn, ParseNode *pn, ParseNode *x) {
pn->pn_u = opn->pn_u;
x = pn->pn_u.name.lexdef->pn_u.name.lexdef;
}
}
namespace PR17596 {
union IntOrString {
int i;
char *s;
};
extern void process(IntOrString);
void test() {
IntOrString uu;
uu.s = strdup("");
process(uu);
}
void testPositive() {
IntOrString uu;
uu.s = strdup("");
} // expected-warning{{leak}}
void testCopy() {
IntOrString uu;
uu.i = 4;
clang_analyzer_eval(uu.i == 4); // expected-warning{{TRUE}}
IntOrString vv;
vv.i = 5;
uu = vv;
clang_analyzer_eval(uu.i == 5); // expected-warning{{TRUE}}
}
void testInvalidation() {
IntOrString uu;
uu.s = strdup("");
IntOrString vv;
char str[] = "abc";
vv.s = str;
uu = vv;
} // expected-warning{{leak}}
void testIndirectInvalidation() {
IntOrString uu;
char str[] = "abc";
uu.s = str;
clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{TRUE}}
process(uu);
clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{UNKNOWN}}
}
}
namespace assume_union_contents {
union U {
int x;
};
U get();
void test() {
U u = get();
int y = 0;
if (u.x)
y = 1;
if (u.x)
y = 1 / y; // no-warning
}
} // end namespace assume_union_contents
namespace pr37688_deleted_union_destructor {
struct S { ~S(); };
struct A {
~A() noexcept {}
union {
struct {
S s;
} ss;
};
};
void foo() {
A a;
} // no-crash
void bar() {
foo();
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
} // end namespace pr37688_deleted_union_destructor