diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRExprEngine.h | 22 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 48 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 32 | ||||
-rw-r--r-- | test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m | 48 |
4 files changed, 136 insertions, 14 deletions
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index f53a9abaad..56e0e1e531 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -113,6 +113,16 @@ public: // (an undefined value). ErrorNodes NilReceiverStructRetImplicit; + /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that + /// resulted from [x ...] with 'x' definitely being nil and the result's size + // was larger than sizeof(void *) (an undefined value). + ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit; + + /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that + /// resulted from [x ...] with 'x' possibly being nil and the result's size + // was larger than sizeof(void *) (an undefined value). + ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; + /// RetsStackAddr - Nodes in the ExplodedGraph that result from returning /// the address of a stack variable. ErrorNodes RetsStackAddr; @@ -329,6 +339,18 @@ public: return NilReceiverStructRetExplicit.end(); } + typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; + + nil_receiver_larger_than_voidptr_ret_iterator + nil_receiver_larger_than_voidptr_ret_begin() { + return NilReceiverLargerThanVoidPtrRetExplicit.begin(); + } + + nil_receiver_larger_than_voidptr_ret_iterator + nil_receiver_larger_than_voidptr_ret_end() { + return NilReceiverLargerThanVoidPtrRetExplicit.end(); + } + typedef ErrorNodes::iterator undef_deref_iterator; undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); } diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 487aac06c5..06d61cc4b0 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -1690,20 +1690,40 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, if (isFeasibleNull) { // Check if the receiver was nil and the return value a struct. - if (ME->getType()->isRecordType() && - BR.getParentMap().isConsumedExpr(ME)) { - // The [0 ...] expressions will return garbage. Flag either an - // explicit or implicit error. Because of the structure of this - // function we currently do not bifurfacte the state graph at - // this point. - // FIXME: We should bifurcate and fill the returned struct with - // garbage. - if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) { - N->markAsSink(); - if (isFeasibleNotNull) - NilReceiverStructRetImplicit.insert(N); - else - NilReceiverStructRetExplicit.insert(N); + if (BR.getParentMap().isConsumedExpr(ME)) { + if(ME->getType()->isRecordType()) { + // The [0 ...] expressions will return garbage. Flag either an + // explicit or implicit error. Because of the structure of this + // function we currently do not bifurfacte the state graph at + // this point. + // FIXME: We should bifurcate and fill the returned struct with + // garbage. + if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) { + N->markAsSink(); + if (isFeasibleNotNull) + NilReceiverStructRetImplicit.insert(N); + else + NilReceiverStructRetExplicit.insert(N); + } + } + else { + ASTContext& Ctx = getContext(); + + // sizeof(void *) + const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); + + // sizeof(return type) + const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType()); + + if(voidPtrSize < returnTypeSize) { + if (NodeTy* N = Builder->generateNode(ME, StNull, Pred)) { + N->markAsSink(); + if(isFeasibleNotNull) + NilReceiverLargerThanVoidPtrRetImplicit.insert(N); + else + NilReceiverLargerThanVoidPtrRetExplicit.insert(N); + } + } } } } diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index 45baebd32b..f4efdb1250 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -98,6 +98,37 @@ public: } } }; + +class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BugType { + GRExprEngine &Eng; +public: + NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) : + BugType("'nil' receiver with return type larger than sizeof(void *)", + "Logic Errors"), + Eng(*eng) {} + + void FlushReports(BugReporter& BR) { + for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator + I=Eng.nil_receiver_larger_than_voidptr_ret_begin(), + E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) { + + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + PostStmt P = cast<PostStmt>((*I)->getLocation()); + ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt()); + os << "The receiver in the message expression is 'nil' and results in the" + " returned value (of type '" + << ME->getType().getAsString() + << "' and of size " + << Eng.getContext().getTypeSize(ME->getType()) / 8 + << " bytes) to be garbage or otherwise undefined."; + + RangedBugReport *R = new RangedBugReport(*this, os.str().c_str(), *I); + R->addRange(ME->getReceiver()->getSourceRange()); + BR.EmitReport(R); + } + } +}; class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug { public: @@ -465,6 +496,7 @@ void GRExprEngine::RegisterInternalChecks() { BR.Register(new OutOfBoundMemoryAccess(this)); BR.Register(new BadSizeVLA(this)); BR.Register(new NilReceiverStructRet(this)); + BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); // The following checks do not need to have their associated BugTypes // explicitly registered with the BugReporter. If they issue any BugReports, diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m new file mode 100644 index 0000000000..a5e9c061bb --- /dev/null +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -0,0 +1,48 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-constraints=basic -analyzer-store=basic %s -verify + +@interface MyClass {} +- (void *)voidPtrM; +- (int)intM; +- (long long)longlongM; +- (double)doubleM; +- (long double)longDoubleM; +@end +@implementation MyClass +- (void *)voidPtrM { return (void *)0; } +- (int)intM { return 0; } +- (long long)longlongM { return 0; } +- (double)doubleM { return 0.0; } +- (long double)longDoubleM { return 0.0; } +@end + +void createFoo() { + MyClass *obj = 0; + + void *v = [obj voidPtrM]; // no-warning + int i = [obj intM]; // no-warning +} + +void createFoo2() { + MyClass *obj = 0; + + long double ld = [obj longDoubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +void createFoo3() { + MyClass *obj = 0; + + long long ll = [obj longlongM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +void createFoo4() { + MyClass *obj = 0; + + double d = [obj doubleM]; // expected-warning{{The receiver in the message expression is 'nil' and results in the returned value}} +} + +void createFoo5() { + MyClass *obj = @""; + + double d = [obj doubleM]; // no-warning +} + |