1 // RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core,unix.Malloc,debug.ExprInspection %s -analyzer-config eagerly-assume=false -verify
2
3 extern void clang_analyzer_eval(bool);
4 extern void clang_analyzer_warnIfReached();
5 extern "C" char *strdup(const char *s);
6
7 namespace PR14054_reduced {
8 struct Definition;
9 struct ParseNode {
10 union {
11 Definition *lexdef;
12 ParseNode *data;
13 } pn_u;
14 };
15 struct Definition : public ParseNode { };
16
CloneParseTree(ParseNode * opn,ParseNode * pn,ParseNode * x)17 void CloneParseTree(ParseNode *opn, ParseNode *pn, ParseNode *x) {
18 // This used to cause an assertion failure because:
19 // 1. The implicit operator= for unions assigns all members of the union,
20 // not just the active one (b/c there's no way to know which is active).
21 // 2. RegionStore dutifully stored all the variants at the same offset;
22 // the last one won.
23 // 3. We asked for the value of the first variant but got back a conjured
24 // symbol for the second variant.
25 // 4. We ended up trying to add a base cast to a region of the wrong type.
26 //
27 // Now (at the time this test was added), we instead treat all variants of
28 // a union as different offsets, but only allow one to be active at a time.
29 *pn = *opn;
30 x = pn->pn_u.lexdef->pn_u.lexdef;
31 }
32 }
33
34 namespace PR14054_original {
35 struct Definition;
36 struct ParseNode {
37 union {
38 struct {
39 union {}; // expected-warning {{does not declare anything}}
40 Definition *lexdef;
41 } name;
42 class {
43 int *target;
44 ParseNode *data;
45 } xmlpi;
46 } pn_u;
47 };
48 struct Definition : public ParseNode { };
49
CloneParseTree(ParseNode * opn,ParseNode * pn,ParseNode * x)50 void CloneParseTree(ParseNode *opn, ParseNode *pn, ParseNode *x) {
51 pn->pn_u = opn->pn_u;
52 x = pn->pn_u.name.lexdef->pn_u.name.lexdef;
53 }
54 }
55
56 namespace PR17596 {
57 union IntOrString {
58 int i;
59 char *s;
60 };
61
62 extern void process(IntOrString);
63
test()64 void test() {
65 IntOrString uu;
66 uu.s = strdup("");
67 process(uu);
68 }
69
testPositive()70 void testPositive() {
71 IntOrString uu;
72 uu.s = strdup("");
73 } // expected-warning{{leak}}
74
testCopy()75 void testCopy() {
76 IntOrString uu;
77 uu.i = 4;
78 clang_analyzer_eval(uu.i == 4); // expected-warning{{TRUE}}
79
80 IntOrString vv;
81 vv.i = 5;
82 uu = vv;
83 clang_analyzer_eval(uu.i == 5); // expected-warning{{TRUE}}
84 }
85
testInvalidation()86 void testInvalidation() {
87 IntOrString uu;
88 uu.s = strdup("");
89
90 IntOrString vv;
91 char str[] = "abc";
92 vv.s = str;
93
94 uu = vv;
95 } // expected-warning{{leak}}
96
testIndirectInvalidation()97 void testIndirectInvalidation() {
98 IntOrString uu;
99 char str[] = "abc";
100 uu.s = str;
101
102 clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{TRUE}}
103
104 process(uu);
105 clang_analyzer_eval(uu.s[0] == 'a'); // expected-warning{{UNKNOWN}}
106 }
107 }
108
109 namespace assume_union_contents {
110 union U {
111 int x;
112 };
113
114 U get();
115
test()116 void test() {
117 U u = get();
118 int y = 0;
119 if (u.x)
120 y = 1;
121 if (u.x)
122 y = 1 / y; // no-warning
123 }
124 } // end namespace assume_union_contents
125
126 namespace pr37688_deleted_union_destructor {
127 struct S { ~S(); };
128 struct A {
~Apr37688_deleted_union_destructor::A129 ~A() noexcept {}
130 union {
131 struct {
132 S s;
133 } ss;
134 };
135 };
foo()136 void foo() {
137 A a;
138 } // no-crash
bar()139 void bar() {
140 foo();
141 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
142 }
143 } // end namespace pr37688_deleted_union_destructor
144