Skip to content

Commit 3ce43c8

Browse files
authored
[WebKit checkers] Don't treat virtual functions as safe. (#129632)
Prior to this PR, WebKit checkers erroneously treated functions to be safe if it has a trivial body even if it was marked as virtual. In the case of a virtual function, it can have an override which does not pass the triviality check so we must not make such an assumption. This PR also restricts the allowed operator overloading while finding the pointer origin to just operators on smart pointer types: Ref, RefPtr, CheckedRef, CheckedPtr, RetainPtr, WeakPtr, WeakRef, unique_ptr, and UniqueRef.
1 parent 9a5a8c9 commit 3ce43c8

File tree

6 files changed

+49
-6
lines changed

6 files changed

+49
-6
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,17 @@ bool tryToFindPtrOrigin(
9191
}
9292

9393
if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) {
94-
if (operatorCall->getNumArgs() == 1) {
95-
E = operatorCall->getArg(0);
96-
continue;
94+
if (auto *Callee = operatorCall->getDirectCallee()) {
95+
auto ClsName = safeGetName(Callee->getParent());
96+
if (isRefType(ClsName) || isCheckedPtr(ClsName) ||
97+
isRetainPtr(ClsName) || ClsName == "unique_ptr" ||
98+
ClsName == "UniqueRef" || ClsName == "WeakPtr" ||
99+
ClsName == "WeakRef") {
100+
if (operatorCall->getNumArgs() == 1) {
101+
E = operatorCall->getArg(0);
102+
continue;
103+
}
104+
}
97105
}
98106
}
99107

@@ -215,7 +223,7 @@ bool EnsureFunctionAnalysis::isACallToEnsureFn(const clang::Expr *E) const {
215223
if (!Callee)
216224
return false;
217225
auto *Body = Callee->getBody();
218-
if (!Body)
226+
if (!Body || Callee->isVirtualAsWritten())
219227
return false;
220228
auto [CacheIt, IsNew] = Cache.insert(std::make_pair(Callee, false));
221229
if (IsNew)

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,10 @@ class TrivialFunctionAnalysisVisitor
480480
TrivialFunctionAnalysisVisitor(CacheTy &Cache) : Cache(Cache) {}
481481

482482
bool IsFunctionTrivial(const Decl *D) {
483+
if (auto *FnDecl = dyn_cast<FunctionDecl>(D)) {
484+
if (FnDecl->isVirtualAsWritten())
485+
return false;
486+
}
483487
return WithCachedResult(D, [&]() {
484488
if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
485489
for (auto *CtorInit : CtorDecl->inits()) {

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ bool isRefType(const std::string &Name);
131131
/// \returns true if \p Name is CheckedRef or CheckedPtr, false if not.
132132
bool isCheckedPtr(const std::string &Name);
133133

134+
/// \returns true if \p Name is RetainPtr or its variant, false if not.
135+
bool isRetainPtr(const std::string &Name);
136+
134137
/// \returns true if \p M is getter of a ref-counted class, false if not.
135138
std::optional<bool> isGetterOfSafePtr(const clang::CXXMethodDecl *Method);
136139

clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class RawPtrRefCallArgsChecker
172172
if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
173173
return true;
174174

175-
if (Callee && TFA.isTrivial(Callee))
175+
if (Callee && TFA.isTrivial(Callee) && !Callee->isVirtualAsWritten())
176176
return true;
177177

178178
if (CE->getNumArgs() == 0)

clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,4 +464,17 @@ namespace local_var_for_singleton {
464464
RefCountable* bar = singleton();
465465
RefCountable* baz = otherSingleton();
466466
}
467+
}
468+
469+
namespace virtual_function {
470+
struct SomeObject {
471+
virtual RefCountable* provide() { return nullptr; }
472+
virtual RefCountable* operator&() { return nullptr; }
473+
};
474+
void foo(SomeObject* obj) {
475+
auto* bar = obj->provide();
476+
// expected-warning@-1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}
477+
auto* baz = &*obj;
478+
// expected-warning@-1{{Local variable 'baz' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}
479+
}
467480
}

clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ class ComplexNumber {
196196
ComplexNumber& operator+();
197197

198198
const Number& real() const { return realPart; }
199+
const Number& complex() const;
200+
201+
void ref() const;
202+
void deref() const;
199203

200204
private:
201205
Number realPart;
@@ -240,6 +244,11 @@ class SomeType : public BaseType {
240244
using BaseType::BaseType;
241245
};
242246

247+
struct OtherObj {
248+
unsigned v { 0 };
249+
OtherObj* children[4] { nullptr };
250+
};
251+
243252
void __libcpp_verbose_abort(const char *__format, ...);
244253

245254
class RefCounted {
@@ -375,7 +384,7 @@ class RefCounted {
375384
double y;
376385
};
377386
void trivial68() { point pt = { 1.0 }; }
378-
unsigned trivial69() { return offsetof(RefCounted, children); }
387+
unsigned trivial69() { return offsetof(OtherObj, children); }
379388
DerivedNumber* trivial70() { [[clang::suppress]] return static_cast<DerivedNumber*>(number); }
380389

381390
static RefCounted& singleton() {
@@ -467,6 +476,8 @@ class RefCounted {
467476
unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); }
468477
unsigned nonTrivial23() { return DerivedNumber("123").value(); }
469478
SomeType nonTrivial24() { return SomeType("123"); }
479+
virtual void nonTrivial25() { }
480+
virtual ComplexNumber* operator->() { return nullptr; }
470481

471482
static unsigned s_v;
472483
unsigned v { 0 };
@@ -642,6 +653,10 @@ class UnrelatedClass {
642653
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
643654
getFieldTrivial().nonTrivial24();
644655
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
656+
getFieldTrivial().nonTrivial25();
657+
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
658+
getFieldTrivial()->complex();
659+
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
645660
}
646661

647662
void setField(RefCounted*);

0 commit comments

Comments
 (0)