From 1ca600586a61cee41e117a188d880417de3e1c00 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 1 May 2024 11:27:45 -0700 Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Support more trivial expressions. (#90414) Treat a compound operator such as |=, array subscription, sizeof, and non-type template parameter as trivial so long as subexpressions are also trivial. Also treat true/false boolean literal as trivial. --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 23 ++++++++++++++++++- .../Checkers/WebKit/uncounted-obj-arg.cpp | 23 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 287f6a52870056..6901dbb415bf76 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -311,7 +311,7 @@ class TrivialFunctionAnalysisVisitor bool VisitUnaryOperator(const UnaryOperator *UO) { // Operator '*' and '!' are allowed as long as the operand is trivial. auto op = UO->getOpcode(); - if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot) + if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot || op == UO_Not) return Visit(UO->getSubExpr()); if (UO->isIncrementOp() || UO->isDecrementOp()) { @@ -331,6 +331,16 @@ class TrivialFunctionAnalysisVisitor return Visit(BO->getLHS()) && Visit(BO->getRHS()); } + bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) { + // Compound assignment operator such as |= is trivial if its + // subexpresssions are trivial. + return VisitChildren(CAO); + } + + bool VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) { + return VisitChildren(ASE); + } + bool VisitConditionalOperator(const ConditionalOperator *CO) { // Ternary operators are trivial if their conditions & values are trivial. return VisitChildren(CO); @@ -360,6 +370,16 @@ class TrivialFunctionAnalysisVisitor return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache); } + bool + VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { + // Non-type template paramter is compile time constant and trivial. + return true; + } + + bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) { + return VisitChildren(E); + } + bool VisitPredefinedExpr(const PredefinedExpr *E) { // A predefined identifier such as "func" is considered trivial. return true; @@ -463,6 +483,7 @@ class TrivialFunctionAnalysisVisitor bool VisitFixedPointLiteral(const FixedPointLiteral *E) { return true; } bool VisitCharacterLiteral(const CharacterLiteral *E) { return true; } bool VisitStringLiteral(const StringLiteral *E) { return true; } + bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return true; } bool VisitConstantExpr(const ConstantExpr *CE) { // Constant expressions are trivial. diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp index 80a9a263dab140..63a68a994a5c64 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp @@ -201,6 +201,13 @@ class RefCounted { unsigned trivial25() const { return __c11_atomic_load((volatile _Atomic(unsigned) *)&v, __ATOMIC_RELAXED); } bool trivial26() { bool hasValue = v; return !hasValue; } bool trivial27(int v) { bool value; value = v ? 1 : 0; return value; } + bool trivial28() { return true; } + bool trivial29() { return false; } + unsigned trivial30(unsigned v) { unsigned r = 0xff; r |= v; return r; } + int trivial31(int* v) { return v[0]; } + unsigned trivial32() { return sizeof(int); } + unsigned trivial33() { return ~0xff; } + template unsigned trivial34() { return v; } static RefCounted& singleton() { static RefCounted s_RefCounted; @@ -273,6 +280,9 @@ class RefCounted { return val; } + int nonTrivial13() { return ~otherFunction(); } + int nonTrivial14() { int r = 0xff; r |= otherFunction(); return r; } + unsigned v { 0 }; Number* number { nullptr }; Enum enumValue { Enum::Value1 }; @@ -322,6 +332,15 @@ class UnrelatedClass { getFieldTrivial().trivial25(); // no-warning getFieldTrivial().trivial26(); // no-warning getFieldTrivial().trivial27(5); // no-warning + getFieldTrivial().trivial28(); // no-warning + getFieldTrivial().trivial29(); // no-warning + getFieldTrivial().trivial30(7); // no-warning + int a[] = {1, 2}; + getFieldTrivial().trivial31(a); // no-warning + getFieldTrivial().trivial32(); // no-warning + getFieldTrivial().trivial33(); // no-warning + getFieldTrivial().trivial34<7>(); // no-warning + RefCounted::singleton().trivial18(); // no-warning RefCounted::singleton().someFunction(); // no-warning @@ -351,6 +370,10 @@ class UnrelatedClass { // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} getFieldTrivial().nonTrivial12(); // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + getFieldTrivial().nonTrivial13(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + getFieldTrivial().nonTrivial14(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} } };