[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