[clang] [WebKit checkers] Treat NULL, 0, and nil like nullptr (PR #157700)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 9 09:15:21 PDT 2025
https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/157700
This PR makes WebKit checkers treat NULL, 0, and nil like nullptr in various places.
>From 8c8c20cf6d3ea822d098bfb97b8426cf8d8eef85 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Tue, 9 Sep 2025 09:13:47 -0700
Subject: [PATCH] [WebKit checkers] Treat NULL, 0, and nil like nullptr
This PR makes WebKit checkers treat NULL, 0, and nil like nullptr in various places.
---
.../lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp | 12 +++++++++++-
clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h | 3 +++
.../Checkers/WebKit/ForwardDeclChecker.cpp | 2 +-
.../Checkers/WebKit/RawPtrRefCallArgsChecker.cpp | 6 ++----
.../Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp | 2 +-
.../Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp | 5 +++--
.../WebKit/call-args-checked-const-member.cpp | 10 ++++++++++
.../Checkers/WebKit/retain-ptr-ctor-adopt-use.mm | 6 ++++++
.../Checkers/WebKit/uncounted-local-vars.cpp | 1 +
.../Analysis/Checkers/WebKit/unretained-call-args.mm | 2 ++
10 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 478bd85177143..f62a868ccd2cd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -215,6 +215,16 @@ bool isASafeCallArg(const Expr *E) {
return isa<CXXThisExpr>(E);
}
+bool isNullPtr(const clang::Expr *E) {
+ if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E))
+ return true;
+ if (auto *Int = dyn_cast_or_null<IntegerLiteral>(E)) {
+ if (Int->getValue().isZero())
+ return true;
+ }
+ return false;
+}
+
bool isConstOwnerPtrMemberExpr(const clang::Expr *E) {
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) {
if (auto *Callee = MCE->getDirectCallee()) {
@@ -273,7 +283,7 @@ class EnsureFunctionVisitor
bool VisitReturnStmt(const ReturnStmt *RS) {
if (auto *RV = RS->getRetValue()) {
RV = RV->IgnoreParenCasts();
- if (isa<CXXNullPtrLiteralExpr>(RV))
+ if (isNullPtr(RV))
return true;
return isConstOwnerPtrMemberExpr(RV);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
index 8302bbe3084c2..3a009d65efea6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
@@ -66,6 +66,9 @@ bool tryToFindPtrOrigin(
/// \returns Whether \p E is a safe call arugment.
bool isASafeCallArg(const clang::Expr *E);
+/// \returns true if E is nullptr or __null.
+bool isNullPtr(const clang::Expr *E);
+
/// \returns true if E is a MemberExpr accessing a const smart pointer type.
bool isConstOwnerPtrMemberExpr(const clang::Expr *E);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
index ec0c2c117fb29..9deb1845a2f1a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
@@ -272,7 +272,7 @@ class ForwardDeclChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
ArgExpr = ArgExpr->IgnoreParenCasts();
}
}
- if (isa<CXXNullPtrLiteralExpr>(ArgExpr) || isa<IntegerLiteral>(ArgExpr) ||
+ if (isNullPtr(ArgExpr) || isa<IntegerLiteral>(ArgExpr) ||
isa<CXXDefaultArgExpr>(ArgExpr))
return;
if (auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index 764e2c640feb8..e80f1749d595b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -217,13 +217,11 @@ class RawPtrRefCallArgsChecker
[&](const clang::Expr *ArgOrigin, bool IsSafe) {
if (IsSafe)
return true;
- if (isa<CXXNullPtrLiteralExpr>(ArgOrigin)) {
- // foo(nullptr)
+ if (isNullPtr(ArgOrigin))
return true;
- }
if (isa<IntegerLiteral>(ArgOrigin)) {
// FIXME: Check the value.
- // foo(NULL)
+ // foo(123)
return true;
}
if (isa<ObjCStringLiteral>(ArgOrigin))
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index 7cd86a682c0a9..f4f6e28c97ea1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -295,7 +295,7 @@ class RawPtrRefLocalVarsChecker
if (isa<CXXThisExpr>(InitArgOrigin))
return true;
- if (isa<CXXNullPtrLiteralExpr>(InitArgOrigin))
+ if (isNullPtr(InitArgOrigin))
return true;
if (isa<IntegerLiteral>(InitArgOrigin))
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index d74fec2c551d4..5c1b2d7cce45d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -177,7 +177,8 @@ class RetainPtrCtorAdoptChecker
CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
return;
}
- if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip) {
+ if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip ||
+ isNullPtr(Arg)) {
CreateOrCopyFnCall.insert(Arg);
return;
}
@@ -486,7 +487,7 @@ class RetainPtrCtorAdoptChecker
continue;
}
}
- if (isa<CXXNullPtrLiteralExpr>(E))
+ if (isNullPtr(E))
return IsOwnedResult::NotOwned;
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
auto QT = DRE->getType();
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp
index f7095606c77a4..7959daf0ceaaf 100644
--- a/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked-const-member.cpp
@@ -71,12 +71,21 @@ class Foo {
return m_obj5.get();
}
+ CheckedObj* ensureObj6() {
+ if (!m_obj6)
+ const_cast<std::unique_ptr<CheckedObj>&>(m_obj6) = new CheckedObj;
+ if (m_obj6->next())
+ return (CheckedObj *)0;
+ return m_obj6.get();
+ }
+
private:
const std::unique_ptr<CheckedObj> m_obj1;
std::unique_ptr<CheckedObj> m_obj2;
const std::unique_ptr<CheckedObj> m_obj3;
const std::unique_ptr<CheckedObj> m_obj4;
const std::unique_ptr<CheckedObj> m_obj5;
+ const std::unique_ptr<CheckedObj> m_obj6;
};
void Foo::bar() {
@@ -87,6 +96,7 @@ void Foo::bar() {
badEnsureObj4().method();
// expected-warning at -1{{Call argument for 'this' parameter is unchecked and unsafe}}
ensureObj5()->method();
+ ensureObj6()->method();
}
} // namespace call_args_const_unique_ptr
diff --git a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
index 83c87b14158b9..769901778cdf0 100644
--- a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
+++ b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
@@ -13,6 +13,8 @@ void basic_correct() {
auto ns4 = adoptNS([ns3 mutableCopy]);
auto ns5 = adoptNS([ns3 copyWithValue:3]);
auto ns6 = retainPtr([ns3 next]);
+ auto ns7 = retainPtr((SomeObj *)0);
+ auto ns8 = adoptNS(nil);
CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10));
auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault));
auto cf3 = adoptCF(checked_cf_cast<CFArrayRef>(CFCopyArray(cf1)));
@@ -111,6 +113,10 @@ - (void)setValue:value {
return adoptCF(rawBuffer);
}
+RetainPtr<SomeObj> return_nil() {
+ return nil;
+}
+
RetainPtr<SomeObj> return_nullptr() {
return nullptr;
}
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
index 0540ed93c5707..3364637369799 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
@@ -121,6 +121,7 @@ void foo8(RefCountable* obj) {
RefCountable *bar = foo->trivial() ? foo.get() : nullptr;
// expected-warning at -1{{Local variable 'bar' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}
foo = nullptr;
+ foo = (RefCountable *)0;
bar->method();
}
}
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
index c69113c48806d..3feecd930f109 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
@@ -456,6 +456,8 @@ - (void)doWorkOnSelf {
// expected-warning at -1{{Call argument is unretained and unsafe}}
// expected-warning at -2{{Call argument is unretained and unsafe}}
[self doWork:@"hello", RetainPtr<SomeObj> { provide() }.get(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get()];
+ [self doWork:__null];
+ [self doWork:nil];
}
- (SomeObj *)getSomeObj {
More information about the cfe-commits
mailing list