1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 2 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 3 // RUN: -x c %s 4 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 5 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 6 // RUN: -x c++ -std=c++14 %s 7 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 8 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 9 // RUN: -x c++ -std=c++17 %s 10 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 11 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 12 // RUN: -DINLINE -x c %s 13 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 14 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 15 // RUN: -DINLINE -x c++ -std=c++14 %s 16 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ 17 // RUN: -analyzer-checker=debug.ExprInspection -verify\ 18 // RUN: -DINLINE -x c++ -std=c++17 %s 19 20 void clang_analyzer_eval(int); 21 22 struct S { 23 int field; 24 25 #if __cplusplus 26 const struct S *getThis() const { return this; } 27 const struct S *operator +() const { return this; } 28 29 bool check() const { return this == this; } 30 bool operator !() const { return this != this; } 31 32 int operator *() const { return field; } 33 #endif 34 }; 35 36 #if __cplusplus 37 const struct S *operator -(const struct S &s) { return &s; } 38 bool operator ~(const struct S &s) { return (&s) != &s; } 39 #endif 40 41 42 #ifdef INLINE 43 struct S getS() { 44 struct S s = { 42 }; 45 return s; 46 } 47 #else 48 struct S getS(); 49 #endif 50 51 52 void testAssignment() { 53 struct S s = getS(); 54 55 if (s.field != 42) return; 56 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} 57 58 s.field = 0; 59 clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}} 60 61 #if __cplusplus 62 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} 63 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} 64 clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}} 65 66 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} 67 clang_analyzer_eval(!s); // expected-warning{{FALSE}} 68 clang_analyzer_eval(~s); // expected-warning{{FALSE}} 69 70 clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}} 71 #endif 72 } 73 74 75 void testImmediateUse() { 76 int x = getS().field; 77 78 if (x != 42) return; 79 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 80 81 #if __cplusplus 82 clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}} 83 clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}} 84 clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}} 85 86 clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}} 87 clang_analyzer_eval(!getS()); // expected-warning{{FALSE}} 88 clang_analyzer_eval(~getS()); // expected-warning{{FALSE}} 89 #endif 90 } 91 92 int getConstrainedField(struct S s) { 93 if (s.field != 42) return 42; 94 return s.field; 95 } 96 97 int getAssignedField(struct S s) { 98 s.field = 42; 99 return s.field; 100 } 101 102 void testArgument() { 103 clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}} 104 clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}} 105 } 106 107 void testImmediateUseParens() { 108 int x = ((getS())).field; 109 110 if (x != 42) return; 111 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 112 113 clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}} 114 clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}} 115 116 #if __cplusplus 117 clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}} 118 clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}} 119 clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}} 120 #endif 121 } 122 123 124 //-------------------- 125 // C++-only tests 126 //-------------------- 127 128 #if __cplusplus 129 void testReferenceAssignment() { 130 const S &s = getS(); 131 132 if (s.field != 42) return; 133 clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} 134 135 clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} 136 clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} 137 138 clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} 139 clang_analyzer_eval(!s); // expected-warning{{FALSE}} 140 clang_analyzer_eval(~s); // expected-warning{{FALSE}} 141 142 clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}} 143 } 144 145 146 int getConstrainedFieldRef(const S &s) { 147 if (s.field != 42) return 42; 148 return s.field; 149 } 150 151 bool checkThis(const S &s) { 152 return s.getThis() == &s; 153 } 154 155 bool checkThisOp(const S &s) { 156 return +s == &s; 157 } 158 159 bool checkThisStaticOp(const S &s) { 160 return -s == &s; 161 } 162 163 void testReferenceArgument() { 164 clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}} 165 clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}} 166 clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}} 167 clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}} 168 } 169 170 171 int getConstrainedFieldOp(S s) { 172 if (*s != 42) return 42; 173 return *s; 174 } 175 176 int getConstrainedFieldRefOp(const S &s) { 177 if (*s != 42) return 42; 178 return *s; 179 } 180 181 void testImmediateUseOp() { 182 int x = *getS(); 183 if (x != 42) return; 184 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 185 186 clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}} 187 clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}} 188 } 189 190 namespace EmptyClass { 191 struct Base { 192 int& x; 193 194 Base(int& x) : x(x) {} 195 }; 196 197 struct Derived : public Base { 198 Derived(int& x) : Base(x) {} 199 200 void operator=(int a) { x = a; } 201 }; 202 203 Derived ref(int& a) { return Derived(a); } 204 205 // There used to be a warning here, because analyzer treated Derived as empty. 206 int test() { 207 int a; 208 ref(a) = 42; 209 return a; // no warning 210 } 211 } 212 213 #if __cplusplus >= 201703L 214 namespace aggregate_inheritance_cxx17 { 215 struct A { 216 int x; 217 }; 218 219 struct B { 220 int y; 221 }; 222 223 struct C: B { 224 int z; 225 }; 226 227 struct D: A, C { 228 int w; 229 }; 230 231 void foo() { 232 D d{1, 2, 3, 4}; 233 clang_analyzer_eval(d.x == 1); // expected-warning{{TRUE}} 234 clang_analyzer_eval(d.y == 2); // expected-warning{{TRUE}} 235 clang_analyzer_eval(d.z == 3); // expected-warning{{TRUE}} 236 clang_analyzer_eval(d.w == 4); // expected-warning{{TRUE}} 237 } 238 } // namespace aggregate_inheritance_cxx17 239 #endif 240 241 namespace flex_array_inheritance_cxx17 { 242 struct A { 243 int flexible_array[]; 244 }; 245 246 struct B { 247 long cookie; 248 }; 249 250 struct C : B { 251 A a; 252 }; 253 254 void foo() { 255 C c{}; // no-crash 256 } 257 } // namespace flex_array_inheritance_cxx17 258 #endif 259