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 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 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 64 void test() { 65 IntOrString uu; 66 uu.s = strdup(""); 67 process(uu); 68 } 69 70 void testPositive() { 71 IntOrString uu; 72 uu.s = strdup(""); 73 } // expected-warning{{leak}} 74 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 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 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 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 { 129 ~A() noexcept {} 130 union { 131 struct { 132 S s; 133 } ss; 134 }; 135 }; 136 void foo() { 137 A a; 138 } // no-crash 139 void bar() { 140 foo(); 141 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} 142 } 143 } // end namespace pr37688_deleted_union_destructor 144