clang 22.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"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/raw_ostream.h"
27
28using namespace clang;
29using namespace ento;
30
31namespace {
32
33class CallAndMessageChecker
34 : public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35 check::PreCall> {
36 const BugType CallNullBug{
37 this, "Called function pointer is null (null dereference)"};
38 const BugType CallUndefBug{
39 this, "Called function pointer is an uninitialized pointer value"};
40 const BugType CXXCallNullBug{this, "Called C++ object pointer is null"};
41 const BugType CXXCallUndefBug{this,
42 "Called C++ object pointer is uninitialized"};
43 const BugType CallArgBug{this, "Uninitialized argument value"};
44 const BugType CXXDeleteUndefBug{this, "Uninitialized argument value"};
45 const BugType MsgUndefBug{
46 this, "Receiver in message expression is an uninitialized value"};
47 const BugType ObjCPropUndefBug{
48 this, "Property access on an uninitialized object pointer"};
49 const BugType ObjCSubscriptUndefBug{
50 this, "Subscript access on an uninitialized object pointer"};
51 const BugType MsgArgBug{this, "Uninitialized argument value"};
52 const BugType MsgRetBug{this, "Receiver in message expression is 'nil'"};
53 const BugType CallFewArgsBug{this, "Function call with too few arguments"};
54
55public:
56 // Like a checker family, CallAndMessageChecker can produce many kinds of
57 // warnings which can be separately enabled or disabled. However, for
58 // historical reasons these warning kinds are represented by checker options
59 // (and not separate checker frontends with their own names) because
60 // CallAndMessage is among the oldest checkers out there, and can
61 // be responsible for the majority of the reports on any given project. This
62 // is obviously not ideal, but changing checker name has the consequence of
63 // changing the issue hashes associated with the reports, and databases
64 // relying on this (CodeChecker, for instance) would suffer greatly.
65 // If we ever end up making changes to the issue hash generation algorithm, or
66 // the warning messages here, we should totally jump on the opportunity to
67 // convert these to actual checker frontends.
68 enum CheckKind {
69 CK_FunctionPointer,
70 CK_ParameterCount,
71 CK_CXXThisMethodCall,
72 CK_CXXDeallocationArg,
73 CK_ArgInitializedness,
74 CK_ArgPointeeInitializedness,
75 CK_NilReceiver,
76 CK_UndefReceiver,
77 CK_NumCheckKinds
78 };
79
80 bool ChecksEnabled[CK_NumCheckKinds] = {false};
81
82 /// When checking a struct value for uninitialized data, should all the fields
83 /// be un-initialized or only find one uninitialized field.
84 bool StructInitializednessComplete = true;
85
86 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
87
88 /// Fill in the return value that results from messaging nil based on the
89 /// return type and architecture and diagnose if the return value will be
90 /// garbage.
91 void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;
92
93 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
94
95 ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,
96 CheckerContext &C,
97 ProgramStateRef State) const;
98
99 ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,
100 CheckerContext &C,
101 ProgramStateRef State) const;
102
103 ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,
104 ProgramStateRef State) const;
105
106 ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,
107 CheckerContext &C,
108 ProgramStateRef State) const;
109
110 ProgramStateRef checkArgInitializedness(const CallEvent &Call,
111 CheckerContext &C,
112 ProgramStateRef State) const;
113
114private:
115 bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
116 const Expr *ArgEx, int ArgumentNumber,
117 bool CheckUninitFields, const CallEvent &Call,
118 const BugType &BT,
119 const ParmVarDecl *ParamDecl) const;
120
121 static void emitBadCall(const BugType &BT, CheckerContext &C,
122 const Expr *BadE);
123 void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
124 ExplodedNode *N) const;
125
126 void HandleNilReceiver(CheckerContext &C,
127 ProgramStateRef state,
128 const ObjCMethodCall &msg) const;
129
130 bool uninitRefOrPointer(CheckerContext &C, SVal V, SourceRange ArgRange,
131 const Expr *ArgEx, const BugType &BT,
132 const ParmVarDecl *ParamDecl,
133 int ArgumentNumber) const;
134};
135} // end anonymous namespace
136
137void CallAndMessageChecker::emitBadCall(const BugType &BT, CheckerContext &C,
138 const Expr *BadE) {
139 ExplodedNode *N = C.generateErrorNode();
140 if (!N)
141 return;
142
143 auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
144 if (BadE) {
145 R->addRange(BadE->getSourceRange());
146 if (BadE->isGLValue())
147 BadE = bugreporter::getDerefExpr(BadE);
149 }
150 C.emitReport(std::move(R));
151}
152
154 int ArgumentNumber,
155 llvm::raw_svector_ostream &Os) {
156 switch (Call.getKind()) {
157 case CE_ObjCMessage: {
159 switch (Msg.getMessageKind()) {
160 case OCM_Message:
161 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
162 << " argument in message expression is an uninitialized value";
163 return;
165 assert(Msg.isSetter() && "Getters have no args");
166 Os << "Argument for property setter is an uninitialized value";
167 return;
168 case OCM_Subscript:
169 if (Msg.isSetter() && (ArgumentNumber == 0))
170 Os << "Argument for subscript setter is an uninitialized value";
171 else
172 Os << "Subscript index is an uninitialized value";
173 return;
174 }
175 llvm_unreachable("Unknown message kind.");
176 }
177 case CE_Block:
178 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
179 << " block call argument is an uninitialized value";
180 return;
181 default:
182 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
183 << " function call argument is an uninitialized value";
184 return;
185 }
186}
187
188namespace {
189class FindUninitializedField {
190public:
191 using FieldChainTy = SmallVector<const FieldDecl *, 10>;
192 FieldChainTy FieldChain;
193
194private:
195 StoreManager &StoreMgr;
196 MemRegionManager &MrMgr;
197 Store store;
198 bool FindNotUninitialized;
199
200public:
201 FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
202 Store s, bool FindNotUninitialized = false)
203 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s),
204 FindNotUninitialized(FindNotUninitialized) {}
205
206 bool Find(const TypedValueRegion *R) {
207 QualType T = R->getValueType();
208 if (const RecordType *RT = T->getAsStructureType()) {
209 const RecordDecl *RD = RT->getDecl()->getDefinition();
210 assert(RD && "Referred record has no definition");
211 for (const auto *I : RD->fields()) {
212 if (I->isUnnamedBitField())
213 continue;
214 const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
215 FieldChain.push_back(I);
216 T = I->getType();
217 if (T->isStructureType()) {
218 if (FindNotUninitialized ? !Find(FR) : Find(FR))
219 return !FindNotUninitialized;
220 } else {
221 SVal V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
222 if (FindNotUninitialized ? !V.isUndef() : V.isUndef())
223 return !FindNotUninitialized;
224 }
225 FieldChain.pop_back();
226 }
227 }
228
229 return FindNotUninitialized;
230 }
231};
232} // namespace
233
234namespace llvm {
235template <> struct format_provider<FindUninitializedField::FieldChainTy> {
236 static void format(const FindUninitializedField::FieldChainTy &V,
237 raw_ostream &Stream, StringRef Style) {
238 if (V.size() == 0)
239 return;
240 else if (V.size() == 1)
241 Stream << " (e.g., field: '" << *V[0] << "')";
242 else {
243 Stream << " (e.g., via the field chain: '";
244 interleave(
245 V, Stream, [&Stream](const FieldDecl *FD) { Stream << *FD; }, ".");
246 Stream << "')";
247 }
248 }
249};
250} // namespace llvm
251
252bool CallAndMessageChecker::uninitRefOrPointer(
253 CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
254 const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
255
256 if (!ChecksEnabled[CK_ArgPointeeInitializedness])
257 return false;
258
259 // No parameter declaration available, i.e. variadic function argument.
260 if (!ParamDecl)
261 return false;
262
263 QualType ParamT = ParamDecl->getType();
264 if (!ParamT->isPointerOrReferenceType())
265 return false;
266
267 QualType PointeeT = ParamT->getPointeeType();
268 if (!PointeeT.isConstQualified())
269 return false;
270
271 const MemRegion *SValMemRegion = V.getAsRegion();
272 if (!SValMemRegion)
273 return false;
274
275 // If parameter is declared as pointer to const in function declaration,
276 // then check if corresponding argument in function call is
277 // pointing to undefined symbol value (uninitialized memory).
278
279 const ProgramStateRef State = C.getState();
280 if (PointeeT->isVoidType())
281 PointeeT = C.getASTContext().CharTy;
282 const SVal PointeeV = State->getSVal(SValMemRegion, PointeeT);
283
284 if (PointeeV.isUndef()) {
285 if (ExplodedNode *N = C.generateErrorNode()) {
286 std::string Msg = llvm::formatv(
287 "{0}{1} function call argument is {2} uninitialized value",
288 ArgumentNumber + 1, llvm::getOrdinalSuffix(ArgumentNumber + 1),
289 ParamT->isPointerType() ? "a pointer to" : "an");
290 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
291 R->addRange(ArgRange);
292 if (ArgEx)
294
295 C.emitReport(std::move(R));
296 }
297 return true;
298 }
299
300 if (auto LV = PointeeV.getAs<nonloc::LazyCompoundVal>()) {
301 const LazyCompoundValData *D = LV->getCVData();
302 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
303 C.getSValBuilder().getRegionManager(),
304 D->getStore(), StructInitializednessComplete);
305
306 if (F.Find(D->getRegion())) {
307 if (ExplodedNode *N = C.generateErrorNode()) {
308 std::string Msg = llvm::formatv(
309 "{0}{1} function call argument {2} an uninitialized value{3}",
310 (ArgumentNumber + 1), llvm::getOrdinalSuffix(ArgumentNumber + 1),
311 ParamT->isPointerType() ? "points to" : "references", F.FieldChain);
312 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
313 R->addRange(ArgRange);
314 if (ArgEx)
316
317 C.emitReport(std::move(R));
318 }
319 return true;
320 }
321 }
322
323 return false;
324}
325
326bool CallAndMessageChecker::PreVisitProcessArg(
327 CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
328 int ArgumentNumber, bool CheckUninitFields, const CallEvent &Call,
329 const BugType &BT, const ParmVarDecl *ParamDecl) const {
330 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, ArgumentNumber))
331 return true;
332
333 if (V.isUndef()) {
334 if (!ChecksEnabled[CK_ArgInitializedness]) {
335 C.addSink();
336 return true;
337 }
338 if (ExplodedNode *N = C.generateErrorNode()) {
339 // Generate a report for this bug.
340 SmallString<200> Buf;
341 llvm::raw_svector_ostream Os(Buf);
342 describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
343 auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
344
345 R->addRange(ArgRange);
346 if (ArgEx)
348 C.emitReport(std::move(R));
349 }
350 return true;
351 }
352
353 if (!CheckUninitFields)
354 return false;
355
356 if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
357 const LazyCompoundValData *D = LV->getCVData();
358 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
359 C.getSValBuilder().getRegionManager(),
360 D->getStore());
361
362 if (F.Find(D->getRegion())) {
363 if (!ChecksEnabled[CK_ArgInitializedness]) {
364 C.addSink();
365 return true;
366 }
367 if (ExplodedNode *N = C.generateErrorNode()) {
368 std::string Msg = llvm::formatv(
369 "Passed-by-value struct argument contains uninitialized data{0}",
370 F.FieldChain);
371
372 // Generate a report for this bug.
373 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
374 R->addRange(ArgRange);
375
376 if (ArgEx)
378 // FIXME: enhance track back for uninitialized value for arbitrary
379 // memregions
380 C.emitReport(std::move(R));
381 }
382 return true;
383 }
384 }
385
386 return false;
387}
388
389ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
390 const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
391
392 const Expr *Callee = CE->getCallee()->IgnoreParens();
393 const LocationContext *LCtx = C.getLocationContext();
394 SVal L = State->getSVal(Callee, LCtx);
395
396 if (L.isUndef()) {
397 if (!ChecksEnabled[CK_FunctionPointer]) {
398 C.addSink(State);
399 return nullptr;
400 }
401 emitBadCall(CallUndefBug, C, Callee);
402 return nullptr;
403 }
404
405 ProgramStateRef StNonNull, StNull;
406 std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
407
408 if (StNull && !StNonNull) {
409 if (!ChecksEnabled[CK_FunctionPointer]) {
410 C.addSink(StNull);
411 return nullptr;
412 }
413 emitBadCall(CallNullBug, C, Callee);
414 return nullptr;
415 }
416
417 return StNonNull;
418}
419
420ProgramStateRef CallAndMessageChecker::checkParameterCount(
421 const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
422
423 // If we have a function or block declaration, we can make sure we pass
424 // enough parameters.
425 unsigned Params = Call.parameters().size();
426 if (Call.getNumArgs() >= Params)
427 return State;
428
429 if (!ChecksEnabled[CK_ParameterCount]) {
430 C.addSink(State);
431 return nullptr;
432 }
433
434 ExplodedNode *N = C.generateErrorNode();
435 if (!N)
436 return nullptr;
437
438 SmallString<512> Str;
439 llvm::raw_svector_ostream os(Str);
441 os << "Function ";
442 } else {
443 assert(isa<BlockCall>(Call));
444 os << "Block ";
445 }
446 os << "taking " << Params << " argument" << (Params == 1 ? "" : "s")
447 << " is called with fewer (" << Call.getNumArgs() << ")";
448
449 C.emitReport(
450 std::make_unique<PathSensitiveBugReport>(CallFewArgsBug, os.str(), N));
451 return nullptr;
452}
453
454ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
455 const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {
456
457 SVal V = CC->getCXXThisVal();
458 if (V.isUndef()) {
459 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
460 C.addSink(State);
461 return nullptr;
462 }
463 emitBadCall(CXXCallUndefBug, C, CC->getCXXThisExpr());
464 return nullptr;
465 }
466
467 ProgramStateRef StNonNull, StNull;
468 std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
469
470 if (StNull && !StNonNull) {
471 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
472 C.addSink(StNull);
473 return nullptr;
474 }
475 emitBadCall(CXXCallNullBug, C, CC->getCXXThisExpr());
476 return nullptr;
477 }
478
479 return StNonNull;
480}
481
483CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
484 CheckerContext &C,
485 ProgramStateRef State) const {
486 const CXXDeleteExpr *DE = DC->getOriginExpr();
487 assert(DE);
488 SVal Arg = C.getSVal(DE->getArgument());
489 if (!Arg.isUndef())
490 return State;
491
492 if (!ChecksEnabled[CK_CXXDeallocationArg]) {
493 C.addSink(State);
494 return nullptr;
495 }
496
497 StringRef Desc;
498 ExplodedNode *N = C.generateErrorNode();
499 if (!N)
500 return nullptr;
501 if (DE->isArrayFormAsWritten())
502 Desc = "Argument to 'delete[]' is uninitialized";
503 else
504 Desc = "Argument to 'delete' is uninitialized";
505 auto R = std::make_unique<PathSensitiveBugReport>(CXXDeleteUndefBug, Desc, N);
507 C.emitReport(std::move(R));
508 return nullptr;
509}
510
511ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
512 const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
513
514 const Decl *D = Call.getDecl();
515
516 // Don't check for uninitialized field values in arguments if the
517 // caller has a body that is available and we have the chance to inline it.
518 // This is a hack, but is a reasonable compromise betweens sometimes warning
519 // and sometimes not depending on if we decide to inline a function.
520 const bool checkUninitFields =
521 !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
522
523 const BugType &BT = isa<ObjCMethodCall>(Call) ? MsgArgBug : CallArgBug;
524
525 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
526 for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
527 const ParmVarDecl *ParamDecl = nullptr;
528 if (FD && i < FD->getNumParams())
529 ParamDecl = FD->getParamDecl(i);
530 if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
531 Call.getArgExpr(i), i, checkUninitFields, Call, BT,
532 ParamDecl))
533 return nullptr;
534 }
535 return State;
536}
537
538void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
539 CheckerContext &C) const {
540 ProgramStateRef State = C.getState();
541
542 if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))
543 State = checkFunctionPointerCall(CE, C, State);
544
545 if (!State)
546 return;
547
548 if (Call.getDecl())
549 State = checkParameterCount(Call, C, State);
550
551 if (!State)
552 return;
553
554 if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))
555 State = checkCXXMethodCall(CC, C, State);
556
557 if (!State)
558 return;
559
560 if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))
561 State = checkCXXDeallocation(DC, C, State);
562
563 if (!State)
564 return;
565
566 State = checkArgInitializedness(Call, C, State);
567
568 // If we make it here, record our assumptions about the callee.
569 C.addTransition(State);
570}
571
572void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
573 CheckerContext &C) const {
574 SVal recVal = msg.getReceiverSVal();
575 if (recVal.isUndef()) {
576 if (!ChecksEnabled[CK_UndefReceiver]) {
577 C.addSink();
578 return;
579 }
580 if (ExplodedNode *N = C.generateErrorNode()) {
581 const BugType *BT = nullptr;
582 switch (msg.getMessageKind()) {
583 case OCM_Message:
584 BT = &MsgUndefBug;
585 break;
587 BT = &ObjCPropUndefBug;
588 break;
589 case OCM_Subscript:
590 BT = &ObjCSubscriptUndefBug;
591 break;
592 }
593 assert(BT && "Unknown message kind.");
594
595 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
596 const ObjCMessageExpr *ME = msg.getOriginExpr();
597 R->addRange(ME->getReceiverRange());
598
599 // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
600 if (const Expr *ReceiverE = ME->getInstanceReceiver())
601 bugreporter::trackExpressionValue(N, ReceiverE, *R);
602 C.emitReport(std::move(R));
603 }
604 return;
605 }
606}
607
608void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
609 CheckerContext &C) const {
610 HandleNilReceiver(C, C.getState(), msg);
611}
612
613void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
614 const ObjCMethodCall &msg,
615 ExplodedNode *N) const {
616 if (!ChecksEnabled[CK_NilReceiver]) {
617 C.addSink();
618 return;
619 }
620
621 const ObjCMessageExpr *ME = msg.getOriginExpr();
622
623 QualType ResTy = msg.getResultType();
624
625 SmallString<200> buf;
626 llvm::raw_svector_ostream os(buf);
627 os << "The receiver of message '";
628 ME->getSelector().print(os);
629 os << "' is nil";
630 if (ResTy->isReferenceType()) {
631 os << ", which results in forming a null reference";
632 } else {
633 os << " and returns a value of type '";
634 msg.getResultType().print(os, C.getLangOpts());
635 os << "' that will be garbage";
636 }
637
638 auto report =
639 std::make_unique<PathSensitiveBugReport>(MsgRetBug, os.str(), N);
640 report->addRange(ME->getReceiverRange());
641 // FIXME: This won't track "self" in messages to super.
642 if (const Expr *receiver = ME->getInstanceReceiver()) {
643 bugreporter::trackExpressionValue(N, receiver, *report);
644 }
645 C.emitReport(std::move(report));
646}
647
648static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
649 return (triple.getVendor() == llvm::Triple::Apple &&
650 (triple.isiOS() || triple.isWatchOS() ||
651 !triple.isMacOSXVersionLT(10,5)));
652}
653
654void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
655 ProgramStateRef state,
656 const ObjCMethodCall &Msg) const {
657 ASTContext &Ctx = C.getASTContext();
658
659 // Check the return type of the message expression. A message to nil will
660 // return different values depending on the return type and the architecture.
661 QualType RetTy = Msg.getResultType();
662 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
663 const LocationContext *LCtx = C.getLocationContext();
664
665 if (CanRetTy->isStructureOrClassType()) {
666 // Structure returns are safe since the compiler zeroes them out.
667 SVal V = C.getSValBuilder().makeZeroVal(RetTy);
668 C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
669 return;
670 }
671
672 // Other cases: check if sizeof(return type) > sizeof(void*)
673 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
674 .isConsumedExpr(Msg.getOriginExpr())) {
675 // Compute: sizeof(void *) and sizeof(return type)
676 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
677 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
678
679 if (CanRetTy.getTypePtr()->isReferenceType()||
680 (voidPtrSize < returnTypeSize &&
682 (Ctx.FloatTy == CanRetTy ||
683 Ctx.DoubleTy == CanRetTy ||
684 Ctx.LongDoubleTy == CanRetTy ||
685 Ctx.LongLongTy == CanRetTy ||
686 Ctx.UnsignedLongLongTy == CanRetTy)))) {
687 if (ExplodedNode *N = C.generateErrorNode(state))
688 emitNilReceiverBug(C, Msg, N);
689 return;
690 }
691
692 // Handle the safe cases where the return value is 0 if the
693 // receiver is nil.
694 //
695 // FIXME: For now take the conservative approach that we only
696 // return null values if we *know* that the receiver is nil.
697 // This is because we can have surprises like:
698 //
699 // ... = [[NSScreens screens] objectAtIndex:0];
700 //
701 // What can happen is that [... screens] could return nil, but
702 // it most likely isn't nil. We should assume the semantics
703 // of this case unless we have *a lot* more knowledge.
704 //
705 SVal V = C.getSValBuilder().makeZeroVal(RetTy);
706 C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
707 return;
708 }
709
710 C.addTransition(state);
711}
712
713void ento::registerCallAndMessageChecker(CheckerManager &Mgr) {
714 CallAndMessageChecker *Chk = Mgr.registerChecker<CallAndMessageChecker>();
715
716#define QUERY_CHECKER_OPTION(OPTION) \
717 Chk->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
718 Mgr.getAnalyzerOptions().getCheckerBooleanOption( \
719 Mgr.getCurrentCheckerName(), #OPTION);
720
721 QUERY_CHECKER_OPTION(FunctionPointer)
723 QUERY_CHECKER_OPTION(CXXThisMethodCall)
724 QUERY_CHECKER_OPTION(CXXDeallocationArg)
725 QUERY_CHECKER_OPTION(ArgInitializedness)
726 QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
727 QUERY_CHECKER_OPTION(NilReceiver)
728 QUERY_CHECKER_OPTION(UndefReceiver)
729
730 Chk->StructInitializednessComplete =
731 Mgr.getAnalyzerOptions().getCheckerBooleanOption(
732 Mgr.getCurrentCheckerName(), "ArgPointeeInitializednessComplete");
733}
734
735bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &) {
736 return true;
737}
#define V(N, I)
#define QUERY_CHECKER_OPTION(OPTION)
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
static void describeUninitializedArgumentInCall(const CallEvent &Call, int ArgumentNumber, llvm::raw_svector_ostream &Os)
Defines the clang::Expr interface and subclasses for C++ expressions.
unsigned ParameterCount
Number of parameters, if this is "(", "[" or "<".
__device__ __2f16 float __ockl_bool s
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
CanQualType FloatTy
CanQualType DoubleTy
CanQualType LongDoubleTy
CanQualType VoidPtrTy
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CanQualType VoidTy
CanQualType UnsignedLongLongTy
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:909
CanQualType LongLongTy
bool isArrayFormAsWritten() const
Definition ExprCXX.h:2653
Expr * getCallee()
Definition Expr.h:3024
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
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:1087
This represents one expression.
Definition Expr.h:112
bool isGLValue() const
Definition Expr.h:287
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3085
Represents a member of a struct/union/class.
Definition Decl.h:3160
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2797
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition ExprObjC.h:1265
Selector getSelector() const
Definition ExprObjC.cpp:289
SourceRange getReceiverRange() const
Source range of the receiver.
Definition ExprObjC.cpp:273
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8366
field_range fields() const
Definition Decl.h:4524
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:338
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isStructureType() const
Definition Type.cpp:678
bool isVoidType() const
Definition TypeBase.h:8892
bool isPointerType() const
Definition TypeBase.h:8530
bool isReferenceType() const
Definition TypeBase.h:8554
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
const RecordType * getAsStructureType() const
Definition Type.cpp:768
bool isPointerOrReferenceType() const
Definition TypeBase.h:8534
QualType getType() const
Definition Decl.h:723
StringRef getDescription() const
Definition BugType.h:58
const CXXDeleteExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
Definition CallEvent.h:1229
virtual SVal getCXXThisVal() const
Returns the value of the implicit 'this' object.
virtual const Expr * getCXXThisExpr() const
Returns the expression representing the implicit 'this' object.
Definition CallEvent.h:713
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:153
QualType getResultType() const
Returns the result type, adjusted for references.
Definition CallEvent.cpp:70
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
CheckerNameRef getCurrentCheckerName() const
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:553
const void * getStore() const
It might return null.
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
const FieldRegion * getFieldRegion(const FieldDecl *FD, const SubRegion *SuperRegion)
getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl.
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1261
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
bool isSetter() const
Returns true if this property access or subscript is a setter (has the form of an assignment).
Definition CallEvent.h:1333
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
Definition CallEvent.h:1287
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
bool isUndef() const
Definition SVals.h:107
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition SVals.h:83
virtual SVal getBinding(Store store, Loc loc, QualType T=QualType())=0
Return the value bound to specified location in a given state.
virtual QualType getValueType() const =0
Defines the clang::TargetInfo interface.
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
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.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
Definition StoreRef.h:27
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
Definition Address.h:330
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
unsigned long uint64_t
static void format(const FindUninitializedField::FieldChainTy &V, raw_ostream &Stream, StringRef Style)