23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/StringExtras.h" 25 #include "llvm/Support/raw_ostream.h" 27 using namespace clang;
33 DefaultBool Check_CallAndMessageUnInitRefArg;
34 DefaultBool Check_CallAndMessageChecker;
36 CheckName CheckName_CallAndMessageUnInitRefArg;
37 CheckName CheckName_CallAndMessageChecker;
40 class CallAndMessageChecker
41 :
public Checker< check::PreStmt<CallExpr>,
42 check::PreStmt<CXXDeleteExpr>,
43 check::PreObjCMessage,
44 check::ObjCMessageNil,
46 mutable std::unique_ptr<BugType> BT_call_null;
47 mutable std::unique_ptr<BugType> BT_call_undef;
48 mutable std::unique_ptr<BugType> BT_cxx_call_null;
49 mutable std::unique_ptr<BugType> BT_cxx_call_undef;
50 mutable std::unique_ptr<BugType> BT_call_arg;
51 mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
52 mutable std::unique_ptr<BugType> BT_msg_undef;
53 mutable std::unique_ptr<BugType> BT_objc_prop_undef;
54 mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
55 mutable std::unique_ptr<BugType> BT_msg_arg;
56 mutable std::unique_ptr<BugType> BT_msg_ret;
57 mutable std::unique_ptr<BugType> BT_call_few_args;
62 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
63 void checkPreStmt(
const CXXDeleteExpr *DE, CheckerContext &C)
const;
64 void checkPreObjCMessage(
const ObjCMethodCall &msg, CheckerContext &C)
const;
69 void checkObjCMessageNil(
const ObjCMethodCall &msg, CheckerContext &C)
const;
71 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
74 bool PreVisitProcessArg(CheckerContext &C, SVal V,
SourceRange ArgRange,
75 const Expr *ArgEx,
int ArgumentNumber,
76 bool CheckUninitFields,
const CallEvent &Call,
77 std::unique_ptr<BugType> &BT,
80 static void emitBadCall(BugType *BT, CheckerContext &C,
const Expr *BadE);
81 void emitNilReceiverBug(CheckerContext &C,
const ObjCMethodCall &msg,
82 ExplodedNode *N)
const;
84 void HandleNilReceiver(CheckerContext &C,
88 void LazyInit_BT(
const char *desc, std::unique_ptr<BugType> &BT)
const {
90 BT.reset(
new BuiltinBug(
this, desc));
92 bool uninitRefOrPointer(CheckerContext &C,
const SVal &V,
94 std::unique_ptr<BugType> &BT,
96 int ArgumentNumber)
const;
100 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
102 ExplodedNode *N = C.generateErrorNode();
106 auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
110 BadE = bugreporter::getDerefExpr(BadE);
111 bugreporter::trackExpressionValue(N, BadE, *R);
113 C.emitReport(std::move(R));
118 llvm::raw_svector_ostream &Os) {
119 switch (Call.getKind()) {
124 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
125 <<
" argument in message expression is an uninitialized value";
128 assert(Msg.
isSetter() &&
"Getters have no args");
129 Os <<
"Argument for property setter is an uninitialized value";
132 if (Msg.
isSetter() && (ArgumentNumber == 0))
133 Os <<
"Argument for subscript setter is an uninitialized value";
135 Os <<
"Subscript index is an uninitialized value";
138 llvm_unreachable(
"Unknown message kind.");
141 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
142 <<
" block call argument is an uninitialized value";
145 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
146 <<
" function call argument is an uninitialized value";
151 bool CallAndMessageChecker::uninitRefOrPointer(
152 CheckerContext &C,
const SVal &V,
SourceRange ArgRange,
const Expr *ArgEx,
153 std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl,
const char *BD,
154 int ArgumentNumber)
const {
155 if (!Filter.Check_CallAndMessageUnInitRefArg)
166 llvm::raw_svector_ostream Os(Buf);
169 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
170 <<
" function call argument is a pointer to uninitialized value";
172 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
173 <<
" function call argument is an uninitialized value";
180 if (
const MemRegion *SValMemRegion = V.getAsRegion()) {
182 const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
184 if (ExplodedNode *N = C.generateErrorNode()) {
186 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
187 R->addRange(ArgRange);
189 bugreporter::trackExpressionValue(N, ArgEx, *R);
191 C.emitReport(std::move(R));
200 class FindUninitializedField {
205 StoreManager &StoreMgr;
206 MemRegionManager &MrMgr;
210 FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
212 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
214 bool Find(
const TypedValueRegion *R) {
218 assert(RD &&
"Referred record has no definition");
219 for (
const auto *I : RD->
fields()) {
220 const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
221 FieldChain.push_back(I);
227 const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
231 FieldChain.pop_back();
240 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
245 bool CheckUninitFields,
247 std::unique_ptr<BugType> &BT,
250 const char *BD =
"Uninitialized argument value";
252 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
257 if (ExplodedNode *N = C.generateErrorNode()) {
261 llvm::raw_svector_ostream Os(Buf);
263 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
265 R->addRange(ArgRange);
267 bugreporter::trackExpressionValue(N, ArgEx, *R);
268 C.emitReport(std::move(R));
273 if (!CheckUninitFields)
276 if (
auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
277 const LazyCompoundValData *D = LV->getCVData();
278 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
279 C.getSValBuilder().getRegionManager(),
282 if (F.Find(D->getRegion())) {
283 if (ExplodedNode *N = C.generateErrorNode()) {
286 llvm::raw_svector_ostream os(Str);
287 os <<
"Passed-by-value struct argument contains uninitialized data";
289 if (F.FieldChain.size() == 1)
290 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
292 os <<
" (e.g., via the field chain: '";
295 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
306 auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
307 R->addRange(ArgRange);
310 bugreporter::trackExpressionValue(N, ArgEx, *R);
313 C.emitReport(std::move(R));
322 void CallAndMessageChecker::checkPreStmt(
const CallExpr *CE,
323 CheckerContext &C)
const{
328 SVal L = State->getSVal(Callee, LCtx);
332 BT_call_undef.reset(
new BuiltinBug(
333 this,
"Called function pointer is an uninitialized pointer value"));
334 emitBadCall(BT_call_undef.get(), C, Callee);
339 std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
341 if (StNull && !StNonNull) {
343 BT_call_null.reset(
new BuiltinBug(
344 this,
"Called function pointer is null (null dereference)"));
345 emitBadCall(BT_call_null.get(), C, Callee);
349 C.addTransition(StNonNull);
352 void CallAndMessageChecker::checkPreStmt(
const CXXDeleteExpr *DE,
353 CheckerContext &C)
const {
358 ExplodedNode *N = C.generateErrorNode();
361 if (!BT_cxx_delete_undef)
362 BT_cxx_delete_undef.reset(
363 new BuiltinBug(
this,
"Uninitialized argument value"));
365 Desc =
"Argument to 'delete[]' is uninitialized";
367 Desc =
"Argument to 'delete' is uninitialized";
368 BugType *BT = BT_cxx_delete_undef.get();
369 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
370 bugreporter::trackExpressionValue(N, DE, *R);
371 C.emitReport(std::move(R));
376 void CallAndMessageChecker::checkPreCall(
const CallEvent &Call,
377 CheckerContext &C)
const {
383 SVal V = CC->getCXXThisVal();
385 if (!BT_cxx_call_undef)
386 BT_cxx_call_undef.reset(
387 new BuiltinBug(
this,
"Called C++ object pointer is uninitialized"));
388 emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
393 std::tie(StNonNull, StNull) =
394 State->assume(V.castAs<DefinedOrUnknownSVal>());
396 if (StNull && !StNonNull) {
397 if (!BT_cxx_call_null)
398 BT_cxx_call_null.reset(
399 new BuiltinBug(
this,
"Called C++ object pointer is null"));
400 emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
407 const Decl *D = Call.getDecl();
408 if (D && (isa<FunctionDecl>(D) || isa<BlockDecl>(D))) {
411 unsigned Params = Call.parameters().size();
412 if (Call.getNumArgs() < Params) {
413 ExplodedNode *N = C.generateErrorNode();
417 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
420 llvm::raw_svector_ostream os(Str);
421 if (isa<FunctionDecl>(D)) {
424 assert(isa<BlockDecl>(D));
427 os <<
"taking " << Params <<
" argument" 428 << (Params == 1 ?
"" :
"s") <<
" is called with fewer (" 429 << Call.getNumArgs() <<
")";
432 llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
440 const bool checkUninitFields =
441 !(C.getAnalysisManager().shouldInlineCall() && (D && D->
getBody()));
443 std::unique_ptr<BugType> *BT;
444 if (isa<ObjCMethodCall>(Call))
449 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
450 for (
unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
452 if(FD && i < FD->getNumParams())
454 if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
455 Call.getArgExpr(i), i,
456 checkUninitFields, Call, *BT, ParamDecl))
461 C.addTransition(State);
464 void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
465 CheckerContext &C)
const {
467 if (recVal.isUndef()) {
468 if (ExplodedNode *N = C.generateErrorNode()) {
469 BugType *BT =
nullptr;
473 BT_msg_undef.reset(
new BuiltinBug(
this,
474 "Receiver in message expression " 475 "is an uninitialized value"));
476 BT = BT_msg_undef.get();
479 if (!BT_objc_prop_undef)
480 BT_objc_prop_undef.reset(
new BuiltinBug(
481 this,
"Property access on an uninitialized object pointer"));
482 BT = BT_objc_prop_undef.get();
485 if (!BT_objc_subscript_undef)
486 BT_objc_subscript_undef.reset(
new BuiltinBug(
487 this,
"Subscript access on an uninitialized object pointer"));
488 BT = BT_objc_subscript_undef.get();
491 assert(BT &&
"Unknown message kind.");
493 auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
495 R->addRange(ME->getReceiverRange());
498 if (
const Expr *ReceiverE = ME->getInstanceReceiver())
499 bugreporter::trackExpressionValue(N, ReceiverE, *R);
500 C.emitReport(std::move(R));
506 void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
507 CheckerContext &C)
const {
508 HandleNilReceiver(C, C.getState(), msg);
511 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
513 ExplodedNode *N)
const {
517 new BuiltinBug(
this,
"Receiver in message expression is 'nil'"));
521 QualType ResTy = msg.getResultType();
524 llvm::raw_svector_ostream os(buf);
525 os <<
"The receiver of message '";
529 os <<
", which results in forming a null reference";
531 os <<
" and returns a value of type '";
532 msg.getResultType().print(os, C.getLangOpts());
533 os <<
"' that will be garbage";
536 auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
540 bugreporter::trackExpressionValue(N, receiver, *report);
542 C.emitReport(std::move(report));
546 return (triple.getVendor() == llvm::Triple::Apple &&
547 (triple.isiOS() || triple.isWatchOS() ||
548 !triple.isMacOSXVersionLT(10,5)));
551 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
555 static CheckerProgramPointTag Tag(
this,
"NilReceiver");
559 QualType RetTy = Msg.getResultType();
563 if (CanRetTy->isStructureOrClassType()) {
565 SVal V = C.getSValBuilder().makeZeroVal(RetTy);
566 C.addTransition(state->BindExpr(Msg.
getOriginExpr(), LCtx, V), &Tag);
571 if (CanRetTy != Ctx.
VoidTy && C.getLocationContext()->getParentMap()
575 const uint64_t returnTypeSize = Ctx.
getTypeSize(CanRetTy);
578 (voidPtrSize < returnTypeSize &&
585 if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
586 emitNilReceiverBug(C, Msg, N);
603 SVal V = C.getSValBuilder().makeZeroVal(RetTy);
604 C.addTransition(state->BindExpr(Msg.
getOriginExpr(), LCtx, V), &Tag);
608 C.addTransition(state);
611 #define REGISTER_CHECKER(name) \ 612 void ento::register##name(CheckerManager &mgr) { \ 613 CallAndMessageChecker *Checker = \ 614 mgr.registerChecker<CallAndMessageChecker>(); \ 615 Checker->Filter.Check_##name = true; \ 616 Checker->Filter.CheckName_##name = mgr.getCurrentCheckName(); \
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
Represents a function declaration or definition.
A (possibly-)qualified type.
Selector getSelector() const
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
bool isArrayFormAsWritten() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Decl - This represents one declaration (or definition), e.g.
const RecordType * getAsStructureType() const
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const TargetInfo & getTargetInfo() const
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
Represents a parameter to a function.
Represents a struct/union/class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
field_range fields() const
bool isReferenceType() const
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
Represents any expression that calls an Objective-C method.
bool isSetter() const
Returns true if this property access or subscript is a setter (has the form of an assignment)...
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
#define REGISTER_CHECKER(name)
Represents a non-static C++ member function call, no matter how it is written.
for(unsigned I=0, E=TL.getNumArgs();I !=E;++I)
This represents one expression.
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
An expression that sends a message to the given Objective-C object or class.
bool isConstQualified() const
Determine whether this type is const-qualified.
const ParmVarDecl * getParamDecl(unsigned i) const
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
virtual const ObjCMessageExpr * getOriginExpr() const
Dataflow Directional Tag Classes.
Represents a delete expression for memory deallocation and destructor calls, e.g. ...
CanQualType UnsignedLongLongTy
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
SourceRange getReceiverRange() const
Source range of the receiver.
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
static void describeUninitializedArgumentInCall(const CallEvent &Call, int ArgumentNumber, llvm::raw_svector_ostream &Os)
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
bool isPointerType() const
A trivial tuple used to represent a source range.
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.