xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (revision b89843299a118d9f97774f35e59f9b541ef5e284)
1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This defines CallAndMessageChecker, a builtin checker that checks for various
11 // errors of call and objc message expressions.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
16 #include "clang/AST/ParentMap.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19 #include "clang/StaticAnalyzer/Core/Checker.h"
20 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 class CallAndMessageChecker
31   : public Checker< check::PreStmt<CallExpr>,
32                     check::PreStmt<CXXDeleteExpr>,
33                     check::PreObjCMessage,
34                     check::PreCall > {
35   mutable std::unique_ptr<BugType> BT_call_null;
36   mutable std::unique_ptr<BugType> BT_call_undef;
37   mutable std::unique_ptr<BugType> BT_cxx_call_null;
38   mutable std::unique_ptr<BugType> BT_cxx_call_undef;
39   mutable std::unique_ptr<BugType> BT_call_arg;
40   mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
41   mutable std::unique_ptr<BugType> BT_msg_undef;
42   mutable std::unique_ptr<BugType> BT_objc_prop_undef;
43   mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
44   mutable std::unique_ptr<BugType> BT_msg_arg;
45   mutable std::unique_ptr<BugType> BT_msg_ret;
46   mutable std::unique_ptr<BugType> BT_call_few_args;
47 
48 public:
49 
50   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
51   void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
52   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
53   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
54 
55 private:
56   bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
57                           const Expr *argEx, bool IsFirstArgument,
58                           bool checkUninitFields, const CallEvent &Call,
59                           std::unique_ptr<BugType> &BT) const;
60 
61   static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
62   void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
63                           ExplodedNode *N) const;
64 
65   void HandleNilReceiver(CheckerContext &C,
66                          ProgramStateRef state,
67                          const ObjCMethodCall &msg) const;
68 
69   void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
70     if (!BT)
71       BT.reset(new BuiltinBug(this, desc));
72   }
73 };
74 } // end anonymous namespace
75 
76 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
77                                         const Expr *BadE) {
78   ExplodedNode *N = C.generateSink();
79   if (!N)
80     return;
81 
82   BugReport *R = new BugReport(*BT, BT->getName(), N);
83   if (BadE) {
84     R->addRange(BadE->getSourceRange());
85     if (BadE->isGLValue())
86       BadE = bugreporter::getDerefExpr(BadE);
87     bugreporter::trackNullOrUndefValue(N, BadE, *R);
88   }
89   C.emitReport(R);
90 }
91 
92 static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
93                                                      bool IsFirstArgument) {
94   switch (Call.getKind()) {
95   case CE_ObjCMessage: {
96     const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
97     switch (Msg.getMessageKind()) {
98     case OCM_Message:
99       return "Argument in message expression is an uninitialized value";
100     case OCM_PropertyAccess:
101       assert(Msg.isSetter() && "Getters have no args");
102       return "Argument for property setter is an uninitialized value";
103     case OCM_Subscript:
104       if (Msg.isSetter() && IsFirstArgument)
105         return "Argument for subscript setter is an uninitialized value";
106       return "Subscript index is an uninitialized value";
107     }
108     llvm_unreachable("Unknown message kind.");
109   }
110   case CE_Block:
111     return "Block call argument is an uninitialized value";
112   default:
113     return "Function call argument is an uninitialized value";
114   }
115 }
116 
117 bool CallAndMessageChecker::PreVisitProcessArg(
118     CheckerContext &C, SVal V, SourceRange argRange, const Expr *argEx,
119     bool IsFirstArgument, bool checkUninitFields, const CallEvent &Call,
120     std::unique_ptr<BugType> &BT) const {
121   if (V.isUndef()) {
122     if (ExplodedNode *N = C.generateSink()) {
123       LazyInit_BT("Uninitialized argument value", BT);
124 
125       // Generate a report for this bug.
126       StringRef Desc = describeUninitializedArgumentInCall(Call,
127                                                            IsFirstArgument);
128       BugReport *R = new BugReport(*BT, Desc, N);
129       R->addRange(argRange);
130       if (argEx)
131         bugreporter::trackNullOrUndefValue(N, argEx, *R);
132       C.emitReport(R);
133     }
134     return true;
135   }
136 
137   if (!checkUninitFields)
138     return false;
139 
140   if (Optional<nonloc::LazyCompoundVal> LV =
141           V.getAs<nonloc::LazyCompoundVal>()) {
142 
143     class FindUninitializedField {
144     public:
145       SmallVector<const FieldDecl *, 10> FieldChain;
146     private:
147       StoreManager &StoreMgr;
148       MemRegionManager &MrMgr;
149       Store store;
150     public:
151       FindUninitializedField(StoreManager &storeMgr,
152                              MemRegionManager &mrMgr, Store s)
153       : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
154 
155       bool Find(const TypedValueRegion *R) {
156         QualType T = R->getValueType();
157         if (const RecordType *RT = T->getAsStructureType()) {
158           const RecordDecl *RD = RT->getDecl()->getDefinition();
159           assert(RD && "Referred record has no definition");
160           for (RecordDecl::field_iterator I =
161                RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
162             const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
163             FieldChain.push_back(*I);
164             T = I->getType();
165             if (T->getAsStructureType()) {
166               if (Find(FR))
167                 return true;
168             }
169             else {
170               const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
171               if (V.isUndef())
172                 return true;
173             }
174             FieldChain.pop_back();
175           }
176         }
177 
178         return false;
179       }
180     };
181 
182     const LazyCompoundValData *D = LV->getCVData();
183     FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
184                              C.getSValBuilder().getRegionManager(),
185                              D->getStore());
186 
187     if (F.Find(D->getRegion())) {
188       if (ExplodedNode *N = C.generateSink()) {
189         LazyInit_BT("Uninitialized argument value", BT);
190         SmallString<512> Str;
191         llvm::raw_svector_ostream os(Str);
192         os << "Passed-by-value struct argument contains uninitialized data";
193 
194         if (F.FieldChain.size() == 1)
195           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
196         else {
197           os << " (e.g., via the field chain: '";
198           bool first = true;
199           for (SmallVectorImpl<const FieldDecl *>::iterator
200                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
201             if (first)
202               first = false;
203             else
204               os << '.';
205             os << **DI;
206           }
207           os << "')";
208         }
209 
210         // Generate a report for this bug.
211         BugReport *R = new BugReport(*BT, os.str(), N);
212         R->addRange(argRange);
213 
214         // FIXME: enhance track back for uninitialized value for arbitrary
215         // memregions
216         C.emitReport(R);
217       }
218       return true;
219     }
220   }
221 
222   return false;
223 }
224 
225 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
226                                          CheckerContext &C) const{
227 
228   const Expr *Callee = CE->getCallee()->IgnoreParens();
229   ProgramStateRef State = C.getState();
230   const LocationContext *LCtx = C.getLocationContext();
231   SVal L = State->getSVal(Callee, LCtx);
232 
233   if (L.isUndef()) {
234     if (!BT_call_undef)
235       BT_call_undef.reset(new BuiltinBug(
236           this, "Called function pointer is an uninitalized pointer value"));
237     emitBadCall(BT_call_undef.get(), C, Callee);
238     return;
239   }
240 
241   ProgramStateRef StNonNull, StNull;
242   std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
243 
244   if (StNull && !StNonNull) {
245     if (!BT_call_null)
246       BT_call_null.reset(new BuiltinBug(
247           this, "Called function pointer is null (null dereference)"));
248     emitBadCall(BT_call_null.get(), C, Callee);
249     return;
250   }
251 
252   C.addTransition(StNonNull);
253 }
254 
255 void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
256                                          CheckerContext &C) const {
257 
258   SVal Arg = C.getSVal(DE->getArgument());
259   if (Arg.isUndef()) {
260     StringRef Desc;
261     ExplodedNode *N = C.generateSink();
262     if (!N)
263       return;
264     if (!BT_cxx_delete_undef)
265       BT_cxx_delete_undef.reset(
266           new BuiltinBug(this, "Uninitialized argument value"));
267     if (DE->isArrayFormAsWritten())
268       Desc = "Argument to 'delete[]' is uninitialized";
269     else
270       Desc = "Argument to 'delete' is uninitialized";
271     BugType *BT = BT_cxx_delete_undef.get();
272     BugReport *R = new BugReport(*BT, Desc, N);
273     bugreporter::trackNullOrUndefValue(N, DE, *R);
274     C.emitReport(R);
275     return;
276   }
277 }
278 
279 
280 void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
281                                          CheckerContext &C) const {
282   ProgramStateRef State = C.getState();
283 
284   // If this is a call to a C++ method, check if the callee is null or
285   // undefined.
286   if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
287     SVal V = CC->getCXXThisVal();
288     if (V.isUndef()) {
289       if (!BT_cxx_call_undef)
290         BT_cxx_call_undef.reset(
291             new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
292       emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
293       return;
294     }
295 
296     ProgramStateRef StNonNull, StNull;
297     std::tie(StNonNull, StNull) =
298         State->assume(V.castAs<DefinedOrUnknownSVal>());
299 
300     if (StNull && !StNonNull) {
301       if (!BT_cxx_call_null)
302         BT_cxx_call_null.reset(
303             new BuiltinBug(this, "Called C++ object pointer is null"));
304       emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
305       return;
306     }
307 
308     State = StNonNull;
309   }
310 
311   const Decl *D = Call.getDecl();
312   if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
313     // If we have a declaration, we can make sure we pass enough parameters to
314     // the function.
315     unsigned Params = FD->getNumParams();
316     if (Call.getNumArgs() < Params) {
317       ExplodedNode *N = C.generateSink();
318       if (!N)
319         return;
320 
321       LazyInit_BT("Function call with too few arguments", BT_call_few_args);
322 
323       SmallString<512> Str;
324       llvm::raw_svector_ostream os(Str);
325       os << "Function taking " << Params << " argument"
326          << (Params == 1 ? "" : "s") << " is called with less ("
327          << Call.getNumArgs() << ")";
328 
329       BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
330       C.emitReport(R);
331     }
332   }
333 
334   // Don't check for uninitialized field values in arguments if the
335   // caller has a body that is available and we have the chance to inline it.
336   // This is a hack, but is a reasonable compromise betweens sometimes warning
337   // and sometimes not depending on if we decide to inline a function.
338   const bool checkUninitFields =
339     !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
340 
341   std::unique_ptr<BugType> *BT;
342   if (isa<ObjCMethodCall>(Call))
343     BT = &BT_msg_arg;
344   else
345     BT = &BT_call_arg;
346 
347   for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
348     if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
349                            Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
350                            checkUninitFields, Call, *BT))
351       return;
352 
353   // If we make it here, record our assumptions about the callee.
354   C.addTransition(State);
355 }
356 
357 void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
358                                                 CheckerContext &C) const {
359   SVal recVal = msg.getReceiverSVal();
360   if (recVal.isUndef()) {
361     if (ExplodedNode *N = C.generateSink()) {
362       BugType *BT = 0;
363       switch (msg.getMessageKind()) {
364       case OCM_Message:
365         if (!BT_msg_undef)
366           BT_msg_undef.reset(new BuiltinBug(this,
367                                             "Receiver in message expression "
368                                             "is an uninitialized value"));
369         BT = BT_msg_undef.get();
370         break;
371       case OCM_PropertyAccess:
372         if (!BT_objc_prop_undef)
373           BT_objc_prop_undef.reset(new BuiltinBug(
374               this, "Property access on an uninitialized object pointer"));
375         BT = BT_objc_prop_undef.get();
376         break;
377       case OCM_Subscript:
378         if (!BT_objc_subscript_undef)
379           BT_objc_subscript_undef.reset(new BuiltinBug(
380               this, "Subscript access on an uninitialized object pointer"));
381         BT = BT_objc_subscript_undef.get();
382         break;
383       }
384       assert(BT && "Unknown message kind.");
385 
386       BugReport *R = new BugReport(*BT, BT->getName(), N);
387       const ObjCMessageExpr *ME = msg.getOriginExpr();
388       R->addRange(ME->getReceiverRange());
389 
390       // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
391       if (const Expr *ReceiverE = ME->getInstanceReceiver())
392         bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
393       C.emitReport(R);
394     }
395     return;
396   } else {
397     // Bifurcate the state into nil and non-nil ones.
398     DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();
399 
400     ProgramStateRef state = C.getState();
401     ProgramStateRef notNilState, nilState;
402     std::tie(notNilState, nilState) = state->assume(receiverVal);
403 
404     // Handle receiver must be nil.
405     if (nilState && !notNilState) {
406       HandleNilReceiver(C, state, msg);
407       return;
408     }
409   }
410 }
411 
412 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
413                                                const ObjCMethodCall &msg,
414                                                ExplodedNode *N) const {
415 
416   if (!BT_msg_ret)
417     BT_msg_ret.reset(
418         new BuiltinBug(this, "Receiver in message expression is 'nil'"));
419 
420   const ObjCMessageExpr *ME = msg.getOriginExpr();
421 
422   QualType ResTy = msg.getResultType();
423 
424   SmallString<200> buf;
425   llvm::raw_svector_ostream os(buf);
426   os << "The receiver of message '";
427   ME->getSelector().print(os);
428   os << "' is nil";
429   if (ResTy->isReferenceType()) {
430     os << ", which results in forming a null reference";
431   } else {
432     os << " and returns a value of type '";
433     msg.getResultType().print(os, C.getLangOpts());
434     os << "' that will be garbage";
435   }
436 
437   BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
438   report->addRange(ME->getReceiverRange());
439   // FIXME: This won't track "self" in messages to super.
440   if (const Expr *receiver = ME->getInstanceReceiver()) {
441     bugreporter::trackNullOrUndefValue(N, receiver, *report);
442   }
443   C.emitReport(report);
444 }
445 
446 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
447   return (triple.getVendor() == llvm::Triple::Apple &&
448           (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
449 }
450 
451 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
452                                               ProgramStateRef state,
453                                               const ObjCMethodCall &Msg) const {
454   ASTContext &Ctx = C.getASTContext();
455   static CheckerProgramPointTag Tag(this, "NilReceiver");
456 
457   // Check the return type of the message expression.  A message to nil will
458   // return different values depending on the return type and the architecture.
459   QualType RetTy = Msg.getResultType();
460   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
461   const LocationContext *LCtx = C.getLocationContext();
462 
463   if (CanRetTy->isStructureOrClassType()) {
464     // Structure returns are safe since the compiler zeroes them out.
465     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
466     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
467     return;
468   }
469 
470   // Other cases: check if sizeof(return type) > sizeof(void*)
471   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
472                                   .isConsumedExpr(Msg.getOriginExpr())) {
473     // Compute: sizeof(void *) and sizeof(return type)
474     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
475     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
476 
477     if (CanRetTy.getTypePtr()->isReferenceType()||
478         (voidPtrSize < returnTypeSize &&
479          !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
480            (Ctx.FloatTy == CanRetTy ||
481             Ctx.DoubleTy == CanRetTy ||
482             Ctx.LongDoubleTy == CanRetTy ||
483             Ctx.LongLongTy == CanRetTy ||
484             Ctx.UnsignedLongLongTy == CanRetTy)))) {
485       if (ExplodedNode *N = C.generateSink(state, 0 , &Tag))
486         emitNilReceiverBug(C, Msg, N);
487       return;
488     }
489 
490     // Handle the safe cases where the return value is 0 if the
491     // receiver is nil.
492     //
493     // FIXME: For now take the conservative approach that we only
494     // return null values if we *know* that the receiver is nil.
495     // This is because we can have surprises like:
496     //
497     //   ... = [[NSScreens screens] objectAtIndex:0];
498     //
499     // What can happen is that [... screens] could return nil, but
500     // it most likely isn't nil.  We should assume the semantics
501     // of this case unless we have *a lot* more knowledge.
502     //
503     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
504     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
505     return;
506   }
507 
508   C.addTransition(state);
509 }
510 
511 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
512   mgr.registerChecker<CallAndMessageChecker>();
513 }
514