320 lines · cpp
1// RUN: %clang_analyze_cc1 -Wno-error=return-type -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s2 3void clang_analyzer_eval(bool);4 5struct A {6 int x;7 void foo() const;8 void bar();9 10 void testImplicitThisSyntax() {11 x = 3;12 foo();13 clang_analyzer_eval(x == 3); // expected-warning{{TRUE}}14 bar();15 clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}}16 }17};18 19struct B {20 mutable int mut;21 void foo() const;22};23 24struct C {25 int *p;26 void foo() const;27};28 29struct MutBase {30 mutable int b_mut;31};32 33struct MutDerived : MutBase {34 void foo() const;35};36 37struct PBase {38 int *p;39};40 41struct PDerived : PBase {42 void foo() const;43};44 45struct Inner {46 int x;47 int *p;48 void bar() const;49};50 51struct Outer {52 int x;53 Inner in;54 void foo() const;55};56 57void checkThatConstMethodWithoutDefinitionDoesNotInvalidateObject() {58 A t;59 t.x = 3;60 t.foo();61 clang_analyzer_eval(t.x == 3); // expected-warning{{TRUE}}62 // Test non-const does invalidate63 t.bar();64 clang_analyzer_eval(t.x); // expected-warning{{UNKNOWN}}65}66 67void checkThatConstMethodDoesInvalidateMutableFields() {68 B t;69 t.mut = 4;70 t.foo();71 clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}72}73 74void checkThatConstMethodDoesInvalidatePointedAtMemory() {75 int x = 1;76 C t;77 t.p = &x;78 t.foo();79 clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}80 clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}81}82 83void checkThatConstMethodDoesInvalidateInheritedMutableFields() {84 MutDerived t;85 t.b_mut = 4;86 t.foo();87 clang_analyzer_eval(t.b_mut); // expected-warning{{UNKNOWN}}88}89 90void checkThatConstMethodDoesInvalidateInheritedPointedAtMemory() {91 int x = 1;92 PDerived t;93 t.p = &x;94 t.foo();95 clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}96 clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}97}98 99void checkThatConstMethodDoesInvalidateContainedPointedAtMemory() {100 int x = 1;101 Outer t;102 t.x = 2;103 t.in.p = &x;104 t.foo();105 clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}106 clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}}107 clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}}108}109 110void checkThatContainedConstMethodDoesNotInvalidateObjects() {111 Outer t;112 t.x = 1;113 t.in.x = 2;114 t.in.bar();115 clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}116 clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}117}118 119void checkPointerTypedThisExpression(A *a) {120 a->x = 3;121 a->foo();122 clang_analyzer_eval(a->x == 3); // expected-warning{{TRUE}}123 a->bar();124 clang_analyzer_eval(a->x == 3); // expected-warning{{UNKNOWN}}125}126 127void checkReferenceTypedThisExpression(A &a) {128 a.x = 3;129 a.foo();130 clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}}131 a.bar();132 clang_analyzer_eval(a.x == 3); // expected-warning{{UNKNOWN}}133}134 135// --- Versions of the above tests where the const method is inherited --- //136 137struct B1 {138 void foo() const;139};140 141struct D1 : public B1 {142 int x;143};144 145struct D2 : public B1 {146 mutable int mut;147};148 149struct D3 : public B1 {150 int *p;151};152 153struct DInner : public B1 {154 int x;155 int *p;156};157 158struct DOuter : public B1 {159 int x;160 DInner in;161};162 163void checkThatInheritedConstMethodDoesNotInvalidateObject() {164 D1 t;165 t.x = 1;166 t.foo();167 clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}168}169 170void checkThatInheritedConstMethodDoesInvalidateMutableFields() {171 D2 t;172 t.mut = 1;173 t.foo();174 clang_analyzer_eval(t.mut); // expected-warning{{UNKNOWN}}175}176 177void checkThatInheritedConstMethodDoesInvalidatePointedAtMemory() {178 int x = 1;179 D3 t;180 t.p = &x;181 t.foo();182 clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}183 clang_analyzer_eval(t.p == &x); // expected-warning{{TRUE}}184}185 186void checkThatInheritedConstMethodDoesInvalidateContainedPointedAtMemory() {187 int x = 1;188 DOuter t;189 t.x = 2;190 t.in.x = 3;191 t.in.p = &x;192 t.foo();193 clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}194 clang_analyzer_eval(t.x == 2); // expected-warning{{TRUE}}195 clang_analyzer_eval(t.in.x == 3); // expected-warning{{TRUE}}196 clang_analyzer_eval(t.in.p == &x); // expected-warning{{TRUE}}197}198 199void checkThatInheritedContainedConstMethodDoesNotInvalidateObjects() {200 DOuter t;201 t.x = 1;202 t.in.x = 2;203 t.in.foo();204 clang_analyzer_eval(t.x == 1); // expected-warning{{TRUE}}205 clang_analyzer_eval(t.in.x == 2); // expected-warning{{TRUE}}206}207 208// --- PR21606 --- //209 210struct s1 {211 void g(const int *i) const;212};213 214struct s2 {215 void f(int *i) {216 m_i = i;217 m_s.g(m_i);218 if (m_i)219 *i = 42; // no-warning220 }221 222 int *m_i;223 s1 m_s;224};225 226void PR21606()227{228 s2().f(0);229}230 231// --- PR25392 --- //232 233struct HasConstMemberFunction {234public:235 void constMemberFunction() const;236};237 238HasConstMemberFunction hasNoReturn() { } // expected-warning {{non-void function does not return a value}}239 240void testUnknownWithConstMemberFunction() {241 hasNoReturn().constMemberFunction();242}243 244void testNonRegionLocWithConstMemberFunction() {245 (*((HasConstMemberFunction *)(&&label))).constMemberFunction();246 247 label: return;248}249 250// FIXME251// When there is a circular reference to an object and a const method is called252// the object is not invalidated because TK_PreserveContents has already been253// set.254struct Outer2;255 256struct InnerWithRef {257 Outer2 *ref;258};259 260struct Outer2 {261 int x;262 InnerWithRef in;263 void foo() const;264};265 266void checkThatConstMethodCallDoesInvalidateObjectForCircularReferences() {267 Outer2 t;268 t.x = 1;269 t.in.ref = &t;270 t.foo();271 // FIXME: Should be UNKNOWN.272 clang_analyzer_eval(t.x); // expected-warning{{TRUE}}273}274 275namespace gh77378 {276template <typename Signature> class callable;277 278template <typename R> class callable<R()> {279 struct CallableType {280 bool operator()();281 };282 using MethodType = R (CallableType::*)();283 CallableType *object_{nullptr};284 MethodType method_;285 286public:287 callable() = default;288 289 template <typename T>290 constexpr callable(const T &obj)291 : object_{reinterpret_cast<CallableType *>(&const_cast<T &>(obj))},292 method_{reinterpret_cast<MethodType>(293 static_cast<bool (T::*)() const>(&T::operator()))} {}294 295 constexpr bool const_method() const {296 return (object_->*(method_))();297 }298 299 callable call() const & {300 static const auto L = [this]() {301 while (true) {302 // This should not crash when conservative eval calling the member function303 // when it unwinds the call stack due to exhausting the budget or reaching304 // the inlining limit.305 if (this->const_method()) {306 break;307 }308 }309 return true;310 };311 return L;312 }313};314 315void entry() {316 callable<bool()>{}.call().const_method();317 // expected-warning@-1 {{Address of stack memory associated with temporary object of type 'callable<bool ()>' is still referred to by the static variable 'L' upon returning to the caller. This will be a dangling reference}}318}319} // namespace gh77378320