clang: lib/StaticAnalyzer/Checkers/MallocChecker.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
84#include "llvm/ADT/STLExtras.h"
85#include "llvm/ADT/SmallVector.h"
86#include "llvm/ADT/StringExtras.h"
87#include "llvm/Support/Casting.h"
88#include "llvm/Support/Compiler.h"
89#include "llvm/Support/ErrorHandling.h"
90#include "llvm/Support/raw_ostream.h"
91#include
92#include
93#include
94
95using namespace clang;
96using namespace ento;
97using namespace std::placeholders;
98
99
100
101
102
103
104
105
106namespace {
107
108
109enum AllocationFamilyKind {
110 AF_None,
111 AF_Malloc,
112 AF_CXXNew,
113 AF_CXXNewArray,
114 AF_IfNameIndex,
115 AF_Alloca,
116 AF_InnerBuffer,
117 AF_Custom,
118};
119
120struct AllocationFamily {
121 AllocationFamilyKind Kind;
122 std::optional CustomName;
123
124 explicit AllocationFamily(AllocationFamilyKind AKind,
125 std::optional Name = std::nullopt)
126 : Kind(AKind), CustomName(Name) {
127 assert((Kind != AF_Custom || CustomName.has_value()) &&
128 "Custom family must specify also the name");
129
130
131 if (Kind == AF_Custom && CustomName.value() == "malloc") {
132 Kind = AF_Malloc;
133 CustomName = std::nullopt;
134 }
135 }
136
138 return std::tie(Kind, CustomName) == std::tie(Other.Kind, Other.CustomName);
139 }
140
142 return !(*this == Other);
143 }
144
145 void Profile(llvm::FoldingSetNodeID &ID) const {
146 ID.AddInteger(Kind);
147
148 if (Kind == AF_Custom)
149 ID.AddString(CustomName.value());
150 }
151};
152
153}
154
155
156
157
159
160
161
163
164
165
167
168
169
170
171
172namespace {
173
174class RefState {
175 enum Kind {
176
177 Allocated,
178
179 AllocatedOfSizeZero,
180
181 Released,
182
183
184 Relinquished,
185
186
187
188 Escaped
189 };
190
191 const Stmt *S;
192
193 Kind K;
194 AllocationFamily Family;
195
196 RefState(Kind k, const Stmt *s, AllocationFamily family)
197 : S(s), K(k), Family(family) {
198 assert(family.Kind != AF_None);
199 }
200
201public:
202 bool isAllocated() const { return K == Allocated; }
203 bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
204 bool isReleased() const { return K == Released; }
205 bool isRelinquished() const { return K == Relinquished; }
206 bool isEscaped() const { return K == Escaped; }
207 AllocationFamily getAllocationFamily() const { return Family; }
208 const Stmt *getStmt() const { return S; }
209
210 bool operator==(const RefState &X) const {
211 return K == X.K && S == X.S && Family == X.Family;
212 }
213
214 static RefState getAllocated(AllocationFamily family, const Stmt *s) {
215 return RefState(Allocated, s, family);
216 }
217 static RefState getAllocatedOfSizeZero(const RefState *RS) {
218 return RefState(AllocatedOfSizeZero, RS->getStmt(),
219 RS->getAllocationFamily());
220 }
221 static RefState getReleased(AllocationFamily family, const Stmt *s) {
222 return RefState(Released, s, family);
223 }
224 static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
225 return RefState(Relinquished, s, family);
226 }
227 static RefState getEscaped(const RefState *RS) {
228 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
229 }
230
231 void Profile(llvm::FoldingSetNodeID &ID) const {
232 ID.AddInteger(K);
233 ID.AddPointer(S);
234 Family.Profile(ID);
235 }
236
237 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
238 switch (K) {
239#define CASE(ID) case ID: OS << #ID; break;
240 CASE(Allocated)
241 CASE(AllocatedOfSizeZero)
242 CASE(Released)
243 CASE(Relinquished)
244 CASE(Escaped)
245 }
246 }
247
248 LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
249};
250
251}
252
254
255
257
258
259
260
263 AllocationFamily Family,
264 std::optional RetVal = std::nullopt);
265
266
267
268
269
270
271
272
274
275namespace {
276
277
278enum OwnershipAfterReallocKind {
279
280 OAR_ToBeFreedAfterFailure,
281
282 OAR_FreeOnFailure,
283
284
285
286
287
288
289
290 OAR_DoNotTrackAfterFailure
291};
292
293
294
295
296
297
298
299struct ReallocPair {
300
301
303 OwnershipAfterReallocKind Kind;
304
305 ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
306 : ReallocatedSym(S), Kind(K) {}
307 void Profile(llvm::FoldingSetNodeID &ID) const {
308 ID.AddInteger(Kind);
309 ID.AddPointer(ReallocatedSym);
310 }
311 bool operator==(const ReallocPair &X) const {
312 return ReallocatedSym == X.ReallocatedSym &&
313 Kind == X.Kind;
314 }
315};
316
317}
318
320
327
334
335
336
340
341namespace {
342
343
344
345
346
347
348#define BUGTYPE_PROVIDER(NAME, DEF) \
349 struct NAME : virtual public CheckerFrontend { \
350 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
351 };
352
354
356
357
358
359
360
362 true};
363};
364
371
372#undef BUGTYPE_PROVIDER
373
374template <typename... BT_PROVIDERS>
375struct DynMemFrontend : virtual public CheckerFrontend, public BT_PROVIDERS... {
376 template const T *getAs() const {
377 if constexpr (std::is_same_v<T, CheckerFrontend> ||
378 (std::is_same_v<T, BT_PROVIDERS> || ...))
379 return static_cast<const T *>(this);
380 return nullptr;
381 }
382};
383
384
385
386
387
388class MallocChecker
390 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
391 check::PreStmt, check::EndFunction, check::PreCall,
392 check::PostCall, eval::Call, check::NewAllocator,
393 check::PostStmt, check::PostObjCMessage, check::Location,
394 eval::Assume> {
395public:
396
397
398
399
400 bool ShouldIncludeOwnershipAnnotatedFunctions = false;
401
402 bool ShouldRegisterNoOwnershipChangeVisitor = false;
403
404
405
406
407
408
409
410
411 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
412 UseZeroAllocated>
413 MallocChecker;
414 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
415 NewDeleteChecker;
416 DynMemFrontend NewDeleteLeaksChecker;
417 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
418 DynMemFrontend InnerPointerChecker;
419
420
421 CheckerFrontendWithBugType TaintedAllocChecker{"Tainted Memory Allocation",
423
424 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
425
426 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
427 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
428 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
429
431 handleSmartPointerConstructorArguments(const CallEvent &Call,
434 CheckerContext &C,
436 void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
437 void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
438 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
439 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
440 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
441 void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;
443 bool Assumption) const;
444 void checkLocation(SVal l, bool isLoad, const Stmt *S,
445 CheckerContext &C) const;
446
449 const CallEvent *Call,
453 const CallEvent *Call,
455
457 const char *NL, const char *Sep) const override;
458
459 StringRef getDebugTag() const override { return "MallocChecker"; }
460
461private:
462#define CHECK_FN(NAME) \
463 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
464 const;
465
473 CHECK_FN(checkIfFreeNameIndex)
474 CHECK_FN(checkCXXNewOrCXXDelete)
479 CHECK_FN(preGetDelimOrGetLine)
480 CHECK_FN(checkGetDelimOrGetLine)
483
486
487 using CheckFn =
490
492
493
494 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
495 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
496 };
497
498 const CallDescriptionMap PostFnMap{
499
500
501 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
502 {{CDM::CLibrary, {"getdelim"}, 4},
503 &MallocChecker::checkGetDelimOrGetLine},
504 };
505
506 const CallDescriptionMap FreeingMemFnMap{
507 {{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},
508 {{CDM::CLibrary, {"if_freenameindex"}, 1},
509 &MallocChecker::checkIfFreeNameIndex},
510 {{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},
511 {{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},
512 };
513
514 bool isFreeingCall(const CallEvent &Call) const;
515 static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);
516 static bool isFreeingOwnershipAttrCall(const CallEvent &Call);
517 static bool isAllocatingOwnershipAttrCall(const FunctionDecl *Func);
518 static bool isAllocatingOwnershipAttrCall(const CallEvent &Call);
519
520 friend class NoMemOwnershipChangeVisitor;
521
522 CallDescriptionMap AllocaMemFnMap{
523 {{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},
524 {{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},
525
526
527
528 {{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},
529 &MallocChecker::checkAlloca},
530 };
531
532 CallDescriptionMap AllocatingMemFnMap{
533 {{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
534 {{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
535 {{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},
536 {{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
537 {{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
538 {{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
539 {{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},
540 {{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
541 {{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
542 {{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
543 {{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
544 {{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
545 {{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
546 {{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
547 {{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
548 {{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
549 {{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
550 {{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
551 {{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
552 {{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
553 };
554
555 CallDescriptionMap ReallocatingMemFnMap{
556 {{CDM::CLibrary, {"realloc"}, 2},
557 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
558 {{CDM::CLibrary, {"reallocf"}, 2},
559 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)},
560 {{CDM::CLibrary, {"g_realloc"}, 2},
561 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
562 {{CDM::CLibrary, {"g_try_realloc"}, 2},
563 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
564 {{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
565 {{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
566 };
567
568 bool isMemCall(const CallEvent &Call) const;
569 bool hasOwnershipReturns(const CallEvent &Call) const;
570 bool hasOwnershipTakesHolds(const CallEvent &Call) const;
571 void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C,
572 llvm::ArrayRef TaintedSyms,
573 AllocationFamily Family) const;
574
575 void checkTaintedness(CheckerContext &C, const CallEvent &Call,
577 AllocationFamily Family) const;
578
579
580 mutable std::optional<uint64_t> KernelZeroFlagVal;
581
582 using KernelZeroSizePtrValueTy = std::optional;
583
584
585
586
587 mutable std::optional KernelZeroSizePtrValue;
588
589
590
592 processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,
593 AllocationFamily Family) const;
594
595
596
597
598
599
600
601
602
604 ProcessZeroAllocCheck(CheckerContext &C, const CallEvent &Call,
606 std::optional RetVal = std::nullopt);
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
625 MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
627
628
629
630
631
632
633
634 [[nodiscard]] ProgramStateRef MallocBindRetVal(CheckerContext &C,
635 const CallEvent &Call,
637 bool isAlloca) const;
638
639
640
641
642
643
644
645
646
647
649 MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
651
652
653
654
655
656
657
658
659
660
661 [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C,
662 const CallEvent &Call, SVal Size,
664 AllocationFamily Family) const;
665
666
667
668 [[nodiscard]] std::optional
669 performKernelMalloc(const CallEvent &Call, CheckerContext &C,
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
690 const CallEvent &Call,
691 const OwnershipAttr *Att,
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
715 unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
716 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
740 FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
741 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
742 AllocationFamily Family, bool ReturnsNullOnFailure = false,
743 std::optional ArgValOpt = {}) const;
744
745
746
747
748
749
750
751
752
753
754
755
756
757
759 ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,
761 bool SuffixWithN = false) const;
762
763
764
765
766
767
768 [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,
769 const Expr *Blocks,
770 const Expr *BlockBytes);
771
772
773
774
775
776
778 const CallEvent &Call,
780
781
782
783 bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,
784 CheckerContext &C) const;
785
786
787 bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
788
789
790
791 void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
792 const Stmt *S) const;
793
794
795
796
797
798
799
800
801
802
803
804 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
806 SymbolRef &EscapingSymbol) const;
807
808
813 bool IsConstPointerEscape) const;
814
815
816 void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
817
818
819
820
821
822
823
824 template
825 const T *getRelevantFrontendAs(AllocationFamily Family) const;
826
827 template
828 const T *getRelevantFrontendAs(CheckerContext &C, SymbolRef Sym) const;
829
830 static bool SummarizeValue(raw_ostream &os, SVal V);
831 static bool SummarizeRegion(ProgramStateRef State, raw_ostream &os,
832 const MemRegion *MR);
833
834 void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,
835 const Expr *DeallocExpr,
836 AllocationFamily Family) const;
837
838 void HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
839 SourceRange Range) const;
840
841 void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range,
842 const Expr *DeallocExpr, const RefState *RS,
843 SymbolRef Sym, bool OwnershipTransferred) const;
844
845 void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
846 const Expr *DeallocExpr, AllocationFamily Family,
847 const Expr *AllocExpr = nullptr) const;
848
849 void HandleUseAfterFree(CheckerContext &C, SourceRange Range,
851
852 void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
854
855 void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
857
858 void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
859 const Expr *FreeExpr,
860 AllocationFamily Family) const;
861
862
863
864 static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
865 CheckerContext &C);
866
867 void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
868
869
870 bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
871 SVal ArgVal) const;
872};
873}
874
875
876
877
878
879namespace {
880class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor {
881protected:
882
883
884
885
886
887
888
889 bool isFreeingCallAsWritten(const CallExpr &Call) const {
890 const auto *MallocChk = static_cast<const MallocChecker *>(&Checker);
891 if (MallocChk->FreeingMemFnMap.lookupAsWritten(Call) ||
892 MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call))
893 return true;
894
895 if (const auto *Func =
896 llvm::dyn_cast_or_null(Call.getCalleeDecl()))
897 return MallocChecker::isFreeingOwnershipAttrCall(Func);
898
899 return false;
900 }
901
902 bool hasResourceStateChanged(ProgramStateRef CallEnterState,
904 return CallEnterState->get(Sym) !=
905 CallExitEndState->get(Sym);
906 }
907
908
909
910
911
912 bool doesFnIntendToHandleOwnership(const Decl *Callee,
913 ASTContext &ACtx) final {
914 const FunctionDecl *FD = dyn_cast(Callee);
915
916
917
918
919
920
921
922 if (!FD || !FD->hasBody())
923 return false;
924 using namespace clang::ast_matchers;
925
929 for (BoundNodes Match : Matches) {
930 if (Match.getNodeAs("delete"))
931 return true;
932
933 if (const auto *Call = Match.getNodeAs("call"))
934 if (isFreeingCallAsWritten(*Call))
935 return true;
936 }
937
938
939
940 return false;
941 }
942
945 N->getLocation(),
946 N->getState()->getStateManager().getContext().getSourceManager());
947 return std::make_shared(
948 L, "Returning without deallocating memory or storing the pointer for "
949 "later deallocation");
950 }
951
952public:
953 NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)
954 : NoOwnershipChangeVisitor(Sym, Checker) {}
955
956 void Profile(llvm::FoldingSetNodeID &ID) const override {
957 static int Tag = 0;
958 ID.AddPointer(&Tag);
959 ID.AddPointer(Sym);
960 }
961};
962
963}
964
965
966
967
968
969namespace {
970
971
972
974protected:
975 enum NotificationMode { Normal, ReallocationFailed };
976
977
979
980
981 NotificationMode Mode;
982
983
985
986
987
988 const StackFrameContext *ReleaseFunctionLC;
989
990 bool IsLeak;
991
992public:
993 MallocBugVisitor(SymbolRef S, bool isLeak = false)
994 : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
995 ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
996
997 static void *getTag() {
998 static int Tag = 0;
999 return &Tag;
1000 }
1001
1002 void Profile(llvm::FoldingSetNodeID &ID) const override {
1003 ID.AddPointer(getTag());
1004 ID.AddPointer(Sym);
1005 }
1006
1007
1008 static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
1009 const Stmt *Stmt) {
1010 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1011 (RSCurr &&
1012 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1013 (!RSPrev ||
1014 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1015 }
1016
1017
1018
1019 static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
1020 const Stmt *Stmt) {
1021 bool IsReleased =
1022 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1023 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1024 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1025 return IsReleased;
1026 }
1027
1028
1029 static inline bool isRelinquished(const RefState *RSCurr,
1030 const RefState *RSPrev, const Stmt *Stmt) {
1031 return (
1032 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1033 (RSCurr && RSCurr->isRelinquished()) &&
1034 (!RSPrev || !RSPrev->isRelinquished()));
1035 }
1036
1037
1038
1039
1040
1041 static inline bool hasReallocFailed(const RefState *RSCurr,
1042 const RefState *RSPrev,
1043 const Stmt *Stmt) {
1044 return ((!isa_and_nonnull(Stmt)) &&
1045 (RSCurr &&
1046 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1047 (RSPrev &&
1048 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1049 }
1050
1052 BugReporterContext &BRC,
1053 PathSensitiveBugReport &BR) override;
1054
1056 const ExplodedNode *EndPathNode,
1057 PathSensitiveBugReport &BR) override {
1058 if (!IsLeak)
1059 return nullptr;
1060
1061 PathDiagnosticLocation L = BR.getLocation();
1062
1063 return std::make_shared(L, BR.getDescription(),
1064 false);
1065 }
1066
1067private:
1068 class StackHintGeneratorForReallocationFailed
1069 : public StackHintGeneratorForSymbol {
1070 public:
1071 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
1072 : StackHintGeneratorForSymbol(S, M) {}
1073
1074 std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {
1075
1076 ++ArgIndex;
1077
1078 SmallString<200> buf;
1079 llvm::raw_svector_ostream os(buf);
1080
1081 os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1082 << " parameter failed";
1083
1084 return std::string(os.str());
1085 }
1086
1087 std::string getMessageForReturn(const CallExpr *CallExpr) override {
1088 return "Reallocation of returned value failed";
1089 }
1090 };
1091};
1092}
1093
1094
1095
1097
1098namespace {
1099class StopTrackingCallback final : public SymbolVisitor {
1101
1102public:
1103 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
1105
1106 bool VisitSymbol(SymbolRef sym) override {
1107 state = state->remove(sym);
1108 return true;
1109 }
1110};
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124class EscapeTrackedCallback final : public SymbolVisitor {
1126
1127 explicit EscapeTrackedCallback(ProgramStateRef S) : State(std::move(S)) {}
1128
1129public:
1130 bool VisitSymbol(SymbolRef Sym) override {
1131 if (const RefState *RS = State->get(Sym)) {
1132 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {
1133 State = State->set(Sym, RefState::getEscaped(RS));
1134 }
1135 }
1136 return true;
1137 }
1138
1139
1141 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1143 if (Roots.empty())
1144 return State;
1145
1146
1147
1148 SmallVector<const MemRegion *, 10> Regions;
1149 EscapeTrackedCallback Visitor(State);
1150 for (const MemRegion *R : Roots) {
1151 Regions.push_back(R);
1152 }
1153 State->scanReachableSymbols(Regions, Visitor);
1154 return Visitor.State;
1155 }
1156
1157 friend class SymbolVisitor;
1158};
1159}
1160
1162 if (!FD)
1163 return false;
1164
1166 if (Kind != OO_New && Kind != OO_Array_New)
1167 return false;
1168
1169
1171
1172
1175}
1176
1178 if (!FD)
1179 return false;
1180
1182 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1183 return false;
1184
1185 bool HasBody = FD->hasBody();
1186
1187
1189
1190
1191
1193 return L.isInvalid() || (!HasBody && SM.isInSystemHeader(L));
1194}
1195
1196
1197
1198
1199
1200bool MallocChecker::isFreeingOwnershipAttrCall(const CallEvent &Call) {
1201 const auto *Func = dyn_cast_or_null(Call.getDecl());
1202
1203 return Func && isFreeingOwnershipAttrCall(Func);
1204}
1205
1206bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {
1207 if (Func->hasAttrs()) {
1208 for (const auto *I : Func->specific_attrs()) {
1209 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1210 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1211 return true;
1212 }
1213 }
1214 return false;
1215}
1216
1217bool MallocChecker::isFreeingCall(const CallEvent &Call) const {
1218 if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1219 return true;
1220
1221 return isFreeingOwnershipAttrCall(Call);
1222}
1223
1224bool MallocChecker::isAllocatingOwnershipAttrCall(const CallEvent &Call) {
1225 const auto *Func = dyn_cast_or_null(Call.getDecl());
1226
1227 return Func && isAllocatingOwnershipAttrCall(Func);
1228}
1229
1230bool MallocChecker::isAllocatingOwnershipAttrCall(const FunctionDecl *Func) {
1231 for (const auto *I : Func->specific_attrs()) {
1232 if (I->getOwnKind() == OwnershipAttr::Returns)
1233 return true;
1234 }
1235
1236 return false;
1237}
1238
1239bool MallocChecker::isMemCall(const CallEvent &Call) const {
1240 if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
1241 AllocaMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1242 return true;
1243
1244 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1245 return false;
1246
1247 const auto *Func = dyn_cast(Call.getDecl());
1248 return Func && Func->hasAttr();
1249}
1250
1251std::optional
1252MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270 ASTContext &Ctx = C.getASTContext();
1272
1273 if (!KernelZeroFlagVal) {
1274 switch (OS) {
1275 case llvm::Triple::FreeBSD:
1276 KernelZeroFlagVal = 0x0100;
1277 break;
1278 case llvm::Triple::NetBSD:
1279 KernelZeroFlagVal = 0x0002;
1280 break;
1281 case llvm::Triple::OpenBSD:
1282 KernelZeroFlagVal = 0x0008;
1283 break;
1284 case llvm::Triple::Linux:
1285
1286 KernelZeroFlagVal = 0x8000;
1287 break;
1288 default:
1289
1290
1291
1292
1293
1294 return std::nullopt;
1295 }
1296 }
1297
1298
1299
1300
1301 if (Call.getNumArgs() < 2)
1302 return std::nullopt;
1303
1304 const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
1305 const SVal V = C.getSVal(FlagsEx);
1307
1308
1309 return std::nullopt;
1310 }
1311
1312 NonLoc Flags = V.castAs();
1313 NonLoc ZeroFlag = C.getSValBuilder()
1314 .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
1315 .castAs();
1316 SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
1317 Flags, ZeroFlag,
1319 if (MaskedFlagsUC.isUnknownOrUndef())
1320 return std::nullopt;
1321 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs();
1322
1323
1325 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1326
1327
1328 if (TrueState && !FalseState) {
1329 SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
1330 return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,
1331 AllocationFamily(AF_Malloc));
1332 }
1333
1334 return std::nullopt;
1335}
1336
1337SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
1338 const Expr *BlockBytes) {
1339 SValBuilder &SB = C.getSValBuilder();
1340 SVal BlocksVal = C.getSVal(Blocks);
1341 SVal BlockBytesVal = C.getSVal(BlockBytes);
1343 SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1345 return TotalSize;
1346}
1347
1348void MallocChecker::checkBasicAlloc(ProgramStateRef State,
1349 const CallEvent &Call,
1350 CheckerContext &C) const {
1351 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1352 AllocationFamily(AF_Malloc));
1353 State = ProcessZeroAllocCheck(C, Call, 0, State);
1354 C.addTransition(State);
1355}
1356
1357void MallocChecker::checkKernelMalloc(ProgramStateRef State,
1358 const CallEvent &Call,
1359 CheckerContext &C) const {
1360 std::optional MaybeState =
1361 performKernelMalloc(Call, C, State);
1362 if (MaybeState)
1363 State = *MaybeState;
1364 else
1365 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1366 AllocationFamily(AF_Malloc));
1367 C.addTransition(State);
1368}
1369
1371 const FunctionDecl *FD = dyn_cast(Call.getDecl());
1372 assert(FD);
1377}
1378
1380 const FunctionDecl *FD = dyn_cast(Call.getDecl());
1381 assert(FD);
1383
1387}
1388
1389void MallocChecker::checkRealloc(ProgramStateRef State, const CallEvent &Call,
1390 CheckerContext &C,
1391 bool ShouldFreeOnFail) const {
1392
1393
1394
1395
1396
1398 return;
1399
1400 State = ReallocMemAux(C, Call, ShouldFreeOnFail, State,
1401 AllocationFamily(AF_Malloc));
1402 State = ProcessZeroAllocCheck(C, Call, 1, State);
1403 C.addTransition(State);
1404}
1405
1406void MallocChecker::checkCalloc(ProgramStateRef State, const CallEvent &Call,
1407 CheckerContext &C) const {
1408 State = CallocMem(C, Call, State);
1409 State = ProcessZeroAllocCheck(C, Call, 0, State);
1410 State = ProcessZeroAllocCheck(C, Call, 1, State);
1411 C.addTransition(State);
1412}
1413
1414void MallocChecker::checkFree(ProgramStateRef State, const CallEvent &Call,
1415 CheckerContext &C) const {
1416 bool IsKnownToBeAllocatedMemory = false;
1417 if (suppressDeallocationsInSuspiciousContexts(Call, C))
1418 return;
1419 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1420 AllocationFamily(AF_Malloc));
1421 C.addTransition(State);
1422}
1423
1424void MallocChecker::checkAlloca(ProgramStateRef State, const CallEvent &Call,
1425 CheckerContext &C) const {
1426 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1427 AllocationFamily(AF_Alloca));
1428 State = ProcessZeroAllocCheck(C, Call, 0, State);
1429 C.addTransition(State);
1430}
1431
1432void MallocChecker::checkStrdup(ProgramStateRef State, const CallEvent &Call,
1433 CheckerContext &C) const {
1434 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
1435 if (!CE)
1436 return;
1437 State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,
1438 AllocationFamily(AF_Malloc));
1439
1440 C.addTransition(State);
1441}
1442
1443void MallocChecker::checkIfNameIndex(ProgramStateRef State,
1444 const CallEvent &Call,
1445 CheckerContext &C) const {
1446
1447
1448 State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,
1449 AllocationFamily(AF_IfNameIndex));
1450
1451 C.addTransition(State);
1452}
1453
1454void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,
1455 const CallEvent &Call,
1456 CheckerContext &C) const {
1457 bool IsKnownToBeAllocatedMemory = false;
1458 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1459 AllocationFamily(AF_IfNameIndex));
1460 C.addTransition(State);
1461}
1462
1465
1466
1467
1470 return nullptr;
1472 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1473 return nullptr;
1474 return CE->getArg(1);
1475}
1476
1477void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
1478 const CallEvent &Call,
1479 CheckerContext &C) const {
1480 bool IsKnownToBeAllocatedMemory = false;
1481 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
1482 if (!CE)
1483 return;
1484
1486
1487
1488
1489
1490
1491 const FunctionDecl *FD = C.getCalleeDecl(CE);
1493
1494 auto RetVal = State->getSVal(BufArg, Call.getLocationContext());
1495 State = State->BindExpr(CE, C.getLocationContext(), RetVal);
1496 C.addTransition(State);
1497 return;
1498 }
1499
1501 case OO_New:
1502 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1503 AllocationFamily(AF_CXXNew));
1504 State = ProcessZeroAllocCheck(C, Call, 0, State);
1505 break;
1506 case OO_Array_New:
1507 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1508 AllocationFamily(AF_CXXNewArray));
1509 State = ProcessZeroAllocCheck(C, Call, 0, State);
1510 break;
1511 case OO_Delete:
1512 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1513 AllocationFamily(AF_CXXNew));
1514 break;
1515 case OO_Array_Delete:
1516 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1517 AllocationFamily(AF_CXXNewArray));
1518 break;
1519 default:
1520 assert(false && "not a new/delete operator");
1521 return;
1522 }
1523
1524 C.addTransition(State);
1525}
1526
1527void MallocChecker::checkGMalloc0(ProgramStateRef State, const CallEvent &Call,
1528 CheckerContext &C) const {
1529 SValBuilder &svalBuilder = C.getSValBuilder();
1531 State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State,
1532 AllocationFamily(AF_Malloc));
1533 State = ProcessZeroAllocCheck(C, Call, 0, State);
1534 C.addTransition(State);
1535}
1536
1537void MallocChecker::checkGMemdup(ProgramStateRef State, const CallEvent &Call,
1538 CheckerContext &C) const {
1539 State = MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State,
1540 AllocationFamily(AF_Malloc));
1541 State = ProcessZeroAllocCheck(C, Call, 1, State);
1542 C.addTransition(State);
1543}
1544
1545void MallocChecker::checkGMallocN(ProgramStateRef State, const CallEvent &Call,
1546 CheckerContext &C) const {
1547 SVal Init = UndefinedVal();
1548 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1549 State = MallocMemAux(C, Call, TotalSize, Init, State,
1550 AllocationFamily(AF_Malloc));
1551 State = ProcessZeroAllocCheck(C, Call, 0, State);
1552 State = ProcessZeroAllocCheck(C, Call, 1, State);
1553 C.addTransition(State);
1554}
1555
1556void MallocChecker::checkGMallocN0(ProgramStateRef State, const CallEvent &Call,
1557 CheckerContext &C) const {
1558 SValBuilder &SB = C.getSValBuilder();
1560 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1561 State = MallocMemAux(C, Call, TotalSize, Init, State,
1562 AllocationFamily(AF_Malloc));
1563 State = ProcessZeroAllocCheck(C, Call, 0, State);
1564 State = ProcessZeroAllocCheck(C, Call, 1, State);
1565 C.addTransition(State);
1566}
1567
1569 const Decl *FD = Call.getDecl();
1570 assert(FD && "a CallDescription cannot match a call without a Decl");
1572}
1573
1574void MallocChecker::preGetDelimOrGetLine(ProgramStateRef State,
1575 const CallEvent &Call,
1576 CheckerContext &C) const {
1577
1578
1580 return;
1581
1583 if (!LinePtr)
1584 return;
1585
1586
1587
1588
1589
1590 bool IsKnownToBeAllocated = false;
1591 State = FreeMemAux(C, Call.getArgExpr(0), Call, State, false,
1592 IsKnownToBeAllocated, AllocationFamily(AF_Malloc), false,
1593 LinePtr);
1594 if (State)
1595 C.addTransition(State);
1596}
1597
1598void MallocChecker::checkGetDelimOrGetLine(ProgramStateRef State,
1599 const CallEvent &Call,
1600 CheckerContext &C) const {
1601
1602
1604 return;
1605
1606
1607
1608 const CallExpr *CE = dyn_cast_or_null(Call.getOriginExpr());
1609 if (!CE)
1610 return;
1611
1612 const auto LinePtrOpt = getPointeeVal(Call.getArgSVal(0), State);
1614 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1615 SizeOpt->isUnknownOrUndef())
1616 return;
1617
1618 const auto LinePtr = LinePtrOpt->getAs();
1619 const auto Size = SizeOpt->getAs();
1620 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1621 if (!LinePtrReg)
1622 return;
1623
1626 AllocationFamily(AF_Malloc), *LinePtr));
1627}
1628
1629void MallocChecker::checkReallocN(ProgramStateRef State, const CallEvent &Call,
1630 CheckerContext &C) const {
1631 State = ReallocMemAux(C, Call, false, State,
1632 AllocationFamily(AF_Malloc),
1633 true);
1634 State = ProcessZeroAllocCheck(C, Call, 1, State);
1635 State = ProcessZeroAllocCheck(C, Call, 2, State);
1636 C.addTransition(State);
1637}
1638
1639void MallocChecker::checkOwnershipAttr(ProgramStateRef State,
1640 const CallEvent &Call,
1641 CheckerContext &C) const {
1642 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
1643 if (!CE)
1644 return;
1645 const FunctionDecl *FD = C.getCalleeDecl(CE);
1646 if (!FD)
1647 return;
1648 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1649 MismatchedDeallocatorChecker.isEnabled()) {
1650
1651
1653 for (const auto *I : FD->specific_attrs()) {
1654 switch (I->getOwnKind()) {
1655 case OwnershipAttr::Returns:
1656 State = MallocMemReturnsAttr(C, Call, I, State);
1657 break;
1658 case OwnershipAttr::Takes:
1659 case OwnershipAttr::Holds:
1660 State = FreeMemAttr(C, Call, I, State);
1661 break;
1662 }
1663 }
1664 }
1665 C.addTransition(State);
1666}
1667
1668bool MallocChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
1669 if (.getOriginExpr())
1670 return false;
1671
1673
1674 if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
1675 (*Callback)(this, State, Call, C);
1676 return true;
1677 }
1678
1679 if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
1680 State = MallocBindRetVal(C, Call, State, false);
1681 (*Callback)(this, State, Call, C);
1682 return true;
1683 }
1684
1685 if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
1686 State = MallocBindRetVal(C, Call, State, false);
1687 (*Callback)(this, State, Call, C);
1688 return true;
1689 }
1690
1692 State = MallocBindRetVal(C, Call, State, false);
1693 checkCXXNewOrCXXDelete(State, Call, C);
1694 return true;
1695 }
1696
1698 checkCXXNewOrCXXDelete(State, Call, C);
1699 return true;
1700 }
1701
1702 if (const CheckFn *Callback = AllocaMemFnMap.lookup(Call)) {
1703 State = MallocBindRetVal(C, Call, State, true);
1704 (*Callback)(this, State, Call, C);
1705 return true;
1706 }
1707
1708 if (isFreeingOwnershipAttrCall(Call)) {
1709 checkOwnershipAttr(State, Call, C);
1710 return true;
1711 }
1712
1713 if (isAllocatingOwnershipAttrCall(Call)) {
1714 State = MallocBindRetVal(C, Call, State, false);
1715 checkOwnershipAttr(State, Call, C);
1716 return true;
1717 }
1718
1719 return false;
1720}
1721
1722
1724 CheckerContext &C, const CallEvent &Call, const unsigned IndexOfSizeArg,
1726 if (!State)
1727 return nullptr;
1728
1729 const Expr *Arg = nullptr;
1730
1731 if (const CallExpr *CE = dyn_cast(Call.getOriginExpr())) {
1732 Arg = CE->getArg(IndexOfSizeArg);
1733 } else if (const CXXNewExpr *NE =
1734 dyn_cast(Call.getOriginExpr())) {
1735 if (NE->isArray()) {
1736 Arg = *NE->getArraySize();
1737 } else {
1738 return State;
1739 }
1740 } else {
1741 assert(false && "not a CallExpr or CXXNewExpr");
1742 return nullptr;
1743 }
1744
1745 if (!RetVal)
1746 RetVal = State->getSVal(Call.getOriginExpr(), C.getLocationContext());
1747
1748 assert(Arg);
1749
1750 auto DefArgVal =
1751 State->getSVal(Arg, Call.getLocationContext()).getAs();
1752
1753 if (!DefArgVal)
1754 return State;
1755
1756
1758 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1759 DefinedSVal Zero =
1761
1762 std::tie(TrueState, FalseState) =
1763 State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
1764
1765 if (TrueState && !FalseState) {
1766 SymbolRef Sym = RetVal->getAsLocSymbol();
1767 if (!Sym)
1768 return State;
1769
1770 const RefState *RS = State->get(Sym);
1771 if (RS) {
1772 if (RS->isAllocated())
1773 return TrueState->set(
1774 Sym, RefState::getAllocatedOfSizeZero(RS));
1775 return State;
1776 }
1777
1778
1779
1780
1781 return TrueState->add(Sym);
1782 }
1783
1784
1785 assert(FalseState);
1786 return FalseState;
1787}
1788
1790 QualType Result = T, PointeeType = T->getPointeeType();
1791 while (!PointeeType.isNull()) {
1792 Result = PointeeType;
1793 PointeeType = PointeeType->getPointeeType();
1794 }
1795 return Result;
1796}
1797
1798
1799
1801
1802 const CXXConstructExpr *ConstructE = NE->getConstructExpr();
1803 if (!ConstructE)
1804 return false;
1805
1806 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1807 return false;
1808
1810
1811
1812 for (const auto *CtorParam : CtorD->parameters()) {
1813
1815 if (CtorParamPointeeT.isNull())
1816 continue;
1817
1819
1821 return true;
1822 }
1823
1824 return false;
1825}
1826
1828MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
1829 CheckerContext &C,
1830 AllocationFamily Family) const {
1832 return nullptr;
1833
1834 const CXXNewExpr *NE = Call.getOriginExpr();
1835 const ParentMap &PM = C.getLocationContext()->getParentMap();
1837
1838
1839
1840
1841
1843 return State;
1844
1845
1846
1847
1848
1849 SVal Target = Call.getObjectUnderConstruction();
1850 if (Call.getOriginExpr()->isArray()) {
1851 if (auto SizeEx = NE->getArraySize())
1852 checkTaintedness(C, Call, C.getSVal(*SizeEx), State,
1853 AllocationFamily(AF_CXXNewArray));
1854 }
1855
1857 State = ProcessZeroAllocCheck(C, Call, 0, State, Target);
1858 return State;
1859}
1860
1861void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
1862 CheckerContext &C) const {
1863 if (.wasInlined) {
1866 AllocationFamily(Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1867 : AF_CXXNew));
1868 C.addTransition(State);
1869 }
1870}
1871
1873
1874
1875
1876
1877
1878 StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
1879 return FirstSlot == "dataWithBytesNoCopy" ||
1880 FirstSlot == "initWithBytesNoCopy" ||
1881 FirstSlot == "initWithCharactersNoCopy";
1882}
1883
1886
1887
1888 for (unsigned i = 1; i < S.getNumArgs(); ++i)
1890 return .getArgSVal(i).isZeroConstant();
1891
1892 return std::nullopt;
1893}
1894
1895void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
1896 CheckerContext &C) const {
1897 if (C.wasInlined)
1898 return;
1899
1901 return;
1902
1904 if (!*FreeWhenDone)
1905 return;
1906
1907 if (Call.hasNonZeroCallbackArg())
1908 return;
1909
1910 bool IsKnownToBeAllocatedMemory;
1912 true, IsKnownToBeAllocatedMemory,
1913 AllocationFamily(AF_Malloc),
1914 true);
1915
1916 C.addTransition(State);
1917}
1918
1920MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
1921 const OwnershipAttr *Att,
1923 if (!State)
1924 return nullptr;
1925
1926 auto attrClassName = Att->getModule()->getName();
1927 auto Family = AllocationFamily(AF_Custom, attrClassName);
1928
1929 if (!Att->args().empty()) {
1930 return MallocMemAux(C, Call,
1931 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1932 UnknownVal(), State, Family);
1933 }
1934 return MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, Family);
1935}
1936
1937ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
1938 const CallEvent &Call,
1940 bool isAlloca) const {
1941 const Expr *CE = Call.getOriginExpr();
1942
1943
1945 return nullptr;
1946
1947 unsigned Count = C.blockCount();
1948 SValBuilder &SVB = C.getSValBuilder();
1949 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1950 DefinedSVal RetVal =
1954 return State->BindExpr(CE, C.getLocationContext(), RetVal);
1955}
1956
1957ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
1958 const CallEvent &Call,
1959 const Expr *SizeEx, SVal Init,
1961 AllocationFamily Family) const {
1962 if (!State)
1963 return nullptr;
1964
1965 assert(SizeEx);
1966 return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);
1967}
1968
1969void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,
1970 CheckerContext &C,
1971 llvm::ArrayRef TaintedSyms,
1972 AllocationFamily Family) const {
1973 if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) {
1974 auto R =
1975 std::make_unique(TaintedAllocChecker, Msg, N);
1976 for (const auto *TaintedSym : TaintedSyms) {
1977 R->markInteresting(TaintedSym);
1978 }
1979 C.emitReport(std::move(R));
1980 }
1981}
1982
1983void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call,
1985 AllocationFamily Family) const {
1986 if (!TaintedAllocChecker.isEnabled())
1987 return;
1988 std::vector TaintedSyms =
1990 if (TaintedSyms.empty())
1991 return;
1992
1993 SValBuilder &SVB = C.getSValBuilder();
1996
1997
1999 const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy);
2000 NonLoc MaxLength =
2001 SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
2002 std::optional SizeNL = SizeSVal.getAs();
2003 auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2004 .getAs();
2005 if (!Cmp)
2006 return;
2007 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
2008 if (!StateTooLarge && StateNotTooLarge) {
2009
2010 return;
2011 }
2012
2013 std::string Callee = "Memory allocation function";
2014 if (Call.getCalleeIdentifier())
2015 Callee = Call.getCalleeIdentifier()->getName().str();
2016 reportTaintBug(
2017 Callee + " is called with a tainted (potentially attacker controlled) "
2018 "value. Make sure the value is bound checked.",
2019 State, C, TaintedSyms, Family);
2020}
2021
2022ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
2023 const CallEvent &Call, SVal Size,
2025 AllocationFamily Family) const {
2026 if (!State)
2027 return nullptr;
2028
2029 const Expr *CE = Call.getOriginExpr();
2030
2031
2032
2034 "Allocation functions must return a pointer");
2035
2036 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
2037 SVal RetVal = State->getSVal(CE, C.getLocationContext());
2038
2039
2040 State = State->bindDefaultInitial(RetVal, Init, LCtx);
2041
2042
2043 if (Size.isUndef())
2044 Size = UnknownVal();
2045
2046 checkTaintedness(C, Call, Size, State, AllocationFamily(AF_Malloc));
2047
2048
2050 Size.castAs());
2051
2053}
2054
2057 AllocationFamily Family,
2058 std::optional RetVal) {
2059 if (!State)
2060 return nullptr;
2061
2062
2063 if (!RetVal)
2064 RetVal = State->getSVal(E, C.getLocationContext());
2065
2066
2067 if (!RetVal->getAs<Loc>())
2068 return nullptr;
2069
2070 SymbolRef Sym = RetVal->getAsLocSymbol();
2071
2072
2073
2074
2075
2076
2077 if (Sym)
2078 return State->set(Sym, RefState::getAllocated(Family, E));
2079
2080 return State;
2081}
2082
2083ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
2084 const CallEvent &Call,
2085 const OwnershipAttr *Att,
2087 if (!State)
2088 return nullptr;
2089
2090 auto attrClassName = Att->getModule()->getName();
2091 auto Family = AllocationFamily(AF_Custom, attrClassName);
2092
2093 bool IsKnownToBeAllocated = false;
2094
2095 for (const auto &Arg : Att->args()) {
2097 FreeMemAux(C, Call, State, Arg.getASTIndex(),
2098 Att->getOwnKind() == OwnershipAttr::Holds,
2099 IsKnownToBeAllocated, Family);
2100 if (StateI)
2101 State = StateI;
2102 }
2103 return State;
2104}
2105
2107 const CallEvent &Call,
2109 bool Hold, bool &IsKnownToBeAllocated,
2110 AllocationFamily Family,
2111 bool ReturnsNullOnFailure) const {
2112 if (!State)
2113 return nullptr;
2114
2115 if (Call.getNumArgs() < (Num + 1))
2116 return nullptr;
2117
2118 return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,
2119 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2120}
2121
2122
2123
2126 const SymbolRef *Ret = State->get(Sym);
2127 if (Ret) {
2128 assert(*Ret && "We should not store the null return symbol");
2131 RetStatusSymbol = *Ret;
2133 }
2134 return false;
2135}
2136
2138 const Expr *E) {
2139 const CallExpr *CE = dyn_cast(E);
2140
2141 if (!CE)
2142 return;
2143
2145 if (!FD)
2146 return;
2147
2148
2149 for (const auto *I : FD->specific_attrs()) {
2150 if (I->getOwnKind() != OwnershipAttr::Takes)
2151 continue;
2152
2153 os << ", which takes ownership of '" << I->getModule()->getName() << '\'';
2154 break;
2155 }
2156}
2157
2159 if (const CallExpr *CE = dyn_cast(E)) {
2160
2161 const FunctionDecl *FD = CE->getDirectCallee();
2162 if (!FD)
2163 return false;
2164
2165 os << '\'' << *FD;
2166
2168 os << "()";
2169
2170 os << '\'';
2171 return true;
2172 }
2173
2174 if (const ObjCMessageExpr *Msg = dyn_cast(E)) {
2175 if (Msg->isInstanceMessage())
2176 os << "-";
2177 else
2178 os << "+";
2179 Msg->getSelector().print(os);
2180 return true;
2181 }
2182
2183 if (const CXXNewExpr *NE = dyn_cast(E)) {
2184 os << "'"
2186 << "'";
2187 return true;
2188 }
2189
2190 if (const CXXDeleteExpr *DE = dyn_cast(E)) {
2191 os << "'"
2192 << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
2193 << "'";
2194 return true;
2195 }
2196
2197 return false;
2198}
2199
2201
2202 switch (Family.Kind) {
2203 case AF_Malloc:
2204 os << "'malloc()'";
2205 return;
2206 case AF_CXXNew:
2207 os << "'new'";
2208 return;
2209 case AF_CXXNewArray:
2210 os << "'new[]'";
2211 return;
2212 case AF_IfNameIndex:
2213 os << "'if_nameindex()'";
2214 return;
2215 case AF_InnerBuffer:
2216 os << "container-specific allocator";
2217 return;
2218 case AF_Custom:
2219 os << Family.CustomName.value();
2220 return;
2221 case AF_Alloca:
2222 case AF_None:
2223 assert(false && "not a deallocation expression");
2224 }
2225}
2226
2228 switch (Family.Kind) {
2229 case AF_Malloc:
2230 os << "'free()'";
2231 return;
2232 case AF_CXXNew:
2233 os << "'delete'";
2234 return;
2235 case AF_CXXNewArray:
2236 os << "'delete[]'";
2237 return;
2238 case AF_IfNameIndex:
2239 os << "'if_freenameindex()'";
2240 return;
2241 case AF_InnerBuffer:
2242 os << "container-specific deallocator";
2243 return;
2244 case AF_Custom:
2245 os << "function that takes ownership of '" << Family.CustomName.value()
2246 << "\'";
2247 return;
2248 case AF_Alloca:
2249 case AF_None:
2250 assert(false && "not a deallocation expression");
2251 }
2252}
2253
2255MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
2257 bool Hold, bool &IsKnownToBeAllocated,
2258 AllocationFamily Family, bool ReturnsNullOnFailure,
2259 std::optional ArgValOpt) const {
2260
2261 if (!State)
2262 return nullptr;
2263
2264 SVal ArgVal = ArgValOpt.value_or(C.getSVal(ArgExpr));
2266 return nullptr;
2267 DefinedOrUnknownSVal location = ArgVal.castAs();
2268
2269
2271 return nullptr;
2272
2273
2275 std::tie(notNullState, nullState) = State->assume(location);
2276 if (nullState && !notNullState)
2277 return nullptr;
2278
2279
2280
2282 return nullptr;
2283
2284 const MemRegion *R = ArgVal.getAsRegion();
2285 const Expr *ParentExpr = Call.getOriginExpr();
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298 if (!R) {
2299
2300
2301
2302
2303
2304 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))
2305 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2306 Family);
2307 return nullptr;
2308 }
2309
2311
2312
2314 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2315 Family);
2316 return nullptr;
2317 }
2318
2319
2320
2321 if (!R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2322
2323
2324
2325
2326
2329 else
2330 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2331 Family);
2332
2333 return nullptr;
2334 }
2335
2336 const SymbolicRegion *SrBase = dyn_cast(R->getBaseRegion());
2337
2338
2339 if (!SrBase)
2340 return nullptr;
2341
2343 const RefState *RsBase = State->get(SymBase);
2344 SymbolRef PreviousRetStatusSymbol = nullptr;
2345
2346 IsKnownToBeAllocated =
2347 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2348
2349 if (RsBase) {
2350
2351
2352 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2354 return nullptr;
2355 }
2356
2357
2358 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2360 HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
2361 SymBase, PreviousRetStatusSymbol);
2362 return nullptr;
2363 }
2364
2365
2366
2367 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2368 RsBase->isEscaped()) {
2369
2370
2371 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2372 if (!DeallocMatchesAlloc) {
2373 HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,
2374 RsBase, SymBase, Hold);
2375 return nullptr;
2376 }
2377
2378
2379
2384 const Expr *AllocExpr = cast(RsBase->getStmt());
2385 HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2386 Family, AllocExpr);
2387 return nullptr;
2388 }
2389 }
2390 }
2391
2393 HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2394 Family);
2395 return nullptr;
2396 }
2397
2398
2399 State = State->remove(SymBase);
2400
2401
2402
2403 if (ReturnsNullOnFailure) {
2404 SVal RetVal = C.getSVal(ParentExpr);
2406 if (RetStatusSymbol) {
2407 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2408 State = State->set(SymBase, RetStatusSymbol);
2409 }
2410 }
2411
2412
2413
2414
2415
2416 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2417
2418
2419
2420
2421 State = State->invalidateRegions({location}, Call.getCFGElementRef(),
2422 C.blockCount(), C.getLocationContext(),
2423 false,
2424 nullptr);
2425
2426
2427 if (Hold)
2428 return State->set(SymBase,
2429 RefState::getRelinquished(Family,
2430 ParentExpr));
2431
2432 return State->set(SymBase,
2433 RefState::getReleased(Family, ParentExpr));
2434}
2435
2436template
2437const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family) const {
2438 switch (Family.Kind) {
2439 case AF_Malloc:
2440 case AF_Alloca:
2441 case AF_Custom:
2442 case AF_IfNameIndex:
2443 return MallocChecker.getAs<T>();
2444 case AF_CXXNew:
2445 case AF_CXXNewArray: {
2446 const T *ND = NewDeleteChecker.getAs<T>();
2447 const T *NDL = NewDeleteLeaksChecker.getAs<T>();
2448
2449
2450 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2451 assert(ND && NDL && "Casting to CheckerFrontend always succeeds");
2452
2453 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2454 }
2455 assert(!(ND && NDL) &&
2456 "NewDelete and NewDeleteLeaks must not share a bug type");
2457 return ND ? ND : NDL;
2458 }
2459 case AF_InnerBuffer:
2460 return InnerPointerChecker.getAs<T>();
2461 case AF_None:
2462 assert(false && "no family");
2463 return nullptr;
2464 }
2465 assert(false && "unhandled family");
2466 return nullptr;
2467}
2468template
2469const T *MallocChecker::getRelevantFrontendAs(CheckerContext &C,
2471 if (C.getState()->contains(Sym))
2472 return MallocChecker.getAs<T>();
2473
2474 const RefState *RS = C.getState()->get(Sym);
2475 assert(RS);
2476 return getRelevantFrontendAs(RS->getAllocationFamily());
2477}
2478
2479bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
2480 if (std::optionalnonloc::ConcreteInt IntVal =
2481 V.getAsnonloc::ConcreteInt())
2482 os << "an integer (" << IntVal->getValue() << ")";
2483 else if (std::optionalloc::ConcreteInt ConstAddr =
2484 V.getAsloc::ConcreteInt())
2485 os << "a constant address (" << ConstAddr->getValue() << ")";
2486 else if (std::optionalloc::GotoLabel Label = V.getAsloc::GotoLabel())
2487 os << "the address of the label '" << Label->getLabel()->getName() << "'";
2488 else
2489 return false;
2490
2491 return true;
2492}
2493
2494bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
2495 const MemRegion *MR) {
2496 switch (MR->getKind()) {
2497 case MemRegion::FunctionCodeRegionKind: {
2499 if (FD)
2500 os << "the address of the function '" << *FD << '\'';
2501 else
2502 os << "the address of a function";
2503 return true;
2504 }
2505 case MemRegion::BlockCodeRegionKind:
2506 os << "block text";
2507 return true;
2508 case MemRegion::BlockDataRegionKind:
2509
2510 os << "a block";
2511 return true;
2512 default: {
2513 const MemSpaceRegion *MS = MR->getMemorySpace(State);
2514
2516 const VarRegion *VR = dyn_cast(MR);
2517 const VarDecl *VD;
2518 if (VR)
2520 else
2521 VD = nullptr;
2522
2523 if (VD)
2524 os << "the address of the local variable '" << VD->getName() << "'";
2525 else
2526 os << "the address of a local stack variable";
2527 return true;
2528 }
2529
2531 const VarRegion *VR = dyn_cast(MR);
2532 const VarDecl *VD;
2533 if (VR)
2535 else
2536 VD = nullptr;
2537
2538 if (VD)
2539 os << "the address of the parameter '" << VD->getName() << "'";
2540 else
2541 os << "the address of a parameter";
2542 return true;
2543 }
2544
2546 const VarRegion *VR = dyn_cast(MR);
2547 const VarDecl *VD;
2548 if (VR)
2550 else
2551 VD = nullptr;
2552
2553 if (VD) {
2555 os << "the address of the static variable '" << VD->getName() << "'";
2556 else
2557 os << "the address of the global variable '" << VD->getName() << "'";
2558 } else
2559 os << "the address of a global variable";
2560 return true;
2561 }
2562
2563 return false;
2564 }
2565 }
2566}
2567
2568void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
2569 SourceRange Range,
2570 const Expr *DeallocExpr,
2571 AllocationFamily Family) const {
2572 const BadFree *Frontend = getRelevantFrontendAs(Family);
2573 if (!Frontend)
2574 return;
2575 if (!Frontend->isEnabled()) {
2576 C.addSink();
2577 return;
2578 }
2579
2580 if (ExplodedNode *N = C.generateErrorNode()) {
2581 SmallString<100> buf;
2582 llvm::raw_svector_ostream os(buf);
2583
2584 const MemRegion *MR = ArgVal.getAsRegion();
2585 while (const ElementRegion *ER = dyn_cast_or_null(MR))
2586 MR = ER->getSuperRegion();
2587
2588 os << "Argument to ";
2590 os << "deallocator";
2591
2592 os << " is ";
2593 bool Summarized =
2594 MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2595 if (Summarized)
2596 os << ", which is not memory allocated by ";
2597 else
2598 os << "not memory allocated by ";
2599
2601
2602 auto R = std::make_unique(Frontend->BadFreeBug,
2603 os.str(), N);
2604 R->markInteresting(MR);
2605 R->addRange(Range);
2606 C.emitReport(std::move(R));
2607 }
2608}
2609
2610void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
2611 SourceRange Range) const {
2612 const FreeAlloca *Frontend;
2613
2614 if (MallocChecker.isEnabled())
2615 Frontend = &MallocChecker;
2616 else if (MismatchedDeallocatorChecker.isEnabled())
2617 Frontend = &MismatchedDeallocatorChecker;
2618 else {
2619 C.addSink();
2620 return;
2621 }
2622
2623 if (ExplodedNode *N = C.generateErrorNode()) {
2624 auto R = std::make_unique(
2625 Frontend->FreeAllocaBug,
2626 "Memory allocated by 'alloca()' should not be deallocated", N);
2627 R->markInteresting(ArgVal.getAsRegion());
2628 R->addRange(Range);
2629 C.emitReport(std::move(R));
2630 }
2631}
2632
2633void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
2634 SourceRange Range,
2635 const Expr *DeallocExpr,
2636 const RefState *RS, SymbolRef Sym,
2637 bool OwnershipTransferred) const {
2638 if (!MismatchedDeallocatorChecker.isEnabled()) {
2639 C.addSink();
2640 return;
2641 }
2642
2643 if (ExplodedNode *N = C.generateErrorNode()) {
2644 SmallString<100> buf;
2645 llvm::raw_svector_ostream os(buf);
2646
2647 const Expr *AllocExpr = cast(RS->getStmt());
2648 SmallString<20> AllocBuf;
2649 llvm::raw_svector_ostream AllocOs(AllocBuf);
2650 SmallString<20> DeallocBuf;
2651 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2652
2653 if (OwnershipTransferred) {
2655 os << DeallocOs.str() << " cannot";
2656 else
2657 os << "Cannot";
2658
2659 os << " take ownership of memory";
2660
2662 os << " allocated by " << AllocOs.str();
2663 } else {
2664 os << "Memory";
2666 os << " allocated by " << AllocOs.str();
2667
2668 os << " should be deallocated by ";
2670
2672 os << ", not " << DeallocOs.str();
2673
2675 }
2676
2677 auto R = std::make_unique(
2678 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2679 R->markInteresting(Sym);
2680 R->addRange(Range);
2681 R->addVisitor(Sym);
2682 C.emitReport(std::move(R));
2683 }
2684}
2685
2686void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
2687 SourceRange Range, const Expr *DeallocExpr,
2688 AllocationFamily Family,
2689 const Expr *AllocExpr) const {
2690 const OffsetFree *Frontend = getRelevantFrontendAs(Family);
2691 if (!Frontend)
2692 return;
2693 if (!Frontend->isEnabled()) {
2694 C.addSink();
2695 return;
2696 }
2697
2698 ExplodedNode *N = C.generateErrorNode();
2699 if (!N)
2700 return;
2701
2702 SmallString<100> buf;
2703 llvm::raw_svector_ostream os(buf);
2704 SmallString<20> AllocNameBuf;
2705 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2706
2707 const MemRegion *MR = ArgVal.getAsRegion();
2708 assert(MR && "Only MemRegion based symbols can have offset free errors");
2709
2710 RegionOffset Offset = MR->getAsOffset();
2711 assert((Offset.isValid() &&
2714 "Only symbols with a valid offset can have offset free errors");
2715
2716 int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
2717
2718 os << "Argument to ";
2720 os << "deallocator";
2721 os << " is offset by "
2722 << offsetBytes
2723 << " "
2724 << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
2725 << " from the start of ";
2726 if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
2727 os << "memory allocated by " << AllocNameOs.str();
2728 else
2729 os << "allocated memory";
2730
2731 auto R = std::make_unique(Frontend->OffsetFreeBug,
2732 os.str(), N);
2734 R->addRange(Range);
2735 C.emitReport(std::move(R));
2736}
2737
2738void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
2740 const UseFree *Frontend = getRelevantFrontendAs(C, Sym);
2741 if (!Frontend)
2742 return;
2743 if (!Frontend->isEnabled()) {
2744 C.addSink();
2745 return;
2746 }
2747
2748 if (ExplodedNode *N = C.generateErrorNode()) {
2749 AllocationFamily AF =
2750 C.getState()->get(Sym)->getAllocationFamily();
2751
2752 auto R = std::make_unique(
2753 Frontend->UseFreeBug,
2754 AF.Kind == AF_InnerBuffer
2755 ? "Inner pointer of container used after re/deallocation"
2756 : "Use of memory after it is released",
2757 N);
2758
2759 R->markInteresting(Sym);
2760 R->addRange(Range);
2761 R->addVisitor(Sym);
2762
2763 if (AF.Kind == AF_InnerBuffer)
2765
2766 C.emitReport(std::move(R));
2767 }
2768}
2769
2770void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
2773 const DoubleFree *Frontend = getRelevantFrontendAs(C, Sym);
2774 if (!Frontend)
2775 return;
2776 if (!Frontend->isEnabled()) {
2777 C.addSink();
2778 return;
2779 }
2780
2781 if (ExplodedNode *N = C.generateErrorNode()) {
2782 auto R = std::make_unique(
2783 Frontend->DoubleFreeBug,
2784 (Released ? "Attempt to release already released memory"
2785 : "Attempt to release non-owned memory"),
2786 N);
2787 if (Range.isValid())
2788 R->addRange(Range);
2789 R->markInteresting(Sym);
2790 if (PrevSym)
2791 R->markInteresting(PrevSym);
2792 R->addVisitor(Sym);
2793 C.emitReport(std::move(R));
2794 }
2795}
2796
2797void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
2799 const UseZeroAllocated *Frontend =
2800 getRelevantFrontendAs(C, Sym);
2801 if (!Frontend)
2802 return;
2803 if (!Frontend->isEnabled()) {
2804 C.addSink();
2805 return;
2806 }
2807
2808 if (ExplodedNode *N = C.generateErrorNode()) {
2809 auto R = std::make_unique(
2810 Frontend->UseZeroAllocatedBug, "Use of memory allocated with size zero",
2811 N);
2812
2813 R->addRange(Range);
2814 if (Sym) {
2815 R->markInteresting(Sym);
2816 R->addVisitor(Sym);
2817 }
2818 C.emitReport(std::move(R));
2819 }
2820}
2821
2822void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
2823 SourceRange Range,
2824 const Expr *FreeExpr,
2825 AllocationFamily Family) const {
2826 const BadFree *Frontend = getRelevantFrontendAs(Family);
2827 if (!Frontend)
2828 return;
2829 if (!Frontend->isEnabled()) {
2830 C.addSink();
2831 return;
2832 }
2833
2834 if (ExplodedNode *N = C.generateErrorNode()) {
2835 SmallString<100> Buf;
2836 llvm::raw_svector_ostream Os(Buf);
2837
2838 const MemRegion *MR = ArgVal.getAsRegion();
2839 while (const ElementRegion *ER = dyn_cast_or_null(MR))
2840 MR = ER->getSuperRegion();
2841
2842 Os << "Argument to ";
2844 Os << "deallocator";
2845
2846 Os << " is a function pointer";
2847
2848 auto R = std::make_unique(Frontend->BadFreeBug,
2849 Os.str(), N);
2850 R->markInteresting(MR);
2851 R->addRange(Range);
2852 C.emitReport(std::move(R));
2853 }
2854}
2855
2857MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,
2859 AllocationFamily Family, bool SuffixWithN) const {
2860 if (!State)
2861 return nullptr;
2862
2864
2866 return nullptr;
2867
2868 const Expr *arg0Expr = CE->getArg(0);
2869 SVal Arg0Val = C.getSVal(arg0Expr);
2871 return nullptr;
2872 DefinedOrUnknownSVal arg0Val = Arg0Val.castAs();
2873
2874 SValBuilder &svalBuilder = C.getSValBuilder();
2875
2876 DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(
2877 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));
2878
2879
2880 const Expr *Arg1 = CE->getArg(1);
2881
2882
2883 SVal TotalSize = C.getSVal(Arg1);
2884 if (SuffixWithN)
2885 TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
2887 return nullptr;
2888
2889
2890 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2891 State, TotalSize.castAs(),
2892 svalBuilder.makeIntValWithWidth(
2893 svalBuilder.getContext().getCanonicalSizeType(), 0));
2894
2896 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2898 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2899
2900
2901 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2902 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2903
2904
2905
2906 if (PrtIsNull && !SizeIsZero) {
2908 C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2909 return stateMalloc;
2910 }
2911
2912
2913 if (PrtIsNull && SizeIsZero)
2914 return State;
2915
2916 assert(!PrtIsNull);
2917
2918 bool IsKnownToBeAllocated = false;
2919
2920
2921 if (SizeIsZero)
2922
2923
2924
2925
2927 C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))
2928 return stateFree;
2929
2930
2932 FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {
2933
2935 MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);
2936 if (!stateRealloc)
2937 return nullptr;
2938
2939 OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
2940 if (ShouldFreeOnFail)
2941 Kind = OAR_FreeOnFailure;
2942 else if (!IsKnownToBeAllocated)
2943 Kind = OAR_DoNotTrackAfterFailure;
2944
2945
2947 SVal RetVal = stateRealloc->getSVal(CE, C.getLocationContext());
2949 assert(FromPtr && ToPtr &&
2950 "By this point, FreeMemAux and MallocMemAux should have checked "
2951 "whether the argument or the return value is symbolic!");
2952
2953
2954
2955 stateRealloc = stateRealloc->set(ToPtr,
2956 ReallocPair(FromPtr, Kind));
2957
2958 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2959 return stateRealloc;
2960 }
2961 return nullptr;
2962}
2963
2965 const CallEvent &Call,
2967 if (!State)
2968 return nullptr;
2969
2970 if (Call.getNumArgs() < 2)
2971 return nullptr;
2972
2973 SValBuilder &svalBuilder = C.getSValBuilder();
2975 SVal TotalSize =
2976 evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
2977
2978 return MallocMemAux(C, Call, TotalSize, zeroVal, State,
2979 AllocationFamily(AF_Malloc));
2980}
2981
2982MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
2984 CheckerContext &C) {
2986
2987
2988 const ExplodedNode *AllocNode = N;
2989 const MemRegion *ReferenceRegion = nullptr;
2990
2991 while (N) {
2993 if (!State->get(Sym))
2994 break;
2995
2996
2997
2998 if (!ReferenceRegion) {
2999 if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
3000 SVal Val = State->getSVal(MR);
3003
3004
3006 ReferenceRegion = MR;
3007 }
3008 }
3009 }
3010
3011
3012
3014 if (NContext == LeakContext ||
3016 AllocNode = N;
3018 }
3019
3020 return LeakInfo(AllocNode, ReferenceRegion);
3021}
3022
3023void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
3024 CheckerContext &C) const {
3025 assert(N && "HandleLeak is only called with a non-null node");
3026
3027 const RefState *RS = C.getState()->get(Sym);
3028 assert(RS && "cannot leak an untracked symbol");
3029 AllocationFamily Family = RS->getAllocationFamily();
3030
3031 if (Family.Kind == AF_Alloca)
3032 return;
3033
3034 const Leak *Frontend = getRelevantFrontendAs(Family);
3035
3036
3037
3038 if (!Frontend || !Frontend->isEnabled())
3039 return;
3040
3041
3042
3043
3044 PathDiagnosticLocation LocUsedForUniqueing;
3045 const ExplodedNode *AllocNode = nullptr;
3046 const MemRegion *Region = nullptr;
3047 std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
3048
3050 if (AllocationStmt)
3052 C.getSourceManager(),
3054
3055 SmallString<200> buf;
3056 llvm::raw_svector_ostream os(buf);
3058 os << "Potential leak of memory pointed to by ";
3060 } else {
3061 os << "Potential memory leak";
3062 }
3063
3064 auto R = std::make_unique(
3065 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3067 R->markInteresting(Sym);
3068 R->addVisitor(Sym, true);
3069 if (ShouldRegisterNoOwnershipChangeVisitor)
3070 R->addVisitor(Sym, this);
3071 C.emitReport(std::move(R));
3072}
3073
3074void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3075 CheckerContext &C) const
3076{
3078 RegionStateTy OldRS = state->get();
3079 RegionStateTy::Factory &F = state->get_context();
3080
3081 RegionStateTy RS = OldRS;
3082 SmallVector<SymbolRef, 2> Errors;
3083 for (auto [Sym, State] : RS) {
3084 if (SymReaper.isDead(Sym)) {
3085 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3086 Errors.push_back(Sym);
3087
3088 RS = F.remove(RS, Sym);
3089 }
3090 }
3091
3092 if (RS == OldRS) {
3093
3094 assert(state->get() ==
3095 C.getState()->get());
3096 assert(state->get() ==
3097 C.getState()->get());
3098 return;
3099 }
3100
3101
3102 ReallocPairsTy RP = state->get();
3103 for (auto [Sym, ReallocPair] : RP) {
3104 if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {
3105 state = state->remove(Sym);
3106 }
3107 }
3108
3109
3110 FreeReturnValueTy FR = state->get();
3111 for (auto [Sym, RetSym] : FR) {
3112 if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {
3113 state = state->remove(Sym);
3114 }
3115 }
3116
3117
3118 ExplodedNode *N = C.getPredecessor();
3119 if (!Errors.empty()) {
3120 N = C.generateNonFatalErrorNode(C.getState());
3121 if (N) {
3123 HandleLeak(Sym, N, C);
3124 }
3125 }
3126 }
3127
3128 C.addTransition(state->set(RS), N);
3129}
3130
3131
3132
3133
3135 return Name == "unique_ptr" || Name == "shared_ptr";
3136}
3137
3138
3141
3142 if (const auto *TST = QT->getAs()) {
3143 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3144 if (!TD)
3145 return false;
3146
3147 const auto *ND = dyn_cast_or_null(TD->getTemplatedDecl());
3148 if (!ND)
3149 return false;
3150
3151
3152
3154 }
3155
3156 return false;
3157}
3158
3159
3160
3161
3162
3166 llvm::SmallPtrSetImpl<const MemRegion *> *Out;
3167
3169 llvm::SmallPtrSetImpl<const MemRegion *> &Out)
3171
3175 Out->insert(FR);
3176 }
3177
3179 bool IsVirtual) {
3180
3181 SVal BaseL =
3182 C->getState()->getLValue(BaseDecl, Reg->getAs<SubRegion>(), IsVirtual);
3184
3186 }
3187 return std::nullopt;
3188 }
3189};
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3203 std::optional FC = std::nullopt) {
3204
3207 if (!FC)
3208 return true;
3209 FC->consume(FD);
3210 }
3211 }
3212
3213
3216 BaseSpec.getType()->getAsCXXRecordDecl()) {
3217 std::optional NewFC;
3218 if (FC) {
3219 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3220 if (!NewFC)
3221 continue;
3222 }
3224 if (Found && !FC)
3225 return true;
3226 }
3227 }
3228 return false;
3229}
3230
3231
3234 return false;
3235
3237 if (->isRecordType() || T->isReferenceType())
3238 return false;
3239
3240
3243}
3244
3245
3246
3249 return false;
3250
3253}
3254
3255
3257 if (!RD)
3258 return false;
3259
3260
3261
3263}
3264
3265
3266
3268
3269 const auto *CD = dyn_cast_or_null(Call.getDecl());
3270 if (!CD)
3271 return false;
3272
3273 const auto *RD = CD->getParent();
3275 return false;
3276
3277
3278 for (const auto *Param : CD->parameters()) {
3279 QualType ParamType = Param->getType();
3282 return true;
3283 }
3284 }
3285
3286 return false;
3287}
3288
3289
3290
3291static void
3294 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3295 if (!Reg)
3296 return;
3297
3299 if (!CRD)
3300 return;
3301
3304}
3305
3306
3307
3308ProgramStateRef MallocChecker::handleSmartPointerConstructorArguments(
3311 for (unsigned I = 0, E = std::min(Call.getNumArgs(), CD->getNumParams());
3312 I != E; ++I) {
3313 const Expr *ArgExpr = Call.getArgExpr(I);
3314 if (!ArgExpr)
3315 continue;
3316
3317 QualType ParamType = CD->getParamDecl(I)->getType();
3320
3321 SVal ArgVal = Call.getArgSVal(I);
3323 if (Sym && State->contains(Sym)) {
3324 const RefState *RS = State->get(Sym);
3325 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3326 State = State->set(Sym, RefState::getEscaped(RS));
3327 }
3328 }
3329 }
3330 }
3331 return State;
3332}
3333
3334
3335
3336
3337ProgramStateRef MallocChecker::handleSmartPointerRelatedCalls(
3339
3340
3342 return handleSmartPointerConstructorArguments(Call, State);
3343 }
3344
3345
3346 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3347 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3348 const Expr *AE = Call.getArgExpr(I);
3349 if (!AE)
3350 continue;
3352
3354 continue;
3355
3356
3357 SVal ArgVal = Call.getArgSVal(I);
3358 const MemRegion *ArgRegion = ArgVal.getAsRegion();
3359
3361 SmartPtrFieldRoots);
3362 }
3363
3364
3365 if (!SmartPtrFieldRoots.empty()) {
3366 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3367 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3368 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3369 SmartPtrFieldRootsVec, State);
3370 }
3371
3372 return State;
3373}
3374
3375void MallocChecker::checkPostCall(const CallEvent &Call,
3376 CheckerContext &C) const {
3377
3378 if (const auto *PostFN = PostFnMap.lookup(Call)) {
3379 (*PostFN)(this, C.getState(), Call, C);
3380 return;
3381 }
3382
3383
3384 C.addTransition(handleSmartPointerRelatedCalls(Call, C, C.getState()));
3385}
3386
3387void MallocChecker::checkPreCall(const CallEvent &Call,
3388 CheckerContext &C) const {
3389
3390 if (const auto *DC = dyn_cast(&Call)) {
3391 const CXXDeleteExpr *DE = DC->getOriginExpr();
3392
3393
3394
3395
3396
3397 if (!NewDeleteChecker.isEnabled())
3399 checkUseAfterFree(Sym, C, DE->getArgument());
3400
3402 return;
3403
3405 bool IsKnownToBeAllocated;
3406 State = FreeMemAux(
3408 false, IsKnownToBeAllocated,
3409 AllocationFamily(DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3410
3411 C.addTransition(State);
3412 return;
3413 }
3414
3415
3416
3417
3418
3419
3420
3421
3422 if (const auto *DC = dyn_cast(&Call)) {
3423 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3424 if (!Sym)
3425 return;
3427 HandleDoubleFree(C, SourceRange(), true, Sym,
3428 nullptr);
3429 return;
3430 }
3431 }
3432
3433
3434
3435 if (const auto *PreFN = PreFnMap.lookup(Call)) {
3436 (*PreFN)(this, C.getState(), Call, C);
3437 return;
3438 }
3439
3440
3441
3442
3443
3444 if (const AnyFunctionCall *FC = dyn_cast(&Call)) {
3445 const FunctionDecl *FD = FC->getDecl();
3446 if (!FD)
3447 return;
3448
3449
3450
3451
3452 if (MallocChecker.isEnabled() && isFreeingCall(Call))
3453 return;
3454 }
3455
3456
3457 if (const CXXInstanceCall *CC = dyn_cast(&Call)) {
3458 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3459 if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))
3460 return;
3461 }
3462
3463
3464 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3465 SVal ArgSVal = Call.getArgSVal(I);
3468 if (!Sym)
3469 continue;
3470 if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
3471 return;
3472 }
3473 }
3474}
3475
3476void MallocChecker::checkPreStmt(const ReturnStmt *S,
3477 CheckerContext &C) const {
3478 checkEscapeOnReturn(S, C);
3479}
3480
3481
3482
3483
3484void MallocChecker::checkEndFunction(const ReturnStmt *S,
3485 CheckerContext &C) const {
3486 checkEscapeOnReturn(S, C);
3487}
3488
3489void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
3490 CheckerContext &C) const {
3491 if (!S)
3492 return;
3493
3495 if (!E)
3496 return;
3497
3498
3500 SVal RetVal = C.getSVal(E);
3502 if (!Sym)
3503
3504
3505 if (const MemRegion *MR = RetVal.getAsRegion())
3507 if (const SymbolicRegion *BMR =
3509 Sym = BMR->getSymbol();
3510
3511
3512 if (Sym)
3513 checkUseAfterFree(Sym, C, E);
3514}
3515
3516
3517
3518
3519void MallocChecker::checkPostStmt(const BlockExpr *BE,
3520 CheckerContext &C) const {
3521
3522
3523
3525 return;
3526
3528 const BlockDataRegion *R =
3530
3532 if (ReferencedVars.empty())
3533 return;
3534
3535 SmallVector<const MemRegion*, 10> Regions;
3536 const LocationContext *LC = C.getLocationContext();
3537 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
3538
3539 for (const auto &Var : ReferencedVars) {
3540 const VarRegion *VR = Var.getCapturedRegion();
3543 }
3544 Regions.push_back(VR);
3545 }
3546
3547 state =
3548 state->scanReachableSymbols(Regions).getState();
3549 C.addTransition(state);
3550}
3551
3553 assert(Sym);
3554 const RefState *RS = C.getState()->get(Sym);
3555 return (RS && RS->isReleased());
3556}
3557
3558bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3559 const CallEvent &Call, CheckerContext &C) const {
3560 if (Call.getNumArgs() == 0)
3561 return false;
3562
3563 StringRef FunctionStr = "";
3564 if (const auto *FD = dyn_cast(C.getStackFrame()->getDecl()))
3565 if (const Stmt *Body = FD->getBody())
3566 if (Body->getBeginLoc().isValid())
3567 FunctionStr =
3569 {FD->getBeginLoc(), Body->getBeginLoc()}),
3570 C.getSourceManager(), C.getLangOpts());
3571
3572
3573 if (!FunctionStr.contains("__isl_"))
3574 return false;
3575
3577
3578 for (const Expr *Arg : cast(Call.getOriginExpr())->arguments())
3579 if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())
3580 if (const RefState *RS = State->get(Sym))
3581 State = State->set(Sym, RefState::getEscaped(RS));
3582
3583 C.addTransition(State);
3584 return true;
3585}
3586
3587bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
3588 const Stmt *S) const {
3589
3592 return true;
3593 }
3594
3595 return false;
3596}
3597
3598void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
3599 const Stmt *S) const {
3600 assert(Sym);
3601
3602 if (const RefState *RS = C.getState()->get(Sym)) {
3603 if (RS->isAllocatedOfSizeZero())
3604 HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
3605 }
3606 else if (C.getState()->contains(Sym)) {
3608 }
3609}
3610
3611
3612void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
3613 CheckerContext &C) const {
3615 if (Sym) {
3616 checkUseAfterFree(Sym, C, S);
3617 checkUseZeroAllocated(Sym, C, S);
3618 }
3619}
3620
3621
3622
3625 bool Assumption) const {
3626 RegionStateTy RS = state->get();
3627 for (SymbolRef Sym : llvm::make_first_range(RS)) {
3628
3629 ConstraintManager &CMgr = state->getConstraintManager();
3630 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3632 state = state->remove(Sym);
3633 }
3634
3635
3636
3637 ReallocPairsTy RP = state->get();
3638 for (auto [Sym, ReallocPair] : RP) {
3639
3640 ConstraintManager &CMgr = state->getConstraintManager();
3641 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3643 continue;
3644
3645 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3646 if (const RefState *RS = state->get(ReallocSym)) {
3647 if (RS->isReleased()) {
3648 switch (ReallocPair.Kind) {
3649 case OAR_ToBeFreedAfterFailure:
3650 state = state->set(ReallocSym,
3651 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3652 break;
3653 case OAR_DoNotTrackAfterFailure:
3654 state = state->remove(ReallocSym);
3655 break;
3656 default:
3657 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3658 }
3659 }
3660 }
3661 state = state->remove(Sym);
3662 }
3663
3664 return state;
3665}
3666
3667bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3668 const CallEvent *Call,
3670 SymbolRef &EscapingSymbol) const {
3671 assert(Call);
3672 EscapingSymbol = nullptr;
3673
3674
3675
3676
3677
3679 return true;
3680
3681
3682 if (const ObjCMethodCall *Msg = dyn_cast(Call)) {
3683
3684
3685 if (->isInSystemHeader() || Call->argumentsMayEscape())
3686 return true;
3687
3688
3689
3691 return false;
3692
3693
3694
3695
3696
3698 return *FreeWhenDone;
3699
3700
3701
3702
3703
3704 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3705 if (FirstSlot.ends_with("NoCopy"))
3706 return true;
3707
3708
3709
3710
3711
3712 if (FirstSlot.starts_with("addPointer") ||
3713 FirstSlot.starts_with("insertPointer") ||
3714 FirstSlot.starts_with("replacePointer") ||
3715 FirstSlot == "valueWithPointer") {
3716 return true;
3717 }
3718
3719
3720
3721
3722 if (Msg->getMethodFamily() == OMF_init) {
3723 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3724 return true;
3725 }
3726
3727
3728
3729 return false;
3730 }
3731
3732
3734 if (!FD)
3735 return true;
3736
3737
3738
3739 if (isMemCall(*Call))
3740 return false;
3741
3742
3743 if (->isInSystemHeader())
3744 return true;
3745
3746
3748 if (!II)
3749 return true;
3750 StringRef FName = II->getName();
3751
3752
3753
3754 if (FName.ends_with("NoCopy")) {
3755
3756
3757
3758 for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
3759 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
3760 if (const DeclRefExpr *DE = dyn_cast(ArgE)) {
3761 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3762 if (DeallocatorName == "kCFAllocatorNull")
3763 return false;
3764 }
3765 }
3766 return true;
3767 }
3768
3769
3770
3771
3772
3773 if (FName == "funopen")
3774 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
3775 return false;
3776
3777
3778
3779
3780 if (FName == "setbuf" || FName =="setbuffer" ||
3781 FName == "setlinebuf" || FName == "setvbuf") {
3782 if (Call->getNumArgs() >= 1) {
3784 if (const DeclRefExpr *ArgDRE = dyn_cast(ArgE))
3785 if (const VarDecl *D = dyn_cast(ArgDRE->getDecl()))
3786 if (D->getCanonicalDecl()->getName().contains("std"))
3787 return true;
3788 }
3789 }
3790
3791
3792
3793
3794
3795
3796 if (FName == "CGBitmapContextCreate" ||
3797 FName == "CGBitmapContextCreateWithData" ||
3798 FName == "CVPixelBufferCreateWithBytes" ||
3799 FName == "CVPixelBufferCreateWithPlanarBytes" ||
3800 FName == "OSAtomicEnqueue") {
3801 return true;
3802 }
3803
3804 if (FName == "postEvent" &&
3806 return true;
3807 }
3808
3809 if (FName == "connectImpl" &&
3811 return true;
3812 }
3813
3814 if (FName == "singleShotImpl" &&
3816 return true;
3817 }
3818
3819
3820
3821
3822
3823
3824 if (FName == "GetOwnedMessageInternal") {
3825 return true;
3826 }
3827
3828
3829
3830
3831
3832 if (Call->argumentsMayEscape())
3833 return true;
3834
3835
3836
3837 return false;
3838}
3839
3842 const CallEvent *Call,
3844 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3845 false);
3846}
3847
3850 const CallEvent *Call,
3852
3853 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3854 true);
3855}
3856
3858 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3859 RS->getAllocationFamily().Kind == AF_CXXNew);
3860}
3861
3865 bool IsConstPointerEscape) const {
3866
3867
3868 SymbolRef EscapingSymbol = nullptr;
3870 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3871 EscapingSymbol) &&
3872 !EscapingSymbol) {
3873 return State;
3874 }
3875
3877 if (EscapingSymbol && EscapingSymbol != sym)
3878 continue;
3879
3880 if (const RefState *RS = State->get(sym))
3881 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3883 State = State->set(sym, RefState::getEscaped(RS));
3884 }
3885 return State;
3886}
3887
3888bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
3889 SVal ArgVal) const {
3890 if (!KernelZeroSizePtrValue)
3891 KernelZeroSizePtrValue =
3893
3894 const llvm::APSInt *ArgValKnown =
3895 C.getSValBuilder().getKnownValue(State, ArgVal);
3896 return ArgValKnown && *KernelZeroSizePtrValue &&
3897 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3898}
3899
3902 ReallocPairsTy currMap = currState->get();
3903 ReallocPairsTy prevMap = prevState->get();
3904
3905 for (const ReallocPairsTy::value_type &Pair : prevMap) {
3907 if (!currMap.lookup(sym))
3908 return sym;
3909 }
3910
3911 return nullptr;
3912}
3913
3916 StringRef N = II->getName();
3917 if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
3918 if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
3919 N.contains_insensitive("intrusive") ||
3920 N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {
3921 return true;
3922 }
3923 }
3924 }
3925 return false;
3926}
3927
3929 BugReporterContext &BRC,
3930 PathSensitiveBugReport &BR) {
3933
3934 const RefState *RSCurr = state->get(Sym);
3935 const RefState *RSPrev = statePrev->get(Sym);
3936
3938
3939
3940 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3941 return nullptr;
3942
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3954 ReleaseFunctionLC->isParentOf(CurrentLC))) {
3955 if (const auto *AE = dyn_cast(S)) {
3956
3958 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3959 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3961
3962
3963 return nullptr;
3964 }
3965 } else if (const auto *CE = dyn_cast(S)) {
3966
3967
3968 if (const auto *MD =
3969 dyn_cast_or_null(CE->getDirectCallee())) {
3970 const CXXRecordDecl *RD = MD->getParent();
3971
3972
3973 if (StringRef(RD->getNameAsString()).contains("atomic")) {
3975
3976
3977 return nullptr;
3978 }
3979 }
3980 }
3981 }
3982
3983
3984
3985
3986
3987 StringRef Msg;
3988 std::unique_ptr StackHint = nullptr;
3989 SmallString<256> Buf;
3990 llvm::raw_svector_ostream OS(Buf);
3991
3992 if (Mode == Normal) {
3993 if (isAllocated(RSCurr, RSPrev, S)) {
3994 Msg = "Memory is allocated";
3995 StackHint = std::make_unique(
3996 Sym, "Returned allocated memory");
3997 } else if (isReleased(RSCurr, RSPrev, S)) {
3998 const auto Family = RSCurr->getAllocationFamily();
3999 switch (Family.Kind) {
4000 case AF_Alloca:
4001 case AF_Malloc:
4002 case AF_Custom:
4003 case AF_CXXNew:
4004 case AF_CXXNewArray:
4005 case AF_IfNameIndex:
4006 Msg = "Memory is released";
4007 StackHint = std::make_unique(
4008 Sym, "Returning; memory was released");
4009 break;
4010 case AF_InnerBuffer: {
4011 const MemRegion *ObjRegion =
4014 QualType ObjTy = TypedRegion->getValueType();
4015 OS << "Inner buffer of '" << ObjTy << "' ";
4016
4018 OS << "deallocated by call to destructor";
4019 StackHint = std::make_unique(
4020 Sym, "Returning; inner buffer was deallocated");
4021 } else {
4022 OS << "reallocated by call to '";
4023 const Stmt *S = RSCurr->getStmt();
4024 if (const auto *MemCallE = dyn_cast(S)) {
4025 OS << MemCallE->getMethodDecl()->getDeclName();
4026 } else if (const auto *OpCallE = dyn_cast(S)) {
4027 OS << OpCallE->getDirectCallee()->getDeclName();
4028 } else if (const auto *CallE = dyn_cast(S)) {
4030 CallEventRef<> Call =
4031 CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
4032 if (const auto *D = dyn_cast_or_null(Call->getDecl()))
4033 OS << D->getDeclName();
4034 else
4035 OS << "unknown";
4036 }
4037 OS << "'";
4038 StackHint = std::make_unique(
4039 Sym, "Returning; inner buffer was reallocated");
4040 }
4041 Msg = OS.str();
4042 break;
4043 }
4044 case AF_None:
4045 assert(false && "Unhandled allocation family!");
4046 return nullptr;
4047 }
4048
4049
4050
4051
4052
4053
4054
4056
4057
4058 for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {
4059 if (const auto *DD = dyn_cast(LC->getDecl())) {
4061
4062
4063
4065
4066
4067
4068 return nullptr;
4069 }
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4096 }
4097 }
4098
4099 } else if (isRelinquished(RSCurr, RSPrev, S)) {
4100 Msg = "Memory ownership is transferred";
4101 StackHint = std::make_unique(Sym, "");
4102 } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4103 Mode = ReallocationFailed;
4104 Msg = "Reallocation failed";
4105 StackHint = std::make_unique(
4106 Sym, "Reallocation failed");
4107
4109
4110 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4111 "We only support one failed realloc at a time.");
4113 FailedReallocSymbol = sym;
4114 }
4115 }
4116
4117
4118 } else if (Mode == ReallocationFailed) {
4119 assert(FailedReallocSymbol && "No symbol to look for.");
4120
4121
4122 if (!statePrev->get(FailedReallocSymbol)) {
4123
4124 Msg = "Attempt to reallocate memory";
4125 StackHint = std::make_unique(
4126 Sym, "Returned reallocated memory");
4127 FailedReallocSymbol = nullptr;
4129 }
4130 }
4131
4132 if (Msg.empty()) {
4133 assert(!StackHint);
4134 return nullptr;
4135 }
4136
4137 assert(StackHint);
4138
4139
4140 PathDiagnosticLocation Pos;
4141 if (!S) {
4142 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4143 auto PostImplCall = N->getLocation().getAs();
4144 if (!PostImplCall)
4145 return nullptr;
4146 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4148 } else {
4151 }
4152
4153 auto P = std::make_shared(Pos, Msg, true);
4155 return P;
4156}
4157
4158void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
4159 const char *NL, const char *Sep) const {
4160
4161 RegionStateTy RS = State->get();
4162
4163 if (!RS.isEmpty()) {
4164 Out << Sep << "MallocChecker :" << NL;
4165 for (auto [Sym, Data] : RS) {
4166 const RefState *RefS = State->get(Sym);
4167 AllocationFamily Family = RefS->getAllocationFamily();
4168
4169 const CheckerFrontend *Frontend =
4170 getRelevantFrontendAs(Family);
4171
4173 Out << " : ";
4174 Data.dump(Out);
4175 if (Frontend && Frontend->isEnabled())
4176 Out << " (" << Frontend->getName() << ")";
4177 Out << NL;
4178 }
4179 }
4180}
4181
4182namespace clang {
4183namespace ento {
4184namespace allocation_state {
4185
4188 AllocationFamily Family(AF_InnerBuffer);
4189 return State->set(Sym, RefState::getReleased(Family, Origin));
4190}
4191
4192}
4193}
4194}
4195
4196
4197
4199 Mgr.getChecker()->InnerPointerChecker.enable(Mgr);
4200}
4201
4202void ento::registerDynamicMemoryModeling(CheckerManager &Mgr) {
4203 auto *Chk = Mgr.getChecker();
4204
4205
4207 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4208 Mgr.getAnalyzerOptions().getCheckerBooleanOption(DMMName, "Optimistic");
4209 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4211 DMMName, "AddNoOwnershipChangeNotes");
4212}
4213
4214bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
4215 return true;
4216}
4217
4218#define REGISTER_CHECKER(NAME) \
4219 void ento::register##NAME(CheckerManager &Mgr) { \
4220 Mgr.getChecker()->NAME.enable(Mgr); \
4221 } \
4222 \
4223 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4224
4225
#define REGISTER_CHECKER(name)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
Definition MallocChecker.cpp:3247
static bool isFromStdNamespace(const CallEvent &Call)
Definition MallocChecker.cpp:1568
static bool isStandardNew(const FunctionDecl *FD)
Definition MallocChecker.cpp:1161
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
Definition MallocChecker.cpp:1800
static QualType getDeepPointeeType(QualType T)
Definition MallocChecker.cpp:1789
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
Definition MallocChecker.cpp:3552
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
Definition MallocChecker.cpp:2200
static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
Definition MallocChecker.cpp:3292
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
Definition MallocChecker.cpp:3202
static bool isStandardDelete(const FunctionDecl *FD)
Definition MallocChecker.cpp:1177
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
Definition MallocChecker.cpp:3914
static bool isSmartPtrType(QualType QT)
Definition MallocChecker.cpp:3139
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
Definition MallocChecker.cpp:337
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
Definition MallocChecker.cpp:3900
static bool isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
Definition MallocChecker.cpp:3232
#define BUGTYPE_PROVIDER(NAME, DEF)
Definition MallocChecker.cpp:348
static bool isGRealloc(const CallEvent &Call)
Definition MallocChecker.cpp:1379
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
Definition MallocChecker.cpp:1463
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
Definition MallocChecker.cpp:3256
#define CHECK_FN(NAME)
Definition MallocChecker.cpp:462
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
Definition MallocChecker.cpp:2227
static bool isStandardRealloc(const CallEvent &Call)
Definition MallocChecker.cpp:1370
static bool isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
Definition MallocChecker.cpp:3267
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
Definition MallocChecker.cpp:2124
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
Definition MallocChecker.cpp:2055
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
Definition MallocChecker.cpp:2158
static bool isSmartPtrName(StringRef Name)
Definition MallocChecker.cpp:3134
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
Definition MallocChecker.cpp:2137
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
Definition MallocChecker.cpp:1872
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
Definition MallocChecker.cpp:1884
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
Definition MallocChecker.cpp:3857
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
CanQualType getCanonicalSizeType() const
CanQualType UnsignedLongTy
static bool hasSameType(QualType T1, QualType T2)
Determine whether the given types T1 and T2 are equivalent.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
const BlockDecl * getBlockDecl() const
Represents a base class of a C++ class.
Represents binding an expression to a temporary.
Represents a call to a C++ constructor.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Represents a C++ constructor within a class.
Represents a delete expression for memory deallocation and destructor calls, e.g.
Represents a C++ destructor within a class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Represents a C++ struct/union/class.
Represents a C++ functional cast expression that builds a temporary object.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
static CharSourceRange getTokenRange(SourceRange R)
Decl - This represents one declaration (or definition), e.g.
bool isInStdNamespace() const
ASTContext & getASTContext() const LLVM_READONLY
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
SourceLocation getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Represents a member of a struct/union/class.
Represents a function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Describes an C or C++ initializer list.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
std::string getQualifiedNameAsString() const
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
An expression that sends a message to the given Objective-C object or class.
bool isConsumedExpr(Expr *E) const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
field_range fields() const
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
The base class of all kinds of template declarations (e.g., class, function, etc.).
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isVoidPointerType() const
bool isFunctionPointerType() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs'.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
APSIntPtr getMaxValue(const llvm::APSInt &v)
llvm::iterator_range< referenced_vars_iterator > referenced_vars() const
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
An immutable map from CallDescriptions to arbitrary data.
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Checker families (where a single backend class implements multiple related frontends) should derive f...
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
static bool isLocType(QualType T)
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
bool hasMemorySpace(ProgramStateRef State) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
Represents any expression that calls an Objective-C method.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
CallEventManager & getCallEventManager()
bool hasSymbolicOffset() const
int64_t getOffset() const
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isUnknownOrUndef() const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolRef getSymbol() const
It might return null.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
Definition MallocChecker.cpp:4187
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
const char *const MemoryError
const char *const TaintedData
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
Definition MallocChecker.cpp:4198
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool isa(CodeGen::Address addr)
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
const FunctionProtoType * T
bool operator!=(CanQual< T > x, CanQual< U > y)
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
U cast(CodeGen::Address addr)
@ Other
Other implicit parameter.
int const char * function
Helper struct for collecting smart owning pointer field regions.
Definition MallocChecker.cpp:3163
void consume(const FieldDecl *FD)
Definition MallocChecker.cpp:3172
std::optional< FieldConsumer > switchToBase(const CXXRecordDecl *BaseDecl, bool IsVirtual)
Definition MallocChecker.cpp:3178
FieldConsumer(const MemRegion *Reg, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Definition MallocChecker.cpp:3168
llvm::SmallPtrSetImpl< const MemRegion * > * Out
Definition MallocChecker.cpp:3166
CheckerContext * C
Definition MallocChecker.cpp:3165
const MemRegion * Reg
Definition MallocChecker.cpp:3164