[clang] e941921 - [analyzer] Add support for ObjCIndirectCopyRestoreExpr.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 3 09:06:18 PDT 2020


Author: Paul Pelzl
Date: 2020-06-03T19:06:04+03:00
New Revision: e94192198f8a949c7880620b06e9ef85d87ad4b3

URL: https://github.com/llvm/llvm-project/commit/e94192198f8a949c7880620b06e9ef85d87ad4b3
DIFF: https://github.com/llvm/llvm-project/commit/e94192198f8a949c7880620b06e9ef85d87ad4b3.diff

LOG: [analyzer] Add support for ObjCIndirectCopyRestoreExpr.

Idiomatic objc using ARC will generate this expression regularly due to
NSError out-param passing.  Providing an implementation for this
expression allows the analyzer to explore many more codepaths in ARC
projects.

The current implementation is not perfect but the differences are hopefully
subtle enough to not cause much problems.

rdar://63918914

Differential Revision: https://reviews.llvm.org/D81071

Added: 
    clang/test/Analysis/objc-indirect-copy-restore.m

Modified: 
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 81caf0f47553..265dcd134213 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1210,7 +1210,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
 
   switch (S->getStmtClass()) {
     // C++, OpenMP and ARC stuff we don't support yet.
-    case Expr::ObjCIndirectCopyRestoreExprClass:
     case Stmt::CXXDependentScopeMemberExprClass:
     case Stmt::CXXTryStmtClass:
     case Stmt::CXXTypeidExprClass:
@@ -1870,6 +1869,21 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       Bldr.addNodes(Dst);
       break;
     }
+
+    case Expr::ObjCIndirectCopyRestoreExprClass: {
+      // ObjCIndirectCopyRestoreExpr implies passing a temporary for
+      // correctness of lifetime management.  Due to limited analysis
+      // of ARC, this is implemented as direct arg passing.
+      Bldr.takeNodes(Pred);
+      ProgramStateRef state = Pred->getState();
+      const auto *OIE = cast<ObjCIndirectCopyRestoreExpr>(S);
+      const Expr *E = OIE->getSubExpr();
+      SVal V = state->getSVal(E, Pred->getLocationContext());
+      Bldr.generateNode(S, Pred,
+              state->BindExpr(S, Pred->getLocationContext(), V));
+      Bldr.addNodes(Dst);
+      break;
+    }
   }
 }
 

diff  --git a/clang/test/Analysis/objc-indirect-copy-restore.m b/clang/test/Analysis/objc-indirect-copy-restore.m
new file mode 100644
index 000000000000..4881d218f31b
--- /dev/null
+++ b/clang/test/Analysis/objc-indirect-copy-restore.m
@@ -0,0 +1,67 @@
+// RUN: %clang_analyze_cc1 -fobjc-arc -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+    unsigned int __line, __const char *__function)
+     __attribute__ ((__noreturn__));
+
+#define assert(expr) \
+  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
+
+ at protocol NSObject
++ (nonnull instancetype)alloc;
+- (nonnull instancetype)init;
+ at end
+ at interface NSObject <NSObject> {}
+ at end
+
+ at interface NSError : NSObject {
+ at public
+  int x;
+}
+ at end
+
+
+ at interface SomeClass : NSObject
++ (int)doSomethingWithError:(NSError *__autoreleasing *)error;
+ at end
+
+ at implementation SomeClass
++ (int)doSomethingWithError:(NSError *__autoreleasing *)error {
+    if (error) {
+        NSError *e = [[NSError alloc] init];
+        assert(e);
+        e->x = 5;
+        *error = e;
+        clang_analyzer_eval(*error != 0); // expected-warning{{TRUE}}
+    }
+    return 0;
+}
+ at end
+
+void testStrongOutParam(void) {
+  NSError *error;
+  clang_analyzer_eval(error != 0); // expected-warning{{FALSE}}
+  int ok = [SomeClass doSomethingWithError:&error];
+  clang_analyzer_eval(ok);         // expected-warning{{FALSE}}
+  clang_analyzer_eval(error != 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(error->x == 5); // expected-warning{{TRUE}}
+}
+
+void testAutoreleasingOutParam(void) {
+  NSError *__autoreleasing error;
+  clang_analyzer_eval(error != 0); // expected-warning{{FALSE}}
+  int ok = [SomeClass doSomethingWithError:&error];
+  clang_analyzer_eval(ok);         // expected-warning{{FALSE}}
+  clang_analyzer_eval(error != 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(error->x == 5); // expected-warning{{TRUE}}
+}
+
+void testNilOutParam(void) {
+    int ok = [SomeClass doSomethingWithError:(void *)0];
+    clang_analyzer_eval(ok);  // expected-warning{{FALSE}}
+}
+


        


More information about the cfe-commits mailing list