Skip to content

Commit 88cb9d6

Browse files
Merge pull request #11408 from rniwa/merge-webkit-checker-fixes-2025-09-23
Merge webkit checker fixes 2025 09 23
2 parents 21179c7 + 063425a commit 88cb9d6

18 files changed

+222
-17
lines changed

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

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ bool tryToFindPtrOrigin(
9191
continue;
9292
}
9393
if (auto *call = dyn_cast<CallExpr>(E)) {
94+
if (auto *Callee = call->getCalleeDecl()) {
95+
if (Callee->hasAttr<CFReturnsRetainedAttr>() ||
96+
Callee->hasAttr<NSReturnsRetainedAttr>()) {
97+
return callback(E, true);
98+
}
99+
}
100+
94101
if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
95102
if (auto *decl = memberCall->getMethodDecl()) {
96103
std::optional<bool> IsGetterOfRefCt = isGetterOfSafePtr(decl);
@@ -153,6 +160,29 @@ bool tryToFindPtrOrigin(
153160
if (Name == "__builtin___CFStringMakeConstantString" ||
154161
Name == "NSClassFromString")
155162
return callback(E, true);
163+
} else if (auto *CalleeE = call->getCallee()) {
164+
if (auto *E = dyn_cast<DeclRefExpr>(CalleeE->IgnoreParenCasts())) {
165+
if (isSingleton(E->getFoundDecl()))
166+
return callback(E, true);
167+
}
168+
}
169+
170+
// Sometimes, canonical type erroneously turns Ref<T> into T.
171+
// Workaround this problem by checking again if the original type was
172+
// a SubstTemplateTypeParmType of a safe smart pointer type (e.g. Ref).
173+
if (auto *CalleeDecl = call->getCalleeDecl()) {
174+
if (auto *FD = dyn_cast<FunctionDecl>(CalleeDecl)) {
175+
auto RetType = FD->getReturnType();
176+
if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(RetType)) {
177+
if (auto *SubstType = Subst->desugar().getTypePtr()) {
178+
if (auto *RD = dyn_cast<RecordType>(SubstType)) {
179+
if (auto *CXX = dyn_cast<CXXRecordDecl>(RD->getDecl()))
180+
if (isSafePtr(CXX))
181+
return callback(E, true);
182+
}
183+
}
184+
}
185+
}
156186
}
157187
}
158188
if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
@@ -208,13 +238,25 @@ bool isASafeCallArg(const Expr *E) {
208238
return true;
209239
}
210240
}
241+
if (isa<CXXTemporaryObjectExpr>(E))
242+
return true; // A temporary lives until the end of this statement.
211243
if (isConstOwnerPtrMemberExpr(E))
212244
return true;
213245

214246
// TODO: checker for method calls on non-refcounted objects
215247
return isa<CXXThisExpr>(E);
216248
}
217249

250+
bool isNullPtr(const clang::Expr *E) {
251+
if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E))
252+
return true;
253+
if (auto *Int = dyn_cast_or_null<IntegerLiteral>(E)) {
254+
if (Int->getValue().isZero())
255+
return true;
256+
}
257+
return false;
258+
}
259+
218260
bool isConstOwnerPtrMemberExpr(const clang::Expr *E) {
219261
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) {
220262
if (auto *Callee = MCE->getDirectCallee()) {
@@ -273,7 +315,7 @@ class EnsureFunctionVisitor
273315
bool VisitReturnStmt(const ReturnStmt *RS) {
274316
if (auto *RV = RS->getRetValue()) {
275317
RV = RV->IgnoreParenCasts();
276-
if (isa<CXXNullPtrLiteralExpr>(RV))
318+
if (isNullPtr(RV))
277319
return true;
278320
return isConstOwnerPtrMemberExpr(RV);
279321
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ bool tryToFindPtrOrigin(
6666
/// \returns Whether \p E is a safe call arugment.
6767
bool isASafeCallArg(const clang::Expr *E);
6868

69+
/// \returns true if E is nullptr or __null.
70+
bool isNullPtr(const clang::Expr *E);
71+
6972
/// \returns true if E is a MemberExpr accessing a const smart pointer type.
7073
bool isConstOwnerPtrMemberExpr(const clang::Expr *E);
7174

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ class ForwardDeclChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
272272
ArgExpr = ArgExpr->IgnoreParenCasts();
273273
}
274274
}
275-
if (isa<CXXNullPtrLiteralExpr>(ArgExpr) || isa<IntegerLiteral>(ArgExpr) ||
275+
if (isNullPtr(ArgExpr) || isa<IntegerLiteral>(ArgExpr) ||
276276
isa<CXXDefaultArgExpr>(ArgExpr))
277277
return;
278278
if (auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) {

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ bool isTrivialBuiltinFunction(const FunctionDecl *F) {
492492
Name.starts_with("os_log") || Name.starts_with("_os_log");
493493
}
494494

495-
bool isSingleton(const FunctionDecl *F) {
495+
bool isSingleton(const NamedDecl *F) {
496496
assert(F);
497497
// FIXME: check # of params == 1
498498
if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(F)) {
@@ -679,6 +679,10 @@ class TrivialFunctionAnalysisVisitor
679679
return IsFunctionTrivial(Callee);
680680
}
681681

682+
bool VisitGCCAsmStmt(const GCCAsmStmt *AS) {
683+
return AS->getAsmString() == "brk #0xc471";
684+
}
685+
682686
bool
683687
VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
684688
// Non-type template paramter is compile time constant and trivial.

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class CXXMethodDecl;
2121
class CXXRecordDecl;
2222
class Decl;
2323
class FunctionDecl;
24+
class NamedDecl;
2425
class QualType;
2526
class RecordType;
2627
class Stmt;
@@ -156,7 +157,7 @@ bool isPtrConversion(const FunctionDecl *F);
156157
bool isTrivialBuiltinFunction(const FunctionDecl *F);
157158

158159
/// \returns true if \p F is a static singleton function.
159-
bool isSingleton(const FunctionDecl *F);
160+
bool isSingleton(const NamedDecl *F);
160161

161162
/// An inter-procedural analysis facility that detects functions with "trivial"
162163
/// behavior with respect to reference counting, such as simple field getters.

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,11 @@ class RawPtrRefCallArgsChecker
217217
[&](const clang::Expr *ArgOrigin, bool IsSafe) {
218218
if (IsSafe)
219219
return true;
220-
if (isa<CXXNullPtrLiteralExpr>(ArgOrigin)) {
221-
// foo(nullptr)
220+
if (isNullPtr(ArgOrigin))
222221
return true;
223-
}
224222
if (isa<IntegerLiteral>(ArgOrigin)) {
225223
// FIXME: Check the value.
226-
// foo(NULL)
224+
// foo(123)
227225
return true;
228226
}
229227
if (isa<ObjCStringLiteral>(ArgOrigin))

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,11 @@ class RawPtrRefLambdaCapturesChecker
232232
if (!Init)
233233
return nullptr;
234234
if (auto *Lambda = dyn_cast<LambdaExpr>(Init)) {
235+
DeclRefExprsToIgnore.insert(DRE);
235236
updateIgnoreList();
236237
return Lambda;
237238
}
238-
TempExpr = dyn_cast<CXXBindTemporaryExpr>(Init->IgnoreParenCasts());
239-
if (!TempExpr)
240-
return nullptr;
241-
updateIgnoreList();
242-
return dyn_cast_or_null<LambdaExpr>(TempExpr->getSubExpr());
239+
return nullptr;
243240
}
244241

245242
void checkCalleeLambda(CallExpr *CE) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ class RawPtrRefLocalVarsChecker
295295
if (isa<CXXThisExpr>(InitArgOrigin))
296296
return true;
297297

298-
if (isa<CXXNullPtrLiteralExpr>(InitArgOrigin))
298+
if (isNullPtr(InitArgOrigin))
299299
return true;
300300

301301
if (isa<IntegerLiteral>(InitArgOrigin))

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ class RetainPtrCtorAdoptChecker
177177
CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
178178
return;
179179
}
180-
if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip) {
180+
if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip ||
181+
isNullPtr(Arg)) {
181182
CreateOrCopyFnCall.insert(Arg);
182183
return;
183184
}
@@ -486,7 +487,7 @@ class RetainPtrCtorAdoptChecker
486487
continue;
487488
}
488489
}
489-
if (isa<CXXNullPtrLiteralExpr>(E))
490+
if (isNullPtr(E))
490491
return IsOwnedResult::NotOwned;
491492
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
492493
auto QT = DRE->getType();

clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,21 @@ class Foo {
7171
return m_obj5.get();
7272
}
7373

74+
CheckedObj* ensureObj6() {
75+
if (!m_obj6)
76+
const_cast<std::unique_ptr<CheckedObj>&>(m_obj6) = new CheckedObj;
77+
if (m_obj6->next())
78+
return (CheckedObj *)0;
79+
return m_obj6.get();
80+
}
81+
7482
private:
7583
const std::unique_ptr<CheckedObj> m_obj1;
7684
std::unique_ptr<CheckedObj> m_obj2;
7785
const std::unique_ptr<CheckedObj> m_obj3;
7886
const std::unique_ptr<CheckedObj> m_obj4;
7987
const std::unique_ptr<CheckedObj> m_obj5;
88+
const std::unique_ptr<CheckedObj> m_obj6;
8089
};
8190

8291
void Foo::bar() {
@@ -87,6 +96,7 @@ void Foo::bar() {
8796
badEnsureObj4().method();
8897
// expected-warning@-1{{Call argument for 'this' parameter is unchecked and unsafe}}
8998
ensureObj5()->method();
99+
ensureObj6()->method();
90100
}
91101

92102
} // namespace call_args_const_unique_ptr

0 commit comments

Comments
 (0)