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