22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/StringExtras.h" 24 #include "llvm/Support/raw_ostream.h" 26 using namespace clang;
31 class CallAndMessageChecker
32 :
public Checker< check::PreStmt<CallExpr>,
33 check::PreStmt<CXXDeleteExpr>,
34 check::PreObjCMessage,
35 check::ObjCMessageNil,
37 mutable std::unique_ptr<BugType> BT_call_null;
38 mutable std::unique_ptr<BugType> BT_call_undef;
39 mutable std::unique_ptr<BugType> BT_cxx_call_null;
40 mutable std::unique_ptr<BugType> BT_cxx_call_undef;
41 mutable std::unique_ptr<BugType> BT_call_arg;
42 mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
43 mutable std::unique_ptr<BugType> BT_msg_undef;
44 mutable std::unique_ptr<BugType> BT_objc_prop_undef;
45 mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
46 mutable std::unique_ptr<BugType> BT_msg_arg;
47 mutable std::unique_ptr<BugType> BT_msg_ret;
48 mutable std::unique_ptr<BugType> BT_call_few_args;
51 DefaultBool Check_CallAndMessageUnInitRefArg;
52 CheckName CheckName_CallAndMessageUnInitRefArg;
54 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
55 void checkPreStmt(
const CXXDeleteExpr *DE, CheckerContext &C)
const;
56 void checkPreObjCMessage(
const ObjCMethodCall &msg, CheckerContext &C)
const;
61 void checkObjCMessageNil(
const ObjCMethodCall &msg, CheckerContext &C)
const;
63 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
66 bool PreVisitProcessArg(CheckerContext &C, SVal
V,
SourceRange ArgRange,
67 const Expr *ArgEx,
int ArgumentNumber,
68 bool CheckUninitFields,
const CallEvent &Call,
69 std::unique_ptr<BugType> &BT,
72 static void emitBadCall(BugType *BT, CheckerContext &C,
const Expr *BadE);
73 void emitNilReceiverBug(CheckerContext &C,
const ObjCMethodCall &msg,
74 ExplodedNode *N)
const;
76 void HandleNilReceiver(CheckerContext &C,
80 void LazyInit_BT(
const char *desc, std::unique_ptr<BugType> &BT)
const {
82 BT.reset(
new BuiltinBug(
this, desc));
84 bool uninitRefOrPointer(CheckerContext &C,
const SVal &
V,
86 std::unique_ptr<BugType> &BT,
88 int ArgumentNumber)
const;
92 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
94 ExplodedNode *N = C.generateErrorNode();
98 auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
102 BadE = bugreporter::getDerefExpr(BadE);
103 bugreporter::trackExpressionValue(N, BadE, *R);
105 C.emitReport(std::move(R));
110 llvm::raw_svector_ostream &Os) {
111 switch (Call.getKind()) {
116 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
117 <<
" argument in message expression is an uninitialized value";
120 assert(Msg.
isSetter() &&
"Getters have no args");
121 Os <<
"Argument for property setter is an uninitialized value";
124 if (Msg.
isSetter() && (ArgumentNumber == 0))
125 Os <<
"Argument for subscript setter is an uninitialized value";
127 Os <<
"Subscript index is an uninitialized value";
130 llvm_unreachable(
"Unknown message kind.");
133 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
134 <<
" block call argument is an uninitialized value";
137 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
138 <<
" function call argument is an uninitialized value";
143 bool CallAndMessageChecker::uninitRefOrPointer(
145 std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl,
const char *BD,
146 int ArgumentNumber)
const {
147 if (!Check_CallAndMessageUnInitRefArg)
158 llvm::raw_svector_ostream Os(Buf);
161 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
162 <<
" function call argument is a pointer to uninitialized value";
164 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
165 <<
" function call argument is an uninitialized value";
172 if (
const MemRegion *SValMemRegion = V.getAsRegion()) {
174 const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
176 if (ExplodedNode *N = C.generateErrorNode()) {
178 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
179 R->addRange(ArgRange);
181 bugreporter::trackExpressionValue(N, ArgEx, *R);
183 C.emitReport(std::move(R));
192 class FindUninitializedField {
197 StoreManager &StoreMgr;
198 MemRegionManager &MrMgr;
202 FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
204 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
206 bool Find(
const TypedValueRegion *R) {
210 assert(RD &&
"Referred record has no definition");
211 for (
const auto *I : RD->
fields()) {
212 const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
213 FieldChain.push_back(I);
219 const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
223 FieldChain.pop_back();
232 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
237 bool CheckUninitFields,
239 std::unique_ptr<BugType> &BT,
242 const char *BD =
"Uninitialized argument value";
244 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
249 if (ExplodedNode *N = C.generateErrorNode()) {
253 llvm::raw_svector_ostream Os(Buf);
255 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
257 R->addRange(ArgRange);
259 bugreporter::trackExpressionValue(N, ArgEx, *R);
260 C.emitReport(std::move(R));
265 if (!CheckUninitFields)
268 if (
auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
269 const LazyCompoundValData *D = LV->getCVData();
270 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
271 C.getSValBuilder().getRegionManager(),
274 if (F.Find(D->getRegion())) {
275 if (ExplodedNode *N = C.generateErrorNode()) {
278 llvm::raw_svector_ostream os(Str);
279 os <<
"Passed-by-value struct argument contains uninitialized data";
281 if (F.FieldChain.size() == 1)
282 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
284 os <<
" (e.g., via the field chain: '";
287 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
298 auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
299 R->addRange(ArgRange);
302 bugreporter::trackExpressionValue(N, ArgEx, *R);
305 C.emitReport(std::move(R));
314 void CallAndMessageChecker::checkPreStmt(
const CallExpr *CE,
315 CheckerContext &C)
const{
320 SVal L = State->getSVal(Callee, LCtx);
324 BT_call_undef.reset(
new BuiltinBug(
325 this,
"Called function pointer is an uninitialized pointer value"));
326 emitBadCall(BT_call_undef.get(), C, Callee);
331 std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
333 if (StNull && !StNonNull) {
335 BT_call_null.reset(
new BuiltinBug(
336 this,
"Called function pointer is null (null dereference)"));
337 emitBadCall(BT_call_null.get(), C, Callee);
341 C.addTransition(StNonNull);
344 void CallAndMessageChecker::checkPreStmt(
const CXXDeleteExpr *DE,
345 CheckerContext &C)
const {
350 ExplodedNode *N = C.generateErrorNode();
353 if (!BT_cxx_delete_undef)
354 BT_cxx_delete_undef.reset(
355 new BuiltinBug(
this,
"Uninitialized argument value"));
357 Desc =
"Argument to 'delete[]' is uninitialized";
359 Desc =
"Argument to 'delete' is uninitialized";
360 BugType *BT = BT_cxx_delete_undef.get();
361 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
362 bugreporter::trackExpressionValue(N, DE, *R);
363 C.emitReport(std::move(R));
368 void CallAndMessageChecker::checkPreCall(
const CallEvent &Call,
369 CheckerContext &C)
const {
375 SVal
V = CC->getCXXThisVal();
377 if (!BT_cxx_call_undef)
378 BT_cxx_call_undef.reset(
379 new BuiltinBug(
this,
"Called C++ object pointer is uninitialized"));
380 emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
385 std::tie(StNonNull, StNull) =
386 State->assume(V.castAs<DefinedOrUnknownSVal>());
388 if (StNull && !StNonNull) {
389 if (!BT_cxx_call_null)
390 BT_cxx_call_null.reset(
391 new BuiltinBug(
this,
"Called C++ object pointer is null"));
392 emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
399 const Decl *D = Call.getDecl();
400 if (D && (isa<FunctionDecl>(D) || isa<BlockDecl>(D))) {
403 unsigned Params = Call.parameters().size();
404 if (Call.getNumArgs() < Params) {
405 ExplodedNode *N = C.generateErrorNode();
409 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
412 llvm::raw_svector_ostream os(Str);
413 if (isa<FunctionDecl>(D)) {
416 assert(isa<BlockDecl>(D));
419 os <<
"taking " << Params <<
" argument" 420 << (Params == 1 ?
"" :
"s") <<
" is called with fewer (" 421 << Call.getNumArgs() <<
")";
424 llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
432 const bool checkUninitFields =
433 !(C.getAnalysisManager().shouldInlineCall() && (D && D->
getBody()));
435 std::unique_ptr<BugType> *BT;
436 if (isa<ObjCMethodCall>(Call))
441 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
442 for (
unsigned i = 0, e = Call.getNumArgs();
i != e; ++
i) {
444 if(FD && i < FD->getNumParams())
446 if (PreVisitProcessArg(C, Call.getArgSVal(
i), Call.getArgSourceRange(
i),
447 Call.getArgExpr(
i),
i,
448 checkUninitFields, Call, *BT, ParamDecl))
453 C.addTransition(State);
456 void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
457 CheckerContext &C)
const {
459 if (recVal.isUndef()) {
460 if (ExplodedNode *N = C.generateErrorNode()) {
461 BugType *BT =
nullptr;
465 BT_msg_undef.reset(
new BuiltinBug(
this,
466 "Receiver in message expression " 467 "is an uninitialized value"));
468 BT = BT_msg_undef.get();
471 if (!BT_objc_prop_undef)
472 BT_objc_prop_undef.reset(
new BuiltinBug(
473 this,
"Property access on an uninitialized object pointer"));
474 BT = BT_objc_prop_undef.get();
477 if (!BT_objc_subscript_undef)
478 BT_objc_subscript_undef.reset(
new BuiltinBug(
479 this,
"Subscript access on an uninitialized object pointer"));
480 BT = BT_objc_subscript_undef.get();
483 assert(BT &&
"Unknown message kind.");
485 auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
487 R->addRange(ME->getReceiverRange());
490 if (
const Expr *ReceiverE = ME->getInstanceReceiver())
491 bugreporter::trackExpressionValue(N, ReceiverE, *R);
492 C.emitReport(std::move(R));
498 void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
499 CheckerContext &C)
const {
500 HandleNilReceiver(C, C.getState(), msg);
503 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
505 ExplodedNode *N)
const {
509 new BuiltinBug(
this,
"Receiver in message expression is 'nil'"));
513 QualType ResTy = msg.getResultType();
516 llvm::raw_svector_ostream os(buf);
517 os <<
"The receiver of message '";
521 os <<
", which results in forming a null reference";
523 os <<
" and returns a value of type '";
524 msg.getResultType().print(os, C.getLangOpts());
525 os <<
"' that will be garbage";
528 auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
532 bugreporter::trackExpressionValue(N, receiver, *report);
534 C.emitReport(std::move(report));
538 return (triple.getVendor() == llvm::Triple::Apple &&
539 (triple.isiOS() || triple.isWatchOS() ||
540 !triple.isMacOSXVersionLT(10,5)));
543 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
547 static CheckerProgramPointTag Tag(
this,
"NilReceiver");
551 QualType RetTy = Msg.getResultType();
555 if (CanRetTy->isStructureOrClassType()) {
557 SVal
V = C.getSValBuilder().makeZeroVal(RetTy);
558 C.addTransition(state->BindExpr(Msg.
getOriginExpr(), LCtx,
V), &Tag);
563 if (CanRetTy != Ctx.
VoidTy && C.getLocationContext()->getParentMap()
567 const uint64_t returnTypeSize = Ctx.
getTypeSize(CanRetTy);
570 (voidPtrSize < returnTypeSize &&
577 if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
578 emitNilReceiverBug(C, Msg, N);
595 SVal
V = C.getSValBuilder().makeZeroVal(RetTy);
596 C.addTransition(state->BindExpr(Msg.
getOriginExpr(), LCtx,
V), &Tag);
600 C.addTransition(state);
603 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
604 mgr.registerChecker<CallAndMessageChecker>();
607 bool ento::shouldRegisterCallAndMessageChecker(
const LangOptions &LO) {
611 void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) {
612 CallAndMessageChecker *Checker = mgr.getChecker<CallAndMessageChecker>();
613 Checker->Check_CallAndMessageUnInitRefArg =
true;
614 Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckName();
617 bool ento::shouldRegisterCallAndMessageUnInitRefArg(
const LangOptions &LO) {
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
for(auto typeArg :T->getTypeArgsAsWritten())
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
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.
Represents a non-static C++ member function call, no matter how it is written.
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
Skip past any parentheses which might surround this expression until reaching a fixed point...