-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[RawPtrRefMemberChecker] Add the support for union and pointers to unsafe pointers. #138042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rniwa
wants to merge
1
commit into
llvm:main
Choose a base branch
from
rniwa:ptr-to-ptr-and-union-in-webkit-member-checker
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[RawPtrRefMemberChecker] Add the support for union and pointers to unsafe pointers. #138042
rniwa
wants to merge
1
commit into
llvm:main
from
rniwa:ptr-to-ptr-and-union-in-webkit-member-checker
+136
−23
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…safe pointers. This PR adds support for detecting unsafe union members and pointers to unsafe pointers (e.g. T** where T* is an unsafe pointer type).
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Ryosuke Niwa (rniwa) ChangesThis PR adds support for detecting unsafe union members and pointers to unsafe pointers (e.g. T** where T* is an unsafe pointer type). Full diff: https://github.com/llvm/llvm-project/pull/138042.diff 5 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index e8992f58273bb..d1a4f203d7a49 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -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 {
@@ -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.
@@ -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);
diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp b/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
index 048ffbffcdefb..3fe15d88ff312 100644
--- a/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
@@ -34,10 +34,11 @@ 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;
};
@@ -45,11 +46,12 @@ namespace ignore_unions {
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 {
@@ -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
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
index 130777a9a5fee..b8c443cda4f8e 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
@@ -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 {
@@ -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
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
index 9820c875b87c0..3491bc93ed98a 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
@@ -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 {
@@ -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
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index fff1f8ede091b..0cb4c4ac0f6a0 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -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}}
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds support for detecting unsafe union members and pointers to unsafe pointers (e.g. T** where T* is an unsafe pointer type).