Author: Ryosuke Niwa Date: 2024-05-14T22:16:06-07:00 New Revision: 24180ea0c295856a696992f072c36259a266226b
URL: https://github.com/llvm/llvm-project/commit/24180ea0c295856a696992f072c36259a266226b DIFF: https://github.com/llvm/llvm-project/commit/24180ea0c295856a696992f072c36259a266226b.diff LOG: [analyzer] Treat break, continue, goto, and label statements as trivial in WebKit checkers. (#91873) Also allow CXXBindTemporaryExpr, which creates a temporary object with a non-trivial destructor, and add a few more std and WTF functions to the explicitly allowed list. Added: Modified: clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index ad493587affa0..950d35a090a3f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -308,6 +308,12 @@ class TrivialFunctionAnalysisVisitor bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + // break, continue, goto, and label statements are always trivial. + bool VisitBreakStmt(const BreakStmt *) { return true; } + bool VisitContinueStmt(const ContinueStmt *) { return true; } + bool VisitGotoStmt(const GotoStmt *) { return true; } + bool VisitLabelStmt(const LabelStmt *) { return true; } + bool VisitUnaryOperator(const UnaryOperator *UO) { // Unary operators are trivial if its operand is trivial except co_await. return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr()); @@ -349,12 +355,17 @@ class TrivialFunctionAnalysisVisitor return false; const auto &Name = safeGetName(Callee); + if (Callee->isInStdNamespace() && + (Name == "addressof" || Name == "forward" || Name == "move")) + return true; + if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" || + Name == "WTFCrashWithSecurityImplication" || Name == "WTFCrash" || Name == "WTFReportAssertionFailure" || Name == "isMainThread" || Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" || Name == "isWebThread" || Name == "isUIThread" || - Name == "compilerFenceForCrash" || Name == "bitwise_cast" || - Name == "addressof" || Name.find("__builtin") == 0) + Name == "mayBeGCThread" || Name == "compilerFenceForCrash" || + Name == "bitwise_cast" || Name.find("__builtin") == 0) return true; return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache); @@ -445,6 +456,14 @@ class TrivialFunctionAnalysisVisitor return Visit(VMT->getSubExpr()); } + bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE) { + if (auto *Temp = BTE->getTemporary()) { + if (!TrivialFunctionAnalysis::isTrivialImpl(Temp->getDestructor(), Cache)) + return false; + } + return Visit(BTE->getSubExpr()); + } + bool VisitExprWithCleanups(const ExprWithCleanups *EWC) { return Visit(EWC->getSubExpr()); } diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp index 073f3252160ee..ed37671df3d3e 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp @@ -7,6 +7,9 @@ void WTFBreakpointTrap(); void WTFCrashWithInfo(int, const char*, const char*, int); void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion); +void WTFCrash(void); +void WTFCrashWithSecurityImplication(void); + inline void compilerFenceForCrash() { asm volatile("" ::: "memory"); @@ -62,14 +65,25 @@ void WTFCrashWithInfo(int line, const char* file, const char* function, int coun template<typename ToType, typename FromType> ToType bitwise_cast(FromType from); +namespace std { + template<typename T> T* addressof(T& arg); +template<typename T> +T&& forward(T& arg); + +template<typename T> +T&& move( T&& t ); + +} // namespace std + bool isMainThread(); bool isMainThreadOrGCThread(); bool isMainRunLoop(); bool isWebThread(); bool isUIThread(); +bool mayBeGCThread(); enum class Flags : unsigned short { Flag1 = 1 << 0, @@ -161,16 +175,42 @@ class Number { class ComplexNumber { public: - ComplexNumber() : real(0), complex(0) { } + ComplexNumber() : realPart(0), complexPart(0) { } ComplexNumber(const ComplexNumber&); - ComplexNumber& operator++() { real.someMethod(); return *this; } + ComplexNumber& operator++() { realPart.someMethod(); return *this; } ComplexNumber operator++(int); ComplexNumber& operator<<(int); ComplexNumber& operator+(); + const Number& real() const { return realPart; } + private: - Number real; - Number complex; + Number realPart; + Number complexPart; +}; + +class ObjectWithNonTrivialDestructor { +public: + ObjectWithNonTrivialDestructor() { } + ObjectWithNonTrivialDestructor(unsigned v) : v(v) { } + ~ObjectWithNonTrivialDestructor() { } + + unsigned value() const { return v; } + +private: + unsigned v { 0 }; +}; + +class ObjectWithMutatingDestructor { +public: + ObjectWithMutatingDestructor() : n(0) { } + ObjectWithMutatingDestructor(int n) : n(n) { } + ~ObjectWithMutatingDestructor() { n.someMethod(); } + + unsigned value() const { return n.value(); } + +private: + Number n; }; class RefCounted { @@ -248,7 +288,7 @@ class RefCounted { int trivial40() { return v << 2; } unsigned trivial41() { v = ++s_v; return v; } unsigned trivial42() { return bitwise_cast<unsigned long>(nullptr); } - Number* trivial43() { return addressof(*number); } + Number* trivial43() { return std::addressof(*number); } Number* trivial44() { return new Number(1); } ComplexNumber* trivial45() { return new ComplexNumber(); } void trivial46() { ASSERT(isMainThread()); } @@ -256,6 +296,21 @@ class RefCounted { void trivial48() { ASSERT(isMainRunLoop()); } void trivial49() { ASSERT(isWebThread()); } void trivial50() { ASSERT(isUIThread()); } + void trivial51() { ASSERT(mayBeGCThread()); } + void trivial52() { WTFCrash(); } + void trivial53() { WTFCrashWithSecurityImplication(); } + unsigned trivial54() { return ComplexNumber().real().value(); } + Number&& trivial55() { return std::forward(*number); } + unsigned trivial56() { Number n { 5 }; return std::move(n).value(); } + void trivial57() { do { break; } while (1); } + void trivial58() { do { continue; } while (0); } + void trivial59() { + do { goto label; } + while (0); + label: + return; + } + unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); } static RefCounted& singleton() { static RefCounted s_RefCounted; @@ -335,6 +390,7 @@ class RefCounted { ComplexNumber nonTrivial17() { return complex << 2; } ComplexNumber nonTrivial18() { return +complex; } ComplexNumber* nonTrivial19() { return new ComplexNumber(complex); } + unsigned nonTrivial20() { return ObjectWithMutatingDestructor { 7 }.value(); } static unsigned s_v; unsigned v { 0 }; @@ -413,6 +469,16 @@ class UnrelatedClass { getFieldTrivial().trivial48(); // no-warning getFieldTrivial().trivial49(); // no-warning getFieldTrivial().trivial50(); // no-warning + getFieldTrivial().trivial51(); // no-warning + getFieldTrivial().trivial52(); // no-warning + getFieldTrivial().trivial53(); // no-warning + getFieldTrivial().trivial54(); // no-warning + getFieldTrivial().trivial55(); // no-warning + getFieldTrivial().trivial56(); // no-warning + getFieldTrivial().trivial57(); // no-warning + getFieldTrivial().trivial58(); // no-warning + getFieldTrivial().trivial59(); // no-warning + getFieldTrivial().trivial60(); // no-warning RefCounted::singleton().trivial18(); // no-warning RefCounted::singleton().someFunction(); // no-warning @@ -457,6 +523,8 @@ class UnrelatedClass { // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} getFieldTrivial().nonTrivial19(); // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + getFieldTrivial().nonTrivial20(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} } }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits