Skip to content
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

[alpha.webkit.UncountedCallArgsChecker] Add support for Objective-C++ property access #108669

Merged
merged 2 commits into from
Sep 18, 2024

Conversation

rniwa
Copy link
Contributor

@rniwa rniwa commented Sep 14, 2024

Treat a function call or property access via a Objective-C++ selector which returns a Ref/RefPtr as safe.

… property access

Treat a function call or property access via a Objective-C++ selector which returns a Ref/RefPtr as safe.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Sep 14, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 14, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Ryosuke Niwa (rniwa)

Changes

Treat a function call or property access via a Objective-C++ selector which returns a Ref/RefPtr as safe.


Full diff: https://github.com/llvm/llvm-project/pull/108669.diff

4 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp (+14-1)
  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+2-3)
  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+2-2)
  • (modified) clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.mm (+22)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index be07cf51eefb3d..394cb26f03cf99 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
 #include <optional>
 
 namespace clang {
@@ -35,6 +36,12 @@ bool tryToFindPtrOrigin(
         break;
       }
     }
+    if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {
+      if (auto *RF = POE->getResultExpr()) {
+        E = RF;
+        continue;
+      }
+    }
     if (auto *tempExpr = dyn_cast<ParenExpr>(E)) {
       E = tempExpr->getSubExpr();
       continue;
@@ -88,7 +95,7 @@ bool tryToFindPtrOrigin(
           continue;
         }
 
-        if (isReturnValueRefCounted(callee))
+        if (isRefType(callee->getReturnType()))
           return callback(E, true);
 
         if (isSingleton(callee))
@@ -100,6 +107,12 @@ bool tryToFindPtrOrigin(
         }
       }
     }
+    if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
+      if (auto *Method = ObjCMsgExpr->getMethodDecl()) {
+        if (isRefType(Method->getReturnType()))
+          return callback(E, true);
+      }
+    }
     if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) {
       // FIXME: Currently accepts ANY unary operator. Is it OK?
       E = unaryOp->getSubExpr();
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index f48b2fd9dca71b..9da3e54e454317 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -123,9 +123,8 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
          || FunctionName == "Identifier";
 }
 
-bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
-  assert(F);
-  QualType type = F->getReturnType();
+bool isRefType(const clang::QualType T) {
+  QualType type = T;
   while (!type.isNull()) {
     if (auto *elaboratedT = type->getAs<ElaboratedType>()) {
       type = elaboratedT->desugar();
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 2932e62ad06e4b..e2d0342bebd52c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -62,8 +62,8 @@ bool isRefType(const std::string &Name);
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
-/// \returns true if \p F returns a ref-counted object, false if not.
-bool isReturnValueRefCounted(const clang::FunctionDecl *F);
+/// \returns true if \p T is RefPtr, Ref, or its variant, false if not.
+bool isRefType(const clang::QualType T);
 
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional<bool> isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.mm b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.mm
index db0c5b19eec5bb..1d81a8851ece0c 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.mm
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.mm
@@ -11,6 +11,7 @@ @interface Foo : NSObject
 
 - (void)execute;
 - (RefPtr<RefCountable>)_protectedRefCountable;
+- (Ref<RefCountable>)_protectedRefCountable2;
 @end
 
 @implementation Foo
@@ -23,4 +24,25 @@ - (void)execute {
   return _countable;
 }
 
+- (Ref<RefCountable>)_protectedRefCountable2 {
+  return *_countable;
+}
+
 @end
+
+class RefCountedObject {
+public:
+  void ref() const;
+  void deref() const;
+  Ref<RefCountedObject> copy() const;
+};
+
+@interface WrapperObj : NSObject
+
+- (Ref<RefCountedObject>)_protectedWebExtensionControllerConfiguration;
+
+@end
+
+static void foo(WrapperObj *configuration) {
+  configuration._protectedWebExtensionControllerConfiguration->copy();
+}

@rniwa rniwa requested a review from haoNoQ September 14, 2024 02:05
Copy link
Collaborator

@haoNoQ haoNoQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sounds about right!

The property syntax is confusing, I don't have enough expertise to confirm that getResultExpr() is the right solution so I think we should keep trying and incrementally figuring out what's going on.

Setters probably look very different but also you probably don't need to support them anyway.

@haoNoQ
Copy link
Collaborator

haoNoQ commented Sep 17, 2024

I'm also somewhat terrified of returning C++ objects from ObjC methods by value, ever since I learned that when you call an ObjC method on a nil it returns a zero-initialized object without calling a constructor on it.

@rniwa rniwa merged commit 33533ba into llvm:main Sep 18, 2024
6 of 8 checks passed
@rniwa rniwa deleted the fix-objc-property-access branch September 18, 2024 01:39
@rniwa
Copy link
Contributor Author

rniwa commented Sep 18, 2024

I'm also somewhat terrified of returning C++ objects from ObjC methods by value, ever since I learned that when you call an ObjC method on a nil it returns a zero-initialized object without calling a constructor on it.

Yikes. I didn't know that!

tmsri pushed a commit to tmsri/llvm-project that referenced this pull request Sep 19, 2024
… property access (llvm#108669)

Treat a function call or property access via a Objective-C++ selector
which returns a Ref/RefPtr as safe.
rniwa added a commit to rniwa/llvm-project that referenced this pull request Feb 3, 2025
… property access (llvm#108669)

Treat a function call or property access via a Objective-C++ selector
which returns a Ref/RefPtr as safe.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:static analyzer clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants