[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
This commit is contained in:
parent
3abe7aca45
commit
e94192198f
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
67
clang/test/Analysis/objc-indirect-copy-restore.m
Normal file
67
clang/test/Analysis/objc-indirect-copy-restore.m
Normal file
|
@ -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__))
|
||||
|
||||
|
||||
@protocol NSObject
|
||||
+ (nonnull instancetype)alloc;
|
||||
- (nonnull instancetype)init;
|
||||
@end
|
||||
@interface NSObject <NSObject> {}
|
||||
@end
|
||||
|
||||
@interface NSError : NSObject {
|
||||
@public
|
||||
int x;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface SomeClass : NSObject
|
||||
+ (int)doSomethingWithError:(NSError *__autoreleasing *)error;
|
||||
@end
|
||||
|
||||
@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;
|
||||
}
|
||||
@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}}
|
||||
}
|
||||
|
Loading…
Reference in a new issue