clang  13.0.0git
CallAndMessageChecker.cpp
Go to the documentation of this file.
1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This defines CallAndMessageChecker, a builtin checker that checks for various
10 // errors of call and objc message expressions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/AST/ExprCXX.h"
15 #include "clang/AST/ParentMap.h"
16 #include "clang/Basic/TargetInfo.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/Casting.h"
26 #include "llvm/Support/raw_ostream.h"
27 
28 using namespace clang;
29 using namespace ento;
30 
31 namespace {
32 
33 class CallAndMessageChecker
34  : public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35  check::PreCall> {
36  mutable std::unique_ptr<BugType> BT_call_null;
37  mutable std::unique_ptr<BugType> BT_call_undef;
38  mutable std::unique_ptr<BugType> BT_cxx_call_null;
39  mutable std::unique_ptr<BugType> BT_cxx_call_undef;
40  mutable std::unique_ptr<BugType> BT_call_arg;
41  mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
42  mutable std::unique_ptr<BugType> BT_msg_undef;
43  mutable std::unique_ptr<BugType> BT_objc_prop_undef;
44  mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
45  mutable std::unique_ptr<BugType> BT_msg_arg;
46  mutable std::unique_ptr<BugType> BT_msg_ret;
47  mutable std::unique_ptr<BugType> BT_call_few_args;
48 
49 public:
50  // These correspond with the checker options. Looking at other checkers such
51  // as MallocChecker and CStringChecker, this is similar as to how they pull
52  // off having a modeling class, but emitting diagnostics under a smaller
53  // checker's name that can be safely disabled without disturbing the
54  // underlaying modeling engine.
55  // The reason behind having *checker options* rather then actual *checkers*
56  // here is that CallAndMessage is among the oldest checkers out there, and can
57  // be responsible for the majority of the reports on any given project. This
58  // is obviously not ideal, but changing checker name has the consequence of
59  // changing the issue hashes associated with the reports, and databases
60  // relying on this (CodeChecker, for instance) would suffer greatly.
61  // If we ever end up making changes to the issue hash generation algorithm, or
62  // the warning messages here, we should totally jump on the opportunity to
63  // convert these to actual checkers.
64  enum CheckKind {
65  CK_FunctionPointer,
66  CK_ParameterCount,
67  CK_CXXThisMethodCall,
68  CK_CXXDeallocationArg,
69  CK_ArgInitializedness,
70  CK_ArgPointeeInitializedness,
71  CK_NilReceiver,
72  CK_UndefReceiver,
73  CK_NumCheckKinds
74  };
75 
76  DefaultBool ChecksEnabled[CK_NumCheckKinds];
77  // The original core.CallAndMessage checker name. This should rather be an
78  // array, as seen in MallocChecker and CStringChecker.
79  CheckerNameRef OriginalName;
80 
81  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
82 
83  /// Fill in the return value that results from messaging nil based on the
84  /// return type and architecture and diagnose if the return value will be
85  /// garbage.
86  void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;
87 
88  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
89 
90  ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,
91  CheckerContext &C,
92  ProgramStateRef State) const;
93 
94  ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,
95  CheckerContext &C,
96  ProgramStateRef State) const;
97 
98  ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,
99  ProgramStateRef State) const;
100 
101  ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,
102  CheckerContext &C,
103  ProgramStateRef State) const;
104 
105  ProgramStateRef checkArgInitializedness(const CallEvent &Call,
106  CheckerContext &C,
107  ProgramStateRef State) const;
108 
109 private:
110  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
111  const Expr *ArgEx, int ArgumentNumber,
112  bool CheckUninitFields, const CallEvent &Call,
113  std::unique_ptr<BugType> &BT,
114  const ParmVarDecl *ParamDecl) const;
115 
116  static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
117  void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
118  ExplodedNode *N) const;
119 
120  void HandleNilReceiver(CheckerContext &C,
122  const ObjCMethodCall &msg) const;
123 
124  void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
125  if (!BT)
126  BT.reset(new BuiltinBug(OriginalName, desc));
127  }
128  bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
129  SourceRange ArgRange, const Expr *ArgEx,
130  std::unique_ptr<BugType> &BT,
131  const ParmVarDecl *ParamDecl, const char *BD,
132  int ArgumentNumber) const;
133 };
134 } // end anonymous namespace
135 
136 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
137  const Expr *BadE) {
138  ExplodedNode *N = C.generateErrorNode();
139  if (!N)
140  return;
141 
142  auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
143  if (BadE) {
144  R->addRange(BadE->getSourceRange());
145  if (BadE->isGLValue())
146  BadE = bugreporter::getDerefExpr(BadE);
148  }
149  C.emitReport(std::move(R));
150 }
151 
152 static void describeUninitializedArgumentInCall(const CallEvent &Call,
153  int ArgumentNumber,
154  llvm::raw_svector_ostream &Os) {
155  switch (Call.getKind()) {
156  case CE_ObjCMessage: {
157  const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
158  switch (Msg.getMessageKind()) {
159  case OCM_Message:
160  Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
161  << " argument in message expression is an uninitialized value";
162  return;
163  case OCM_PropertyAccess:
164  assert(Msg.isSetter() && "Getters have no args");
165  Os << "Argument for property setter is an uninitialized value";
166  return;
167  case OCM_Subscript:
168  if (Msg.isSetter() && (ArgumentNumber == 0))
169  Os << "Argument for subscript setter is an uninitialized value";
170  else
171  Os << "Subscript index is an uninitialized value";
172  return;
173  }
174  llvm_unreachable("Unknown message kind.");
175  }
176  case CE_Block:
177  Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
178  << " block call argument is an uninitialized value";
179  return;
180  default:
181  Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
182  << " function call argument is an uninitialized value";
183  return;
184  }
185 }
186 
187 bool CallAndMessageChecker::uninitRefOrPointer(
188  CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
189  std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
190  int ArgumentNumber) const {
191 
192  // The pointee being uninitialized is a sign of code smell, not a bug, no need
193  // to sink here.
194  if (!ChecksEnabled[CK_ArgPointeeInitializedness])
195  return false;
196 
197  // No parameter declaration available, i.e. variadic function argument.
198  if(!ParamDecl)
199  return false;
200 
201  // If parameter is declared as pointer to const in function declaration,
202  // then check if corresponding argument in function call is
203  // pointing to undefined symbol value (uninitialized memory).
204  SmallString<200> Buf;
205  llvm::raw_svector_ostream Os(Buf);
206 
207  if (ParamDecl->getType()->isPointerType()) {
208  Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
209  << " function call argument is a pointer to uninitialized value";
210  } else if (ParamDecl->getType()->isReferenceType()) {
211  Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
212  << " function call argument is an uninitialized value";
213  } else
214  return false;
215 
216  if(!ParamDecl->getType()->getPointeeType().isConstQualified())
217  return false;
218 
219  if (const MemRegion *SValMemRegion = V.getAsRegion()) {
220  const ProgramStateRef State = C.getState();
221  const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
222  if (PSV.isUndef()) {
223  if (ExplodedNode *N = C.generateErrorNode()) {
224  LazyInit_BT(BD, BT);
225  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
226  R->addRange(ArgRange);
227  if (ArgEx)
228  bugreporter::trackExpressionValue(N, ArgEx, *R);
229 
230  C.emitReport(std::move(R));
231  }
232  return true;
233  }
234  }
235  return false;
236 }
237 
238 namespace {
239 class FindUninitializedField {
240 public:
242 
243 private:
244  StoreManager &StoreMgr;
245  MemRegionManager &MrMgr;
246  Store store;
247 
248 public:
249  FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
250  Store s)
251  : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
252 
253  bool Find(const TypedValueRegion *R) {
254  QualType T = R->getValueType();
255  if (const RecordType *RT = T->getAsStructureType()) {
256  const RecordDecl *RD = RT->getDecl()->getDefinition();
257  assert(RD && "Referred record has no definition");
258  for (const auto *I : RD->fields()) {
259  const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
260  FieldChain.push_back(I);
261  T = I->getType();
262  if (T->getAsStructureType()) {
263  if (Find(FR))
264  return true;
265  } else {
266  const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
267  if (V.isUndef())
268  return true;
269  }
270  FieldChain.pop_back();
271  }
272  }
273 
274  return false;
275  }
276 };
277 } // namespace
278 
279 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
280  SVal V,
281  SourceRange ArgRange,
282  const Expr *ArgEx,
283  int ArgumentNumber,
284  bool CheckUninitFields,
285  const CallEvent &Call,
286  std::unique_ptr<BugType> &BT,
287  const ParmVarDecl *ParamDecl
288  ) const {
289  const char *BD = "Uninitialized argument value";
290 
291  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
292  ArgumentNumber))
293  return true;
294 
295  if (V.isUndef()) {
296  if (!ChecksEnabled[CK_ArgInitializedness]) {
297  C.addSink();
298  return true;
299  }
300  if (ExplodedNode *N = C.generateErrorNode()) {
301  LazyInit_BT(BD, BT);
302  // Generate a report for this bug.
303  SmallString<200> Buf;
304  llvm::raw_svector_ostream Os(Buf);
305  describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
306  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
307 
308  R->addRange(ArgRange);
309  if (ArgEx)
310  bugreporter::trackExpressionValue(N, ArgEx, *R);
311  C.emitReport(std::move(R));
312  }
313  return true;
314  }
315 
316  if (!CheckUninitFields)
317  return false;
318 
319  if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
320  const LazyCompoundValData *D = LV->getCVData();
321  FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
322  C.getSValBuilder().getRegionManager(),
323  D->getStore());
324 
325  if (F.Find(D->getRegion())) {
326  if (!ChecksEnabled[CK_ArgInitializedness]) {
327  C.addSink();
328  return true;
329  }
330  if (ExplodedNode *N = C.generateErrorNode()) {
331  LazyInit_BT(BD, BT);
332  SmallString<512> Str;
333  llvm::raw_svector_ostream os(Str);
334  os << "Passed-by-value struct argument contains uninitialized data";
335 
336  if (F.FieldChain.size() == 1)
337  os << " (e.g., field: '" << *F.FieldChain[0] << "')";
338  else {
339  os << " (e.g., via the field chain: '";
340  bool first = true;
342  DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
343  if (first)
344  first = false;
345  else
346  os << '.';
347  os << **DI;
348  }
349  os << "')";
350  }
351 
352  // Generate a report for this bug.
353  auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
354  R->addRange(ArgRange);
355 
356  if (ArgEx)
357  bugreporter::trackExpressionValue(N, ArgEx, *R);
358  // FIXME: enhance track back for uninitialized value for arbitrary
359  // memregions
360  C.emitReport(std::move(R));
361  }
362  return true;
363  }
364  }
365 
366  return false;
367 }
368 
369 ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
370  const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
371 
372  const Expr *Callee = CE->getCallee()->IgnoreParens();
373  const LocationContext *LCtx = C.getLocationContext();
374  SVal L = State->getSVal(Callee, LCtx);
375 
376  if (L.isUndef()) {
377  if (!ChecksEnabled[CK_FunctionPointer]) {
378  C.addSink(State);
379  return nullptr;
380  }
381  if (!BT_call_undef)
382  BT_call_undef.reset(new BuiltinBug(
383  OriginalName,
384  "Called function pointer is an uninitialized pointer value"));
385  emitBadCall(BT_call_undef.get(), C, Callee);
386  return nullptr;
387  }
388 
389  ProgramStateRef StNonNull, StNull;
390  std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
391 
392  if (StNull && !StNonNull) {
393  if (!ChecksEnabled[CK_FunctionPointer]) {
394  C.addSink(StNull);
395  return nullptr;
396  }
397  if (!BT_call_null)
398  BT_call_null.reset(new BuiltinBug(
399  OriginalName, "Called function pointer is null (null dereference)"));
400  emitBadCall(BT_call_null.get(), C, Callee);
401  return nullptr;
402  }
403 
404  return StNonNull;
405 }
406 
407 ProgramStateRef CallAndMessageChecker::checkParameterCount(
408  const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
409 
410  // If we have a function or block declaration, we can make sure we pass
411  // enough parameters.
412  unsigned Params = Call.parameters().size();
413  if (Call.getNumArgs() >= Params)
414  return State;
415 
416  if (!ChecksEnabled[CK_ParameterCount]) {
417  C.addSink(State);
418  return nullptr;
419  }
420 
421  ExplodedNode *N = C.generateErrorNode();
422  if (!N)
423  return nullptr;
424 
425  LazyInit_BT("Function call with too few arguments", BT_call_few_args);
426 
427  SmallString<512> Str;
428  llvm::raw_svector_ostream os(Str);
429  if (isa<AnyFunctionCall>(Call)) {
430  os << "Function ";
431  } else {
432  assert(isa<BlockCall>(Call));
433  os << "Block ";
434  }
435  os << "taking " << Params << " argument" << (Params == 1 ? "" : "s")
436  << " is called with fewer (" << Call.getNumArgs() << ")";
437 
438  C.emitReport(
439  std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
440  return nullptr;
441 }
442 
443 ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
444  const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {
445 
446  SVal V = CC->getCXXThisVal();
447  if (V.isUndef()) {
448  if (!ChecksEnabled[CK_CXXThisMethodCall]) {
449  C.addSink(State);
450  return nullptr;
451  }
452  if (!BT_cxx_call_undef)
453  BT_cxx_call_undef.reset(new BuiltinBug(
454  OriginalName, "Called C++ object pointer is uninitialized"));
455  emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
456  return nullptr;
457  }
458 
459  ProgramStateRef StNonNull, StNull;
460  std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
461 
462  if (StNull && !StNonNull) {
463  if (!ChecksEnabled[CK_CXXThisMethodCall]) {
464  C.addSink(StNull);
465  return nullptr;
466  }
467  if (!BT_cxx_call_null)
468  BT_cxx_call_null.reset(
469  new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
470  emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
471  return nullptr;
472  }
473 
474  return StNonNull;
475 }
476 
478 CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
479  CheckerContext &C,
480  ProgramStateRef State) const {
481  const CXXDeleteExpr *DE = DC->getOriginExpr();
482  assert(DE);
483  SVal Arg = C.getSVal(DE->getArgument());
484  if (!Arg.isUndef())
485  return State;
486 
487  if (!ChecksEnabled[CK_CXXDeallocationArg]) {
488  C.addSink(State);
489  return nullptr;
490  }
491 
492  StringRef Desc;
493  ExplodedNode *N = C.generateErrorNode();
494  if (!N)
495  return nullptr;
496  if (!BT_cxx_delete_undef)
497  BT_cxx_delete_undef.reset(
498  new BuiltinBug(OriginalName, "Uninitialized argument value"));
499  if (DE->isArrayFormAsWritten())
500  Desc = "Argument to 'delete[]' is uninitialized";
501  else
502  Desc = "Argument to 'delete' is uninitialized";
503  BugType *BT = BT_cxx_delete_undef.get();
504  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
506  C.emitReport(std::move(R));
507  return nullptr;
508 }
509 
510 ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
511  const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
512 
513  const Decl *D = Call.getDecl();
514 
515  // Don't check for uninitialized field values in arguments if the
516  // caller has a body that is available and we have the chance to inline it.
517  // This is a hack, but is a reasonable compromise betweens sometimes warning
518  // and sometimes not depending on if we decide to inline a function.
519  const bool checkUninitFields =
520  !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
521 
522  std::unique_ptr<BugType> *BT;
523  if (isa<ObjCMethodCall>(Call))
524  BT = &BT_msg_arg;
525  else
526  BT = &BT_call_arg;
527 
528  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
529  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
530  const ParmVarDecl *ParamDecl = nullptr;
531  if (FD && i < FD->getNumParams())
532  ParamDecl = FD->getParamDecl(i);
533  if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
534  Call.getArgExpr(i), i, checkUninitFields, Call, *BT,
535  ParamDecl))
536  return nullptr;
537  }
538  return State;
539 }
540 
541 void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
542  CheckerContext &C) const {
543  ProgramStateRef State = C.getState();
544 
545  if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))
546  State = checkFunctionPointerCall(CE, C, State);
547 
548  if (!State)
549  return;
550 
551  if (Call.getDecl())
552  State = checkParameterCount(Call, C, State);
553 
554  if (!State)
555  return;
556 
557  if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))
558  State = checkCXXMethodCall(CC, C, State);
559 
560  if (!State)
561  return;
562 
563  if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))
564  State = checkCXXDeallocation(DC, C, State);
565 
566  if (!State)
567  return;
568 
569  State = checkArgInitializedness(Call, C, State);
570 
571  // If we make it here, record our assumptions about the callee.
572  C.addTransition(State);
573 }
574 
575 void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
576  CheckerContext &C) const {
577  SVal recVal = msg.getReceiverSVal();
578  if (recVal.isUndef()) {
579  if (!ChecksEnabled[CK_UndefReceiver]) {
580  C.addSink();
581  return;
582  }
583  if (ExplodedNode *N = C.generateErrorNode()) {
584  BugType *BT = nullptr;
585  switch (msg.getMessageKind()) {
586  case OCM_Message:
587  if (!BT_msg_undef)
588  BT_msg_undef.reset(new BuiltinBug(OriginalName,
589  "Receiver in message expression "
590  "is an uninitialized value"));
591  BT = BT_msg_undef.get();
592  break;
593  case OCM_PropertyAccess:
594  if (!BT_objc_prop_undef)
595  BT_objc_prop_undef.reset(new BuiltinBug(
596  OriginalName,
597  "Property access on an uninitialized object pointer"));
598  BT = BT_objc_prop_undef.get();
599  break;
600  case OCM_Subscript:
601  if (!BT_objc_subscript_undef)
602  BT_objc_subscript_undef.reset(new BuiltinBug(
603  OriginalName,
604  "Subscript access on an uninitialized object pointer"));
605  BT = BT_objc_subscript_undef.get();
606  break;
607  }
608  assert(BT && "Unknown message kind.");
609 
610  auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
611  const ObjCMessageExpr *ME = msg.getOriginExpr();
612  R->addRange(ME->getReceiverRange());
613 
614  // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
615  if (const Expr *ReceiverE = ME->getInstanceReceiver())
616  bugreporter::trackExpressionValue(N, ReceiverE, *R);
617  C.emitReport(std::move(R));
618  }
619  return;
620  }
621 }
622 
623 void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
624  CheckerContext &C) const {
625  HandleNilReceiver(C, C.getState(), msg);
626 }
627 
628 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
629  const ObjCMethodCall &msg,
630  ExplodedNode *N) const {
631  if (!ChecksEnabled[CK_NilReceiver]) {
632  C.addSink();
633  return;
634  }
635 
636  if (!BT_msg_ret)
637  BT_msg_ret.reset(new BuiltinBug(OriginalName,
638  "Receiver in message expression is 'nil'"));
639 
640  const ObjCMessageExpr *ME = msg.getOriginExpr();
641 
642  QualType ResTy = msg.getResultType();
643 
644  SmallString<200> buf;
645  llvm::raw_svector_ostream os(buf);
646  os << "The receiver of message '";
647  ME->getSelector().print(os);
648  os << "' is nil";
649  if (ResTy->isReferenceType()) {
650  os << ", which results in forming a null reference";
651  } else {
652  os << " and returns a value of type '";
653  msg.getResultType().print(os, C.getLangOpts());
654  os << "' that will be garbage";
655  }
656 
657  auto report =
658  std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
659  report->addRange(ME->getReceiverRange());
660  // FIXME: This won't track "self" in messages to super.
661  if (const Expr *receiver = ME->getInstanceReceiver()) {
662  bugreporter::trackExpressionValue(N, receiver, *report);
663  }
664  C.emitReport(std::move(report));
665 }
666 
667 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
668  return (triple.getVendor() == llvm::Triple::Apple &&
669  (triple.isiOS() || triple.isWatchOS() ||
670  !triple.isMacOSXVersionLT(10,5)));
671 }
672 
673 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
675  const ObjCMethodCall &Msg) const {
676  ASTContext &Ctx = C.getASTContext();
677  static CheckerProgramPointTag Tag(this, "NilReceiver");
678 
679  // Check the return type of the message expression. A message to nil will
680  // return different values depending on the return type and the architecture.
681  QualType RetTy = Msg.getResultType();
682  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
683  const LocationContext *LCtx = C.getLocationContext();
684 
685  if (CanRetTy->isStructureOrClassType()) {
686  // Structure returns are safe since the compiler zeroes them out.
687  SVal V = C.getSValBuilder().makeZeroVal(RetTy);
688  C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
689  return;
690  }
691 
692  // Other cases: check if sizeof(return type) > sizeof(void*)
693  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
694  .isConsumedExpr(Msg.getOriginExpr())) {
695  // Compute: sizeof(void *) and sizeof(return type)
696  const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
697  const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
698 
699  if (CanRetTy.getTypePtr()->isReferenceType()||
700  (voidPtrSize < returnTypeSize &&
702  (Ctx.FloatTy == CanRetTy ||
703  Ctx.DoubleTy == CanRetTy ||
704  Ctx.LongDoubleTy == CanRetTy ||
705  Ctx.LongLongTy == CanRetTy ||
706  Ctx.UnsignedLongLongTy == CanRetTy)))) {
707  if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
708  emitNilReceiverBug(C, Msg, N);
709  return;
710  }
711 
712  // Handle the safe cases where the return value is 0 if the
713  // receiver is nil.
714  //
715  // FIXME: For now take the conservative approach that we only
716  // return null values if we *know* that the receiver is nil.
717  // This is because we can have surprises like:
718  //
719  // ... = [[NSScreens screens] objectAtIndex:0];
720  //
721  // What can happen is that [... screens] could return nil, but
722  // it most likely isn't nil. We should assume the semantics
723  // of this case unless we have *a lot* more knowledge.
724  //
725  SVal V = C.getSValBuilder().makeZeroVal(RetTy);
726  C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
727  return;
728  }
729 
730  C.addTransition(state);
731 }
732 
733 void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
734  mgr.registerChecker<CallAndMessageChecker>();
735 }
736 
737 bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
738  return true;
739 }
740 
741 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
742  CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
743 
744  checker->OriginalName = mgr.getCurrentCheckerName();
745 
746 #define QUERY_CHECKER_OPTION(OPTION) \
747  checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
748  mgr.getAnalyzerOptions().getCheckerBooleanOption( \
749  mgr.getCurrentCheckerName(), #OPTION);
750 
751  QUERY_CHECKER_OPTION(FunctionPointer)
752  QUERY_CHECKER_OPTION(ParameterCount)
753  QUERY_CHECKER_OPTION(CXXThisMethodCall)
754  QUERY_CHECKER_OPTION(CXXDeallocationArg)
755  QUERY_CHECKER_OPTION(ArgInitializedness)
756  QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
757  QUERY_CHECKER_OPTION(NilReceiver)
758  QUERY_CHECKER_OPTION(UndefReceiver)
759 }
760 
761 bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
762  return true;
763 }
clang::ASTContext::LongDoubleTy
CanQualType LongDoubleTy
Definition: ASTContext.h:1057
clang::LocationContext
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
Definition: AnalysisDeclContext.h:215
clang::ento::OCM_Subscript
@ OCM_Subscript
Definition: CallEvent.h:1113
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:212
clang::QualType::isConstQualified
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: Type.h:6486
supportsNilWithFloatRet
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
Definition: CallAndMessageChecker.cpp:667
clang::ObjCMessageExpr::getSelector
Selector getSelector() const
Definition: ExprObjC.cpp:306
clang::ASTContext::VoidTy
CanQualType VoidTy
Definition: ASTContext.h:1045
llvm::SmallVector
Definition: LLVM.h:38
clang::ObjCMessageExpr::getReceiverRange
SourceRange getReceiverRange() const
Source range of the receiver.
Definition: ExprObjC.cpp:290
TargetInfo.h
clang::Stmt::getSourceRange
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:324
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:668
clang::FunctionDecl::getParamDecl
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2504
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::ParmVarDecl
Represents a parameter to a function.
Definition: Decl.h:1663
clang::ObjCMessageExpr::getInstanceReceiver
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition: ExprObjC.h:1250
clang::RecordDecl::getDefinition
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition: Decl.h:4054
clang::index::SymbolRole::Call
@ Call
clang::ento::Store
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
Definition: StoreRef.h:27
clang::Expr::isGLValue
bool isGLValue() const
Definition: Expr.h:273
CallEvent.h
clang::Type::getAsStructureType
const RecordType * getAsStructureType() const
Definition: Type.cpp:641
clang::ento::CE_Block
@ CE_Block
Definition: CallEvent.h:74
clang::CanQual::getTypePtr
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
Definition: CanonicalType.h:83
clang::Type::isReferenceType
bool isReferenceType() const
Definition: Type.h:6687
clang::CallExpr::getCallee
Expr * getCallee()
Definition: Expr.h:2939
V
#define V(N, I)
Definition: ASTContext.h:3083
clang::ento::OCM_PropertyAccess
@ OCM_PropertyAccess
Definition: CallEvent.h:1112
clang::RecordType
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4615
BuiltinCheckerRegistration.h
clang::syntax::NodeRole::Callee
@ Callee
CheckerManager.h
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:189
clang::ASTContext::getTypeSize
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2209
clang::Selector::print
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
Definition: IdentifierTable.cpp:542
llvm::SmallString
Definition: LLVM.h:37
clang::ASTContext::FloatTy
CanQualType FloatTy
Definition: ASTContext.h:1057
clang::Type::getPointeeType
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:625
clang::ASTContext::getCanonicalType
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2432
QUERY_CHECKER_OPTION
#define QUERY_CHECKER_OPTION(OPTION)
clang::CanQual< Type >
ExprCXX.h
clang::ento::CE_ObjCMessage
@ CE_ObjCMessage
Definition: CallEvent.h:75
clang::ObjCMessageExpr
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:940
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
clang::ASTContext::UnsignedLongLongTy
CanQualType UnsignedLongLongTy
Definition: ASTContext.h:1056
clang::ento::bugreporter::trackExpressionValue
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
clang::TargetInfo::getTriple
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1110
clang::ento::bugreporter::getDerefExpr
const Expr * getDerefExpr(const Stmt *S)
clang::ASTContext::LongLongTy
CanQualType LongLongTy
Definition: ASTContext.h:1054
clang::ASTContext::VoidPtrTy
CanQualType VoidPtrTy
Definition: ASTContext.h:1074
clang::Type::isPointerType
bool isPointerType() const
Definition: Type.h:6675
clang::ASTContext::DoubleTy
CanQualType DoubleTy
Definition: ASTContext.h:1057
BugType.h
describeUninitializedArgumentInCall
static void describeUninitializedArgumentInCall(const CallEvent &Call, int ArgumentNumber, llvm::raw_svector_ostream &Os)
Definition: CallAndMessageChecker.cpp:152
clang::RecordDecl::fields
field_range fields() const
Definition: Decl.h:4069
clang::CXXDeleteExpr
Represents a delete expression for memory deallocation and destructor calls, e.g.
Definition: ExprCXX.h:2398
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
State
LineState State
Definition: UnwrappedLineFormatter.cpp:985
clang::ASTContext::getTargetInfo
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:718
CheckerContext.h
clang::Decl::getBody
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:1010
Checker.h
ParentMap.h
clang::ento::OCM_Message
@ OCM_Message
Definition: CallEvent.h:1114
clang::Expr::IgnoreParens
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:2921
clang
Definition: CalledOnceCheck.h:17
s
__device__ __2f16 float bool s
Definition: __clang_hip_libdevice_declares.h:315
clang::CXXDeleteExpr::getArgument
Expr * getArgument()
Definition: ExprCXX.h:2439
llvm::SmallVectorImpl
Definition: LLVM.h:39
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:685
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::CXXDeleteExpr::isArrayFormAsWritten
bool isArrayFormAsWritten() const
Definition: ExprCXX.h:2425
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1854
clang::RecordDecl
Represents a struct/union/class.
Definition: Decl.h:3849
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2789