Skip to content

Commit f811649

Browse files
committed
Check the type of Objective-C++ instance variables in WebKit member variable checkers. (llvm#127570)
Like a C++ member variable, every Objective-C++ instance variable must be a RefPtr, Ref CheckedPtr, or CheckedRef to an object, not a raw pointer or reference.
1 parent 6adc720 commit f811649

File tree

3 files changed

+107
-3
lines changed

3 files changed

+107
-3
lines changed

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

+37-3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ class RawPtrRefMemberChecker
6262
Checker->visitRecordDecl(RD);
6363
return true;
6464
}
65+
66+
bool VisitObjCContainerDecl(const ObjCContainerDecl *CD) {
67+
Checker->visitObjCDecl(CD);
68+
return true;
69+
}
6570
};
6671

6772
LocalVisitor visitor(this);
@@ -88,6 +93,31 @@ class RawPtrRefMemberChecker
8893
}
8994
}
9095

96+
void visitObjCDecl(const ObjCContainerDecl *CD) const {
97+
if (auto *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
98+
for (auto *Ivar : ID->ivars())
99+
visitIvarDecl(CD, Ivar);
100+
return;
101+
}
102+
if (auto *ID = dyn_cast<ObjCImplementationDecl>(CD)) {
103+
for (auto *Ivar : ID->ivars())
104+
visitIvarDecl(CD, Ivar);
105+
return;
106+
}
107+
}
108+
109+
void visitIvarDecl(const ObjCContainerDecl *CD,
110+
const ObjCIvarDecl *Ivar) const {
111+
const Type *IvarType = Ivar->getType().getTypePtrOrNull();
112+
if (!IvarType)
113+
return;
114+
if (auto *IvarCXXRD = IvarType->getPointeeCXXRecordDecl()) {
115+
std::optional<bool> IsCompatible = isPtrCompatible(IvarCXXRD);
116+
if (IsCompatible && *IsCompatible)
117+
reportBug(Ivar, IvarType, IvarCXXRD, CD);
118+
}
119+
}
120+
91121
bool shouldSkipDecl(const RecordDecl *RD) const {
92122
if (!RD->isThisDeclarationADefinition())
93123
return true;
@@ -122,17 +152,21 @@ class RawPtrRefMemberChecker
122152
return false;
123153
}
124154

125-
void reportBug(const FieldDecl *Member, const Type *MemberType,
155+
template <typename DeclType, typename ParentDeclType>
156+
void reportBug(const DeclType *Member, const Type *MemberType,
126157
const CXXRecordDecl *MemberCXXRD,
127-
const RecordDecl *ClassCXXRD) const {
158+
const ParentDeclType *ClassCXXRD) const {
128159
assert(Member);
129160
assert(MemberType);
130161
assert(MemberCXXRD);
131162

132163
SmallString<100> Buf;
133164
llvm::raw_svector_ostream Os(Buf);
134165

135-
Os << "Member variable ";
166+
if (isa<ObjCContainerDecl>(ClassCXXRD))
167+
Os << "Instance variable ";
168+
else
169+
Os << "Member variable ";
136170
printQuotedName(Os, Member);
137171
Os << " in ";
138172
printQuotedQualifiedName(Os, ClassCXXRD);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.NoUncheckedPtrMemberChecker -verify %s
2+
3+
#include "mock-types.h"
4+
5+
__attribute__((objc_root_class))
6+
@interface NSObject
7+
+ (instancetype) alloc;
8+
- (instancetype) init;
9+
- (instancetype)retain;
10+
- (void)release;
11+
@end
12+
13+
void doSomeWork();
14+
15+
@interface SomeObjC : NSObject {
16+
CheckedObj* _unchecked1;
17+
// expected-warning@-1{{Instance variable '_unchecked1' in 'SomeObjC' is a raw pointer to CheckedPtr capable type 'CheckedObj'}}
18+
CheckedPtr<CheckedObj> _counted1;
19+
[[clang::suppress]] CheckedObj* _unchecked2;
20+
}
21+
- (void)doWork;
22+
@end
23+
24+
@implementation SomeObjC {
25+
CheckedObj* _unchecked3;
26+
// expected-warning@-1{{Instance variable '_unchecked3' in 'SomeObjC' is a raw pointer to CheckedPtr capable type 'CheckedObj'}}
27+
CheckedPtr<CheckedObj> _counted2;
28+
[[clang::suppress]] CheckedObj* _unchecked4;
29+
}
30+
31+
- (void)doWork {
32+
doSomeWork();
33+
}
34+
35+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.NoUncountedMemberChecker -verify %s
2+
3+
#include "mock-types.h"
4+
5+
__attribute__((objc_root_class))
6+
@interface NSObject
7+
+ (instancetype) alloc;
8+
- (instancetype) init;
9+
- (instancetype)retain;
10+
- (void)release;
11+
@end
12+
13+
void doSomeWork();
14+
15+
@interface SomeObjC : NSObject {
16+
RefCountable* _uncounted1;
17+
// expected-warning@-1{{Instance variable '_uncounted1' in 'SomeObjC' is a raw pointer to ref-countable type 'RefCountable'}}
18+
RefPtr<RefCountable> _counted1;
19+
[[clang::suppress]] RefCountable* _uncounted2;
20+
}
21+
- (void)doWork;
22+
@end
23+
24+
@implementation SomeObjC {
25+
RefCountable* _uncounted3;
26+
// expected-warning@-1{{Instance variable '_uncounted3' in 'SomeObjC' is a raw pointer to ref-countable type 'RefCountable'}}
27+
RefPtr<RefCountable> _counted2;
28+
[[clang::suppress]] RefCountable* _uncounted4;
29+
}
30+
31+
- (void)doWork {
32+
doSomeWork();
33+
}
34+
35+
@end

0 commit comments

Comments
 (0)