Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,31 @@ class RawPtrRefMemberChecker
if (shouldSkipDecl(RD))
return;

for (auto *Member : RD->fields()) {
auto QT = Member->getType();
const Type *MemberType = QT.getTypePtrOrNull();
if (!MemberType)
continue;
for (auto *Member : RD->fields())
visitMember(Member, RD);
}

auto IsUnsafePtr = isUnsafePtr(QT);
if (!IsUnsafePtr || !*IsUnsafePtr)
continue;
void visitMember(const FieldDecl *Member, const RecordDecl *RD) const {
auto QT = Member->getType();
const Type *MemberType = QT.getTypePtrOrNull();

if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl())
reportBug(Member, MemberType, MemberCXXRD, RD);
else if (auto *ObjCDecl = getObjCDecl(MemberType))
reportBug(Member, MemberType, ObjCDecl, RD);
while (MemberType) {
auto IsUnsafePtr = isUnsafePtr(QT);
if (IsUnsafePtr && *IsUnsafePtr)
break;
if (!MemberType->isPointerType())
return;
QT = MemberType->getPointeeType();
MemberType = QT.getTypePtrOrNull();
}

if (!MemberType)
return;

if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl())
reportBug(Member, MemberType, MemberCXXRD, RD);
else if (auto *ObjCDecl = getObjCDecl(MemberType))
reportBug(Member, MemberType, ObjCDecl, RD);
}

ObjCInterfaceDecl *getObjCDecl(const Type *TypePtr) const {
Expand Down Expand Up @@ -192,7 +202,8 @@ class RawPtrRefMemberChecker

const auto Kind = RD->getTagKind();
// FIMXE: Should we check union members too?
if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class &&
Kind != TagTypeKind::Union)
return true;

// Ignore CXXRecords that come from system headers.
Expand Down Expand Up @@ -229,7 +240,10 @@ class RawPtrRefMemberChecker
printQuotedName(Os, Member);
Os << " in ";
printQuotedQualifiedName(Os, ClassCXXRD);
Os << " is a ";
if (Member->getType().getTypePtrOrNull() == MemberType)
Os << " is a ";
else
Os << " contains a ";
if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) {
auto Typedef = MemberType->getAs<TypedefType>();
assert(Typedef);
Expand Down
26 changes: 24 additions & 2 deletions clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,24 @@ namespace members {

} // namespace members

namespace ignore_unions {
namespace unions {

union Foo {
CheckedObj* a;
// expected-warning@-1{{Member variable 'a' in 'unions::Foo' is a raw pointer to CheckedPtr capable type 'CheckedObj'}}
CheckedPtr<CheckedObj> c;
CheckedRef<CheckedObj> d;
};

template<class T>
union FooTmpl {
T* a;
// expected-warning@-1{{Member variable 'a' in 'unions::FooTmpl<CheckedObj>' is a raw pointer to CheckedPtr capable type 'CheckedObj'}}
};

void forceTmplToInstantiate(FooTmpl<CheckedObj>) { }

} // namespace ignore_unions
} // namespace unions

namespace checked_ptr_ref_ptr_capable {

Expand All @@ -59,3 +61,23 @@ namespace checked_ptr_ref_ptr_capable {
}

} // checked_ptr_ref_ptr_capable

namespace ptr_to_ptr_to_checked_ptr_capable {

struct List {
CheckedObj** elements;
// expected-warning@-1{{Member variable 'elements' in 'ptr_to_ptr_to_checked_ptr_capable::List' contains a raw pointer to CheckedPtr capable type 'CheckedObj'}}
};

template <typename T>
struct TemplateList {
T** elements;
// expected-warning@-1{{Member variable 'elements' in 'ptr_to_ptr_to_checked_ptr_capable::TemplateList<CheckedObj>' contains a raw pointer to CheckedPtr capable type 'CheckedObj'}}
};
TemplateList<CheckedObj> list;

struct SafeList {
CheckedPtr<CheckedObj>* elements;
};

} // namespace ptr_to_ptr_to_checked_ptr_capable
30 changes: 26 additions & 4 deletions clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,22 @@ namespace members {
};
} // members

namespace ignore_unions {
namespace unions {
union Foo {
RefCountable* a;
// expected-warning@-1{{Member variable 'a' in 'unions::Foo' is a raw pointer to ref-countable type 'RefCountable'}}
RefPtr<RefCountable> b;
Ref<RefCountable> c;
};

template<class T>
union RefPtr {
union FooTmpl {
T* a;
// expected-warning@-1{{Member variable 'a' in 'unions::FooTmpl<RefCountable>' is a raw pointer to ref-countable type 'RefCountable'}}
};

void forceTmplToInstantiate(RefPtr<RefCountable>) {}
} // ignore_unions
void forceTmplToInstantiate(FooTmpl<RefCountable>) {}
} // unions

namespace ignore_system_header {

Expand Down Expand Up @@ -77,3 +79,23 @@ namespace checked_ptr_ref_ptr_capable {
}

} // checked_ptr_ref_ptr_capable

namespace ptr_to_ptr_to_ref_counted {

struct List {
RefCountable** elements;
// expected-warning@-1{{Member variable 'elements' in 'ptr_to_ptr_to_ref_counted::List' contains a raw pointer to ref-countable type 'RefCountable'}}
};

template <typename T>
struct TemplateList {
T** elements;
// expected-warning@-1{{Member variable 'elements' in 'ptr_to_ptr_to_ref_counted::TemplateList<RefCountable>' contains a raw pointer to ref-countable type 'RefCountable'}}
};
TemplateList<RefCountable> list;

struct SafeList {
RefPtr<RefCountable>* elements;
};

} // namespace ptr_to_ptr_to_ref_counted
27 changes: 27 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
CFMutableArrayRef e = nullptr;
// expected-warning@-1{{Member variable 'e' in 'members::Foo' is a retainable type 'CFMutableArrayRef'}}
};

union FooUnion {
SomeObj* a;
CFMutableArrayRef b;
// expected-warning@-1{{Member variable 'b' in 'members::FooUnion' is a retainable type 'CFMutableArrayRef'}}
};

template<class T, class S>
struct FooTmpl {
Expand All @@ -37,3 +43,24 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
};

}

namespace ptr_to_ptr_to_retained {

struct List {
CFMutableArrayRef* elements2;
// expected-warning@-1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::List' contains a retainable type 'CFMutableArrayRef'}}
};

template <typename T, typename S>
struct TemplateList {
S* elements2;
// expected-warning@-1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw pointer to retainable type '__CFArray'}}
};
TemplateList<SomeObj, CFMutableArrayRef> list;

struct SafeList {
RetainPtr<SomeObj>* elements1;
RetainPtr<CFMutableArrayRef>* elements2;
};

} // namespace ptr_to_ptr_to_retained
34 changes: 31 additions & 3 deletions clang/test/Analysis/Checkers/WebKit/unretained-members.mm
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,49 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}

}

namespace ignore_unions {
namespace unions {
union Foo {
SomeObj* a;
// expected-warning@-1{{Member variable 'a' in 'unions::Foo' is a raw pointer to retainable type 'SomeObj'}}
RetainPtr<SomeObj> b;
CFMutableArrayRef c;
// expected-warning@-1{{Member variable 'c' in 'unions::Foo' is a retainable type 'CFMutableArrayRef'}}
};

template<class T>
union RefPtr {
union FooTempl {
T* a;
// expected-warning@-1{{Member variable 'a' in 'unions::FooTempl<SomeObj>' is a raw pointer to retainable type 'SomeObj'}}
};

void forceTmplToInstantiate(RefPtr<SomeObj>) {}
void forceTmplToInstantiate(FooTempl<SomeObj>) {}
}

namespace ptr_to_ptr_to_retained {

struct List {
SomeObj** elements1;
// expected-warning@-1{{Member variable 'elements1' in 'ptr_to_ptr_to_retained::List' contains a raw pointer to retainable type 'SomeObj'}}
CFMutableArrayRef* elements2;
// expected-warning@-1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::List' contains a retainable type 'CFMutableArrayRef'}}
};

template <typename T, typename S>
struct TemplateList {
T** elements1;
// expected-warning@-1{{Member variable 'elements1' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw pointer to retainable type 'SomeObj'}}
S* elements2;
// expected-warning@-1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw pointer to retainable type '__CFArray'}}
};
TemplateList<SomeObj, CFMutableArrayRef> list;

struct SafeList {
RetainPtr<SomeObj>* elements1;
RetainPtr<CFMutableArrayRef>* elements2;
};

} // namespace ptr_to_ptr_to_retained

@interface AnotherObject : NSObject {
NSString *ns_string;
// expected-warning@-1{{Instance variable 'ns_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
Expand Down