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
81#include "llvm/ADT/STLExtras.h"
82#include "llvm/ADT/SetOperations.h"
83#include "llvm/ADT/StringExtras.h"
84#include "llvm/Support/Casting.h"
85#include "llvm/Support/Compiler.h"
86#include "llvm/Support/ErrorHandling.h"
87#include "llvm/Support/raw_ostream.h"
88#include
89#include
90#include
91
92using namespace clang;
93using namespace ento;
94using namespace std::placeholders;
95
96
97
98
99
100
101
102
103namespace {
104
105
106enum AllocationFamilyKind {
107 AF_None,
108 AF_Malloc,
109 AF_CXXNew,
110 AF_CXXNewArray,
111 AF_IfNameIndex,
112 AF_Alloca,
113 AF_InnerBuffer,
114 AF_Custom,
115};
116
117struct AllocationFamily {
118 AllocationFamilyKind Kind;
119 std::optional CustomName;
120
121 explicit AllocationFamily(AllocationFamilyKind AKind,
122 std::optional Name = std::nullopt)
123 : Kind(AKind), CustomName(Name) {
124 assert((Kind != AF_Custom || CustomName.has_value()) &&
125 "Custom family must specify also the name");
126
127
128 if (Kind == AF_Custom && CustomName.value() == "malloc") {
129 Kind = AF_Malloc;
130 CustomName = std::nullopt;
131 }
132 }
133
135 return std::tie(Kind, CustomName) == std::tie(Other.Kind, Other.CustomName);
136 }
137
139 return !(*this == Other);
140 }
141
142 void Profile(llvm::FoldingSetNodeID &ID) const {
143 ID.AddInteger(Kind);
144
145 if (Kind == AF_Custom)
146 ID.AddString(CustomName.value());
147 }
148};
149
150}
151
152
153
154
156
157
158
160
161
162
164
165
166
167
168
169namespace {
170
171class RefState {
173
174 Allocated,
175
176 AllocatedOfSizeZero,
177
178 Released,
179
180
181 Relinquished,
182
183
184
185 Escaped
186 };
187
188 const Stmt *S;
189
191 AllocationFamily Family;
192
193 RefState(Kind k, const Stmt *s, AllocationFamily family)
194 : S(s), K(k), Family(family) {
195 assert(family.Kind != AF_None);
196 }
197
198public:
199 bool isAllocated() const { return K == Allocated; }
200 bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
201 bool isReleased() const { return K == Released; }
202 bool isRelinquished() const { return K == Relinquished; }
203 bool isEscaped() const { return K == Escaped; }
204 AllocationFamily getAllocationFamily() const { return Family; }
205 const Stmt *getStmt() const { return S; }
206
207 bool operator==(const RefState &X) const {
208 return K == X.K && S == X.S && Family == X.Family;
209 }
210
211 static RefState getAllocated(AllocationFamily family, const Stmt *s) {
212 return RefState(Allocated, s, family);
213 }
214 static RefState getAllocatedOfSizeZero(const RefState *RS) {
215 return RefState(AllocatedOfSizeZero, RS->getStmt(),
216 RS->getAllocationFamily());
217 }
218 static RefState getReleased(AllocationFamily family, const Stmt *s) {
219 return RefState(Released, s, family);
220 }
221 static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
222 return RefState(Relinquished, s, family);
223 }
224 static RefState getEscaped(const RefState *RS) {
225 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
226 }
227
228 void Profile(llvm::FoldingSetNodeID &ID) const {
229 ID.AddInteger(K);
230 ID.AddPointer(S);
231 Family.Profile(ID);
232 }
233
234 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
235 switch (K) {
236#define CASE(ID) case ID: OS << #ID; break;
237 CASE(Allocated)
238 CASE(AllocatedOfSizeZero)
239 CASE(Released)
240 CASE(Relinquished)
241 CASE(Escaped)
242 }
243 }
244
245 LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
246};
247
248}
249
251
252
254
255
256
257
260 AllocationFamily Family,
261 std::optional RetVal = std::nullopt);
262
263
264
265
266
267
268
269
271
272namespace {
273
274
275enum OwnershipAfterReallocKind {
276
277 OAR_ToBeFreedAfterFailure,
278
279 OAR_FreeOnFailure,
280
281
282
283
284
285
286
287 OAR_DoNotTrackAfterFailure
288};
289
290
291
292
293
294
295
296struct ReallocPair {
297
298
300 OwnershipAfterReallocKind Kind;
301
302 ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
303 : ReallocatedSym(S), Kind(K) {}
304 void Profile(llvm::FoldingSetNodeID &ID) const {
305 ID.AddInteger(Kind);
306 ID.AddPointer(ReallocatedSym);
307 }
308 bool operator==(const ReallocPair &X) const {
309 return ReallocatedSym == X.ReallocatedSym &&
311 }
312};
313
314}
315
317
320 if (.getDecl() || !isa(Call.getDecl()))
321 return false;
323}
324
327 if (.getDecl() || !isa(Call.getDecl()))
328 return false;
330}
331
332
333
336}
337
338
339
340
341
342namespace {
343
344class MallocChecker
345 : public Checker<check::DeadSymbols, check::PointerEscape,
346 check::ConstPointerEscape, check::PreStmt,
347 check::EndFunction, check::PreCall, check::PostCall,
348 eval::Call, check::NewAllocator,
349 check::PostStmt, check::PostObjCMessage,
350 check::Location, eval::Assume> {
351public:
352
353
354
355
356 bool ShouldIncludeOwnershipAnnotatedFunctions = false;
357
358 bool ShouldRegisterNoOwnershipChangeVisitor = false;
359
360
361
362 enum CheckKind {
363
364
365
366 CK_MallocChecker,
367 CK_NewDeleteChecker,
368 CK_NewDeleteLeaksChecker,
369 CK_MismatchedDeallocatorChecker,
370 CK_InnerPointerChecker,
371 CK_TaintedAllocChecker,
372 CK_NumCheckKinds
373 };
374
375 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
376
377 bool ChecksEnabled[CK_NumCheckKinds] = {false};
379
390 bool Assumption) const;
391 void checkLocation(SVal l, bool isLoad, const Stmt *S,
393
402
404 const char *NL, const char *Sep) const override;
405
406private:
407 mutable std::unique_ptr BT_DoubleFree[CK_NumCheckKinds];
408 mutable std::unique_ptr BT_DoubleDelete;
409 mutable std::unique_ptr BT_Leak[CK_NumCheckKinds];
410 mutable std::unique_ptr BT_UseFree[CK_NumCheckKinds];
411 mutable std::unique_ptr BT_BadFree[CK_NumCheckKinds];
412 mutable std::unique_ptr BT_FreeAlloca[CK_NumCheckKinds];
413 mutable std::unique_ptr BT_MismatchedDealloc;
414 mutable std::unique_ptr BT_OffsetFree[CK_NumCheckKinds];
415 mutable std::unique_ptr BT_UseZerroAllocated[CK_NumCheckKinds];
416 mutable std::unique_ptr BT_TaintedAlloc;
417
418#define CHECK_FN(NAME) \
419 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
420 const;
421
429 CHECK_FN(checkIfFreeNameIndex)
430 CHECK_FN(checkCXXNewOrCXXDelete)
439
442
443 using CheckFn =
444 std::function<void(const MallocChecker *, ProgramStateRef State,
446
448
449
450 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetdelim},
451 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetdelim},
452 };
453
455
456
457 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetdelim},
458 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::checkGetdelim},
459 };
460
462 {{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},
463 {{CDM::CLibrary, {"if_freenameindex"}, 1},
464 &MallocChecker::checkIfFreeNameIndex},
465 {{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},
466 {{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},
467 };
468
470 static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);
471 static bool isFreeingOwnershipAttrCall(const CallEvent &Call);
472 static bool isAllocatingOwnershipAttrCall(const FunctionDecl *Func);
473 static bool isAllocatingOwnershipAttrCall(const CallEvent &Call);
474
475 friend class NoMemOwnershipChangeVisitor;
476
478 {{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},
479 {{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},
480
481
482
483 {{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},
484 &MallocChecker::checkAlloca},
485 };
486
488 {{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
489 {{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
490 {{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},
491 {{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
492 {{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
493 {{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
494 {{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},
495 {{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
496 {{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
497 {{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
498 {{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
499 {{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
500 {{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
501 {{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
502 {{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
503 {{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
504 {{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
505 {{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
506 {{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
507 {{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
508 };
509
511 {{CDM::CLibrary, {"realloc"}, 2},
512 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
513 {{CDM::CLibrary, {"reallocf"}, 2},
514 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)},
515 {{CDM::CLibrary, {"g_realloc"}, 2},
516 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
517 {{CDM::CLibrary, {"g_try_realloc"}, 2},
518 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
519 {{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
520 {{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
521 };
522
524 bool hasOwnershipReturns(const CallEvent &Call) const;
525 bool hasOwnershipTakesHolds(const CallEvent &Call) const;
528 AllocationFamily Family) const;
529
532 AllocationFamily Family) const;
533
534
535 mutable std::optional<uint64_t> KernelZeroFlagVal;
536
537 using KernelZeroSizePtrValueTy = std::optional;
538
539
540
541
542 mutable std::optional KernelZeroSizePtrValue;
543
544
545
548 AllocationFamily Family) const;
549
550
551
552
553
554
555
556
557
561 std::optional RetVal = std::nullopt);
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
582
583
584
585
586
587
588
592 bool isAlloca) const;
593
594
595
596
597
598
599
600
601
602
606
607
608
609
610
611
612
613
614
615
619 AllocationFamily Family) const;
620
621
622
623 [[nodiscard]] std::optional
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
646 const OwnershipAttr *Att,
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
670 unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
671 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
696 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
697 AllocationFamily Family, bool ReturnsNullOnFailure = false,
698 std::optional ArgValOpt = {}) const;
699
700
701
702
703
704
705
706
707
708
709
710
711
712
716 bool SuffixWithN = false) const;
717
718
719
720
721
722
724 const Expr *Blocks,
725 const Expr *BlockBytes);
726
727
728
729
730
731
735
736
737
738 bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,
740
741
743
744
745
747 const Stmt *S) const;
748
749
751
752
753
754
755
756
757
758
759
760
761
762 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
764 SymbolRef &EscapingSymbol) const;
765
766
771 bool IsConstPointerEscape) const;
772
773
775
776
777
778
779
780 std::optional getCheckIfTracked(AllocationFamily Family,
781 bool IsALeakCheck = false) const;
782
784 bool IsALeakCheck = false) const;
785
786 static bool SummarizeValue(raw_ostream &os, SVal V);
787 static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
788
790 const Expr *DeallocExpr,
791 AllocationFamily Family) const;
792
795
797 const Expr *DeallocExpr, const RefState *RS,
798 SymbolRef Sym, bool OwnershipTransferred) const;
799
801 const Expr *DeallocExpr, AllocationFamily Family,
802 const Expr *AllocExpr = nullptr) const;
803
806
809
811
814
816 const Expr *FreeExpr,
817 AllocationFamily Family) const;
818
819
820
823
825
826
828 SVal ArgVal) const;
829};
830}
831
832
833
834
835
836namespace {
838protected:
839
840
841
842
843
844
845
846 bool isFreeingCallAsWritten(const CallExpr &Call) const {
847 const auto *MallocChk = static_cast<const MallocChecker *>(&Checker);
848 if (MallocChk->FreeingMemFnMap.lookupAsWritten(Call) ||
849 MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call))
850 return true;
851
852 if (const auto *Func =
853 llvm::dyn_cast_or_null(Call.getCalleeDecl()))
854 return MallocChecker::isFreeingOwnershipAttrCall(Func);
855
856 return false;
857 }
858
859 bool hasResourceStateChanged(ProgramStateRef CallEnterState,
861 return CallEnterState->get(Sym) !=
862 CallExitEndState->get(Sym);
863 }
864
865
866
867
868
869 bool doesFnIntendToHandleOwnership(const Decl *Callee,
871 const FunctionDecl *FD = dyn_cast(Callee);
872
873
874
875
876
877
878
879 if (!FD || !FD->hasBody())
880 return false;
882
888 return true;
889
890 if (const auto *Call = Match.getNodeAs<CallExpr>("call"))
891 if (isFreeingCallAsWritten(*Call))
892 return true;
893 }
894
895
896
897 return false;
898 }
899
902 N->getLocation(),
903 N->getState()->getStateManager().getContext().getSourceManager());
904 return std::make_shared(
905 L, "Returning without deallocating memory or storing the pointer for "
906 "later deallocation");
907 }
908
909public:
910 NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)
912
913 void Profile(llvm::FoldingSetNodeID &ID) const override {
914 static int Tag = 0;
915 ID.AddPointer(&Tag);
916 ID.AddPointer(Sym);
917 }
918};
919
920}
921
922
923
924
925
926namespace {
927
928
929
931protected:
932 enum NotificationMode { Normal, ReallocationFailed };
933
934
936
937
938 NotificationMode Mode;
939
940
942
943
944
946
947 bool IsLeak;
948
949public:
950 MallocBugVisitor(SymbolRef S, bool isLeak = false)
951 : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
952 ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
953
954 static void *getTag() {
955 static int Tag = 0;
956 return &Tag;
957 }
958
959 void Profile(llvm::FoldingSetNodeID &ID) const override {
960 ID.AddPointer(getTag());
961 ID.AddPointer(Sym);
962 }
963
964
965 static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
967 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
968 (RSCurr &&
969 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
970 (!RSPrev ||
971 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
972 }
973
974
975
976 static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
978 bool IsReleased =
979 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
980 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
981 ( && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
982 return IsReleased;
983 }
984
985
986 static inline bool isRelinquished(const RefState *RSCurr,
987 const RefState *RSPrev, const Stmt *Stmt) {
988 return (
989 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
990 (RSCurr && RSCurr->isRelinquished()) &&
991 (!RSPrev || !RSPrev->isRelinquished()));
992 }
993
994
995
996
997
998 static inline bool hasReallocFailed(const RefState *RSCurr,
999 const RefState *RSPrev,
1001 return ((!isa_and_nonnull(Stmt)) &&
1002 (RSCurr &&
1003 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1004 (RSPrev &&
1005 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1006 }
1007
1011
1015 if (!IsLeak)
1016 return nullptr;
1017
1019
1020 return std::make_shared(L, BR.getDescription(),
1021 false);
1022 }
1023
1024private:
1025 class StackHintGeneratorForReallocationFailed
1027 public:
1028 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
1030
1031 std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {
1032
1033 ++ArgIndex;
1034
1036 llvm::raw_svector_ostream os(buf);
1037
1038 os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1039 << " parameter failed";
1040
1041 return std::string(os.str());
1042 }
1043
1044 std::string getMessageForReturn(const CallExpr *CallExpr) override {
1045 return "Reallocation of returned value failed";
1046 }
1047 };
1048};
1049}
1050
1051
1052
1054
1055namespace {
1056class StopTrackingCallback final : public SymbolVisitor {
1058
1059public:
1062
1064 state = state->remove(sym);
1065 return true;
1066 }
1067};
1068}
1069
1071 if (!FD)
1072 return false;
1073
1075 if (Kind != OO_New && Kind != OO_Array_New)
1076 return false;
1077
1078
1080
1081
1084}
1085
1087 if (!FD)
1088 return false;
1089
1091 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1092 return false;
1093
1094 bool HasBody = FD->hasBody();
1095
1096
1098
1099
1100
1102 return L.isInvalid() || (!HasBody && SM.isInSystemHeader(L));
1103}
1104
1105
1106
1107
1108
1109bool MallocChecker::isFreeingOwnershipAttrCall(const CallEvent &Call) {
1110 const auto *Func = dyn_cast_or_null(Call.getDecl());
1111
1112 return Func && isFreeingOwnershipAttrCall(Func);
1113}
1114
1115bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {
1116 if (Func->hasAttrs()) {
1117 for (const auto *I : Func->specific_attrs()) {
1118 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1119 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1120 return true;
1121 }
1122 }
1123 return false;
1124}
1125
1126bool MallocChecker::isFreeingCall(const CallEvent &Call) const {
1127 if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1128 return true;
1129
1130 return isFreeingOwnershipAttrCall(Call);
1131}
1132
1133bool MallocChecker::isAllocatingOwnershipAttrCall(const CallEvent &Call) {
1134 const auto *Func = dyn_cast_or_null(Call.getDecl());
1135
1136 return Func && isAllocatingOwnershipAttrCall(Func);
1137}
1138
1139bool MallocChecker::isAllocatingOwnershipAttrCall(const FunctionDecl *Func) {
1140 for (const auto *I : Func->specific_attrs()) {
1141 if (I->getOwnKind() == OwnershipAttr::Returns)
1142 return true;
1143 }
1144
1145 return false;
1146}
1147
1148bool MallocChecker::isMemCall(const CallEvent &Call) const {
1149 if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
1150 AllocaMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1151 return true;
1152
1153 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1154 return false;
1155
1156 const auto *Func = dyn_cast(Call.getDecl());
1157 return Func && Func->hasAttr();
1158}
1159
1160std::optional
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1181
1182 if (!KernelZeroFlagVal) {
1183 switch (OS) {
1184 case llvm::Triple::FreeBSD:
1185 KernelZeroFlagVal = 0x0100;
1186 break;
1187 case llvm::Triple::NetBSD:
1188 KernelZeroFlagVal = 0x0002;
1189 break;
1190 case llvm::Triple::OpenBSD:
1191 KernelZeroFlagVal = 0x0008;
1192 break;
1193 case llvm::Triple::Linux:
1194
1195 KernelZeroFlagVal = 0x8000;
1196 break;
1197 default:
1198
1199
1200
1201
1202
1203 return std::nullopt;
1204 }
1205 }
1206
1207
1208
1209
1210 if (Call.getNumArgs() < 2)
1211 return std::nullopt;
1212
1213 const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
1214 const SVal V = C.getSVal(FlagsEx);
1215 if (!isa(V)) {
1216
1217
1218 return std::nullopt;
1219 }
1220
1222 NonLoc ZeroFlag = C.getSValBuilder()
1223 .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
1224 .castAs();
1225 SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
1226 Flags, ZeroFlag,
1229 return std::nullopt;
1231
1232
1234 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1235
1236
1237 if (TrueState && !FalseState) {
1238 SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
1239 return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,
1240 AllocationFamily(AF_Malloc));
1241 }
1242
1243 return std::nullopt;
1244}
1245
1247 const Expr *BlockBytes) {
1249 SVal BlocksVal = C.getSVal(Blocks);
1250 SVal BlockBytesVal = C.getSVal(BlockBytes);
1252 SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1254 return TotalSize;
1255}
1256
1257void MallocChecker::checkBasicAlloc(ProgramStateRef State,
1261 AllocationFamily(AF_Malloc));
1262 State = ProcessZeroAllocCheck(C, Call, 0, State);
1263 C.addTransition(State);
1264}
1265
1266void MallocChecker::checkKernelMalloc(ProgramStateRef State,
1269 std::optional MaybeState =
1270 performKernelMalloc(Call, C, State);
1271 if (MaybeState)
1272 State = *MaybeState;
1273 else
1275 AllocationFamily(AF_Malloc));
1276 C.addTransition(State);
1277}
1278
1280 const FunctionDecl *FD = dyn_cast(Call.getDecl());
1281 assert(FD);
1283
1287 AC.getSizeType();
1288}
1289
1291 const FunctionDecl *FD = dyn_cast(Call.getDecl());
1292 assert(FD);
1294
1298 AC.UnsignedLongTy;
1299}
1300
1303 bool ShouldFreeOnFail) const {
1304
1305
1306
1307
1308
1310 return;
1311
1312 State = ReallocMemAux(C, Call, ShouldFreeOnFail, State,
1313 AllocationFamily(AF_Malloc));
1314 State = ProcessZeroAllocCheck(C, Call, 1, State);
1315 C.addTransition(State);
1316}
1317
1320 State = CallocMem(C, Call, State);
1321 State = ProcessZeroAllocCheck(C, Call, 0, State);
1322 State = ProcessZeroAllocCheck(C, Call, 1, State);
1323 C.addTransition(State);
1324}
1325
1328 bool IsKnownToBeAllocatedMemory = false;
1329 if (suppressDeallocationsInSuspiciousContexts(Call, C))
1330 return;
1331 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1332 AllocationFamily(AF_Malloc));
1333 C.addTransition(State);
1334}
1335
1339 AllocationFamily(AF_Alloca));
1340 State = ProcessZeroAllocCheck(C, Call, 0, State);
1341 C.addTransition(State);
1342}
1343
1346 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
1347 if (!CE)
1348 return;
1350 AllocationFamily(AF_Malloc));
1351
1352 C.addTransition(State);
1353}
1354
1355void MallocChecker::checkIfNameIndex(ProgramStateRef State,
1358
1359
1361 AllocationFamily(AF_IfNameIndex));
1362
1363 C.addTransition(State);
1364}
1365
1366void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,
1369 bool IsKnownToBeAllocatedMemory = false;
1370 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1371 AllocationFamily(AF_IfNameIndex));
1372 C.addTransition(State);
1373}
1374
1375void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
1378 bool IsKnownToBeAllocatedMemory = false;
1379 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
1380 if (!CE)
1381 return;
1382
1384
1385
1386
1387
1388
1391 case OO_New:
1392 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1393 AllocationFamily(AF_CXXNew));
1394 State = ProcessZeroAllocCheck(C, Call, 0, State);
1395 break;
1396 case OO_Array_New:
1397 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1398 AllocationFamily(AF_CXXNewArray));
1399 State = ProcessZeroAllocCheck(C, Call, 0, State);
1400 break;
1401 case OO_Delete:
1402 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1403 AllocationFamily(AF_CXXNew));
1404 break;
1405 case OO_Array_Delete:
1406 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1407 AllocationFamily(AF_CXXNewArray));
1408 break;
1409 default:
1410 assert(false && "not a new/delete operator");
1411 return;
1412 }
1413
1414 C.addTransition(State);
1415}
1416
1419 SValBuilder &svalBuilder = C.getSValBuilder();
1421 State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State,
1422 AllocationFamily(AF_Malloc));
1423 State = ProcessZeroAllocCheck(C, Call, 0, State);
1424 C.addTransition(State);
1425}
1426
1430 AllocationFamily(AF_Malloc));
1431 State = ProcessZeroAllocCheck(C, Call, 1, State);
1432 C.addTransition(State);
1433}
1434
1438 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1439 State = MallocMemAux(C, Call, TotalSize, Init, State,
1440 AllocationFamily(AF_Malloc));
1441 State = ProcessZeroAllocCheck(C, Call, 0, State);
1442 State = ProcessZeroAllocCheck(C, Call, 1, State);
1443 C.addTransition(State);
1444}
1445
1450 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1451 State = MallocMemAux(C, Call, TotalSize, Init, State,
1452 AllocationFamily(AF_Malloc));
1453 State = ProcessZeroAllocCheck(C, Call, 0, State);
1454 State = ProcessZeroAllocCheck(C, Call, 1, State);
1455 C.addTransition(State);
1456}
1457
1459 const Decl *FD = Call.getDecl();
1460 assert(FD && "a CallDescription cannot match a call without a Decl");
1462}
1463
1466
1467
1469 return;
1470
1472 if (!LinePtr)
1473 return;
1474
1475
1476
1477
1478
1479 bool IsKnownToBeAllocated = false;
1480 State = FreeMemAux(C, Call.getArgExpr(0), Call, State, false,
1481 IsKnownToBeAllocated, AllocationFamily(AF_Malloc), false,
1482 LinePtr);
1483 if (State)
1484 C.addTransition(State);
1485}
1486
1489
1490
1492 return;
1493
1494
1495
1496 const CallExpr *CE = dyn_cast_or_null(Call.getOriginExpr());
1497 if (!CE)
1498 return;
1499
1500 const auto LinePtr =
1502 const auto Size =
1504 if (!LinePtr || !Size || !LinePtr->getAsRegion())
1505 return;
1506
1507 State = setDynamicExtent(State, LinePtr->getAsRegion(), *Size);
1509 AllocationFamily(AF_Malloc), *LinePtr));
1510}
1511
1514 State = ReallocMemAux(C, Call, false, State,
1515 AllocationFamily(AF_Malloc),
1516 true);
1517 State = ProcessZeroAllocCheck(C, Call, 1, State);
1518 State = ProcessZeroAllocCheck(C, Call, 2, State);
1519 C.addTransition(State);
1520}
1521
1522void MallocChecker::checkOwnershipAttr(ProgramStateRef State,
1525 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
1526 if (!CE)
1527 return;
1529 if (!FD)
1530 return;
1531 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1532 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1533
1534
1536 for (const auto *I : FD->specific_attrs()) {
1537 switch (I->getOwnKind()) {
1538 case OwnershipAttr::Returns:
1539 State = MallocMemReturnsAttr(C, Call, I, State);
1540 break;
1541 case OwnershipAttr::Takes:
1542 case OwnershipAttr::Holds:
1543 State = FreeMemAttr(C, Call, I, State);
1544 break;
1545 }
1546 }
1547 }
1548 C.addTransition(State);
1549}
1550
1552 if (.getOriginExpr())
1553 return false;
1554
1556
1557 if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
1558 (*Callback)(this, State, Call, C);
1559 return true;
1560 }
1561
1562 if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
1563 State = MallocBindRetVal(C, Call, State, false);
1564 (*Callback)(this, State, Call, C);
1565 return true;
1566 }
1567
1568 if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
1569 State = MallocBindRetVal(C, Call, State, false);
1570 (*Callback)(this, State, Call, C);
1571 return true;
1572 }
1573
1575 State = MallocBindRetVal(C, Call, State, false);
1576 checkCXXNewOrCXXDelete(State, Call, C);
1577 return true;
1578 }
1579
1581 checkCXXNewOrCXXDelete(State, Call, C);
1582 return true;
1583 }
1584
1585 if (const CheckFn *Callback = AllocaMemFnMap.lookup(Call)) {
1586 State = MallocBindRetVal(C, Call, State, true);
1587 (*Callback)(this, State, Call, C);
1588 return true;
1589 }
1590
1591 if (isFreeingOwnershipAttrCall(Call)) {
1592 checkOwnershipAttr(State, Call, C);
1593 return true;
1594 }
1595
1596 if (isAllocatingOwnershipAttrCall(Call)) {
1597 State = MallocBindRetVal(C, Call, State, false);
1598 checkOwnershipAttr(State, Call, C);
1599 return true;
1600 }
1601
1602 return false;
1603}
1604
1605
1609 if (!State)
1610 return nullptr;
1611
1612 const Expr *Arg = nullptr;
1613
1614 if (const CallExpr *CE = dyn_cast(Call.getOriginExpr())) {
1615 Arg = CE->getArg(IndexOfSizeArg);
1617 dyn_cast(Call.getOriginExpr())) {
1618 if (NE->isArray()) {
1619 Arg = *NE->getArraySize();
1620 } else {
1621 return State;
1622 }
1623 } else {
1624 assert(false && "not a CallExpr or CXXNewExpr");
1625 return nullptr;
1626 }
1627
1628 if (!RetVal)
1629 RetVal = State->getSVal(Call.getOriginExpr(), C.getLocationContext());
1630
1631 assert(Arg);
1632
1633 auto DefArgVal =
1634 State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();
1635
1636 if (!DefArgVal)
1637 return State;
1638
1639
1641 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1644
1645 std::tie(TrueState, FalseState) =
1646 State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
1647
1648 if (TrueState && !FalseState) {
1649 SymbolRef Sym = RetVal->getAsLocSymbol();
1650 if (!Sym)
1651 return State;
1652
1653 const RefState *RS = State->get(Sym);
1654 if (RS) {
1655 if (RS->isAllocated())
1656 return TrueState->set(Sym,
1657 RefState::getAllocatedOfSizeZero(RS));
1658 else
1659 return State;
1660 } else {
1661
1662
1663
1664
1665 return TrueState->add(Sym);
1666 }
1667 }
1668
1669
1670 assert(FalseState);
1671 return FalseState;
1672}
1673
1676 while (!PointeeType.isNull()) {
1677 Result = PointeeType;
1678 PointeeType = PointeeType->getPointeeType();
1679 }
1680 return Result;
1681}
1682
1683
1684
1686
1687 const CXXConstructExpr *ConstructE = NE->getConstructExpr();
1688 if (!ConstructE)
1689 return false;
1690
1691 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1692 return false;
1693
1695
1696
1697 for (const auto *CtorParam : CtorD->parameters()) {
1698
1700 if (CtorParamPointeeT.isNull())
1701 continue;
1702
1704
1706 return true;
1707 }
1708
1709 return false;
1710}
1711
1715 AllocationFamily Family) const {
1717 return nullptr;
1718
1720 const ParentMap &PM = C.getLocationContext()->getParentMap();
1722
1723
1724
1725
1726
1728 return State;
1729
1730
1731
1732
1733
1735 if (Call.getOriginExpr()->isArray()) {
1736 if (auto SizeEx = NE->getArraySize())
1737 checkTaintedness(C, Call, C.getSVal(*SizeEx), State,
1738 AllocationFamily(AF_CXXNewArray));
1739 }
1740
1742 State = ProcessZeroAllocCheck(C, Call, 0, State, Target);
1743 return State;
1744}
1745
1748 if (.wasInlined) {
1751 AllocationFamily(Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1752 : AF_CXXNew));
1753 C.addTransition(State);
1754 }
1755}
1756
1758
1759
1760
1761
1762
1763 StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
1764 return FirstSlot == "dataWithBytesNoCopy" ||
1765 FirstSlot == "initWithBytesNoCopy" ||
1766 FirstSlot == "initWithCharactersNoCopy";
1767}
1768
1771
1772
1773 for (unsigned i = 1; i < S.getNumArgs(); ++i)
1774 if (S.getNameForSlot(i) == "freeWhenDone")
1775 return .getArgSVal(i).isZeroConstant();
1776
1777 return std::nullopt;
1778}
1779
1782 if (C.wasInlined)
1783 return;
1784
1786 return;
1787
1789 if (!*FreeWhenDone)
1790 return;
1791
1792 if (Call.hasNonZeroCallbackArg())
1793 return;
1794
1795 bool IsKnownToBeAllocatedMemory;
1797 true, IsKnownToBeAllocatedMemory,
1798 AllocationFamily(AF_Malloc),
1799 true);
1800
1801 C.addTransition(State);
1802}
1803
1806 const OwnershipAttr *Att,
1808 if (!State)
1809 return nullptr;
1810
1811 auto attrClassName = Att->getModule()->getName();
1812 auto Family = AllocationFamily(AF_Custom, attrClassName);
1813
1814 if (!Att->args().empty()) {
1815 return MallocMemAux(C, Call,
1816 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1818 }
1820}
1821
1825 bool isAlloca) const {
1826 const Expr *CE = Call.getOriginExpr();
1827
1828
1830 return nullptr;
1831
1832 unsigned Count = C.blockCount();
1834 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1837 return State->BindExpr(CE, C.getLocationContext(), RetVal);
1838}
1839
1844 AllocationFamily Family) const {
1845 if (!State)
1846 return nullptr;
1847
1848 assert(SizeEx);
1849 return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);
1850}
1851
1852void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,
1855 AllocationFamily Family) const {
1856 if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) {
1857 if (!BT_TaintedAlloc)
1858 BT_TaintedAlloc.reset(new BugType(CheckNames[CK_TaintedAllocChecker],
1859 "Tainted Memory Allocation",
1861 auto R = std::make_unique(*BT_TaintedAlloc, Msg, N);
1862 for (auto TaintedSym : TaintedSyms) {
1863 R->markInteresting(TaintedSym);
1864 }
1865 C.emitReport(std::move(R));
1866 }
1867}
1868
1871 AllocationFamily Family) const {
1872 if (!ChecksEnabled[CK_TaintedAllocChecker])
1873 return;
1874 std::vector TaintedSyms =
1876 if (TaintedSyms.empty())
1877 return;
1878
1882
1883
1885 const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy);
1888 std::optional SizeNL = SizeSVal.getAs<NonLoc>();
1889 auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
1891 if (!Cmp)
1892 return;
1893 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
1894 if (!StateTooLarge && StateNotTooLarge) {
1895
1896 return;
1897 }
1898
1899 std::string Callee = "Memory allocation function";
1900 if (Call.getCalleeIdentifier())
1901 Callee = Call.getCalleeIdentifier()->getName().str();
1902 reportTaintBug(
1903 Callee + " is called with a tainted (potentially attacker controlled) "
1904 "value. Make sure the value is bound checked.",
1905 State, C, TaintedSyms, Family);
1906}
1907
1911 AllocationFamily Family) const {
1912 if (!State)
1913 return nullptr;
1914
1915 const Expr *CE = Call.getOriginExpr();
1916
1917
1918
1920 "Allocation functions must return a pointer");
1921
1922 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1923 SVal RetVal = State->getSVal(CE, C.getLocationContext());
1924
1925
1926 State = State->bindDefaultInitial(RetVal, Init, LCtx);
1927
1928
1929 if (Size.isUndef())
1931
1932 checkTaintedness(C, Call, Size, State, AllocationFamily(AF_Malloc));
1933
1934
1937
1939}
1940
1943 AllocationFamily Family,
1944 std::optional RetVal) {
1945 if (!State)
1946 return nullptr;
1947
1948
1949 if (!RetVal)
1950 RetVal = State->getSVal(E, C.getLocationContext());
1951
1952
1953 if (!RetVal->getAs<Loc>())
1954 return nullptr;
1955
1956 SymbolRef Sym = RetVal->getAsLocSymbol();
1957
1958
1959
1960
1961
1962
1963 if (Sym)
1964 return State->set(Sym, RefState::getAllocated(Family, E));
1965
1966 return State;
1967}
1968
1971 const OwnershipAttr *Att,
1973 if (!State)
1974 return nullptr;
1975
1976 auto attrClassName = Att->getModule()->getName();
1977 auto Family = AllocationFamily(AF_Custom, attrClassName);
1978
1979 bool IsKnownToBeAllocated = false;
1980
1981 for (const auto &Arg : Att->args()) {
1983 FreeMemAux(C, Call, State, Arg.getASTIndex(),
1984 Att->getOwnKind() == OwnershipAttr::Holds,
1985 IsKnownToBeAllocated, Family);
1986 if (StateI)
1987 State = StateI;
1988 }
1989 return State;
1990}
1991
1995 bool Hold, bool &IsKnownToBeAllocated,
1996 AllocationFamily Family,
1997 bool ReturnsNullOnFailure) const {
1998 if (!State)
1999 return nullptr;
2000
2001 if (Call.getNumArgs() < (Num + 1))
2002 return nullptr;
2003
2004 return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,
2005 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2006}
2007
2008
2009
2012 const SymbolRef *Ret = State->get(Sym);
2013 if (Ret) {
2014 assert(*Ret && "We should not store the null return symbol");
2017 RetStatusSymbol = *Ret;
2019 }
2020 return false;
2021}
2022
2025 const CallExpr *CE = dyn_cast(E);
2026
2027 if (!CE)
2028 return;
2029
2031 if (!FD)
2032 return;
2033
2034
2035 for (const auto *I : FD->specific_attrs()) {
2036 if (I->getOwnKind() != OwnershipAttr::Takes)
2037 continue;
2038
2039 os << ", which takes ownership of '" << I->getModule()->getName() << '\'';
2040 break;
2041 }
2042}
2043
2045 if (const CallExpr *CE = dyn_cast(E)) {
2046
2047 const FunctionDecl *FD = CE->getDirectCallee();
2048 if (!FD)
2049 return false;
2050
2051 os << '\'' << *FD;
2052
2054 os << "()";
2055
2056 os << '\'';
2057 return true;
2058 }
2059
2060 if (const ObjCMessageExpr *Msg = dyn_cast(E)) {
2061 if (Msg->isInstanceMessage())
2062 os << "-";
2063 else
2064 os << "+";
2065 Msg->getSelector().print(os);
2066 return true;
2067 }
2068
2069 if (const CXXNewExpr *NE = dyn_cast(E)) {
2070 os << "'"
2072 << "'";
2073 return true;
2074 }
2075
2076 if (const CXXDeleteExpr *DE = dyn_cast(E)) {
2077 os << "'"
2078 << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
2079 << "'";
2080 return true;
2081 }
2082
2083 return false;
2084}
2085
2087
2088 switch (Family.Kind) {
2089 case AF_Malloc:
2090 os << "'malloc()'";
2091 return;
2092 case AF_CXXNew:
2093 os << "'new'";
2094 return;
2095 case AF_CXXNewArray:
2096 os << "'new[]'";
2097 return;
2098 case AF_IfNameIndex:
2099 os << "'if_nameindex()'";
2100 return;
2101 case AF_InnerBuffer:
2102 os << "container-specific allocator";
2103 return;
2104 case AF_Custom:
2105 os << Family.CustomName.value();
2106 return;
2107 case AF_Alloca:
2108 case AF_None:
2109 assert(false && "not a deallocation expression");
2110 }
2111}
2112
2114 switch (Family.Kind) {
2115 case AF_Malloc:
2116 os << "'free()'";
2117 return;
2118 case AF_CXXNew:
2119 os << "'delete'";
2120 return;
2121 case AF_CXXNewArray:
2122 os << "'delete[]'";
2123 return;
2124 case AF_IfNameIndex:
2125 os << "'if_freenameindex()'";
2126 return;
2127 case AF_InnerBuffer:
2128 os << "container-specific deallocator";
2129 return;
2130 case AF_Custom:
2131 os << "function that takes ownership of '" << Family.CustomName.value()
2132 << "\'";
2133 return;
2134 case AF_Alloca:
2135 case AF_None:
2136 assert(false && "not a deallocation expression");
2137 }
2138}
2139
2143 bool Hold, bool &IsKnownToBeAllocated,
2144 AllocationFamily Family, bool ReturnsNullOnFailure,
2145 std::optional ArgValOpt) const {
2146
2147 if (!State)
2148 return nullptr;
2149
2150 SVal ArgVal = ArgValOpt.value_or(C.getSVal(ArgExpr));
2151 if (!isa(ArgVal))
2152 return nullptr;
2154
2155
2156 if (!isa(location))
2157 return nullptr;
2158
2159
2161 std::tie(notNullState, nullState) = State->assume(location);
2162 if (nullState && !notNullState)
2163 return nullptr;
2164
2165
2166
2168 return nullptr;
2169
2171 const Expr *ParentExpr = Call.getOriginExpr();
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184 if (!R) {
2185
2186
2187
2188
2189
2190 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))
2191 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2192 Family);
2193 return nullptr;
2194 }
2195
2197
2198
2199 if (isa(R)) {
2200 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2201 Family);
2202 return nullptr;
2203 }
2204
2206
2207
2208
2209 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
2210
2211
2212
2213
2214
2215 if (isa(R))
2217 else
2218 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2219 Family);
2220
2221 return nullptr;
2222 }
2223
2225
2226
2227 if (!SrBase)
2228 return nullptr;
2229
2231 const RefState *RsBase = State->get(SymBase);
2232 SymbolRef PreviousRetStatusSymbol = nullptr;
2233
2234 IsKnownToBeAllocated =
2235 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2236
2237 if (RsBase) {
2238
2239
2240 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2242 return nullptr;
2243 }
2244
2245
2246 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2248 HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
2249 SymBase, PreviousRetStatusSymbol);
2250 return nullptr;
2251
2252
2253
2254 } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2255 RsBase->isEscaped()) {
2256
2257
2258 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2259 if (!DeallocMatchesAlloc) {
2260 HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,
2261 RsBase, SymBase, Hold);
2262 return nullptr;
2263 }
2264
2265
2266
2268 if (Offset.isValid() &&
2269 !Offset.hasSymbolicOffset() &&
2270 Offset.getOffset() != 0) {
2271 const Expr *AllocExpr = cast(RsBase->getStmt());
2272 HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2273 Family, AllocExpr);
2274 return nullptr;
2275 }
2276 }
2277 }
2278
2280 HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2281 Family);
2282 return nullptr;
2283 }
2284
2285
2286 State = State->remove(SymBase);
2287
2288
2289
2290 if (ReturnsNullOnFailure) {
2291 SVal RetVal = C.getSVal(ParentExpr);
2293 if (RetStatusSymbol) {
2294 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2295 State = State->set(SymBase, RetStatusSymbol);
2296 }
2297 }
2298
2299
2300
2301
2302
2303 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2304
2305
2306
2307
2308 State = State->invalidateRegions({location}, Call.getOriginExpr(),
2309 C.blockCount(), C.getLocationContext(),
2310 false,
2311 nullptr);
2312
2313
2314 if (Hold)
2315 return State->set(SymBase,
2316 RefState::getRelinquished(Family,
2317 ParentExpr));
2318
2319 return State->set(SymBase,
2320 RefState::getReleased(Family, ParentExpr));
2321}
2322
2323std::optionalMallocChecker::CheckKind
2324MallocChecker::getCheckIfTracked(AllocationFamily Family,
2325 bool IsALeakCheck) const {
2326 switch (Family.Kind) {
2327 case AF_Malloc:
2328 case AF_Alloca:
2329 case AF_Custom:
2330 case AF_IfNameIndex: {
2331 if (ChecksEnabled[CK_MallocChecker])
2332 return CK_MallocChecker;
2333 return std::nullopt;
2334 }
2335 case AF_CXXNew:
2336 case AF_CXXNewArray: {
2337 if (IsALeakCheck) {
2338 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2339 return CK_NewDeleteLeaksChecker;
2340 }
2341 else {
2342 if (ChecksEnabled[CK_NewDeleteChecker])
2343 return CK_NewDeleteChecker;
2344 }
2345 return std::nullopt;
2346 }
2347 case AF_InnerBuffer: {
2348 if (ChecksEnabled[CK_InnerPointerChecker])
2349 return CK_InnerPointerChecker;
2350 return std::nullopt;
2351 }
2352 case AF_None: {
2353 assert(false && "no family");
2354 return std::nullopt;
2355 }
2356 }
2357 assert(false && "unhandled family");
2358 return std::nullopt;
2359}
2360
2361std::optionalMallocChecker::CheckKind
2363 bool IsALeakCheck) const {
2364 if (C.getState()->contains(Sym))
2365 return CK_MallocChecker;
2366
2367 const RefState *RS = C.getState()->get(Sym);
2368 assert(RS);
2369 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2370}
2371
2372bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
2373 if (std::optionalnonloc::ConcreteInt IntVal =
2375 os << "an integer (" << IntVal->getValue() << ")";
2376 else if (std::optionalloc::ConcreteInt ConstAddr =
2378 os << "a constant address (" << ConstAddr->getValue() << ")";
2380 os << "the address of the label '" << Label->getLabel()->getName() << "'";
2381 else
2382 return false;
2383
2384 return true;
2385}
2386
2387bool MallocChecker::SummarizeRegion(raw_ostream &os,
2389 switch (MR->getKind()) {
2390 case MemRegion::FunctionCodeRegionKind: {
2391 const NamedDecl *FD = cast(MR)->getDecl();
2392 if (FD)
2393 os << "the address of the function '" << *FD << '\'';
2394 else
2395 os << "the address of a function";
2396 return true;
2397 }
2398 case MemRegion::BlockCodeRegionKind:
2399 os << "block text";
2400 return true;
2401 case MemRegion::BlockDataRegionKind:
2402
2403 os << "a block";
2404 return true;
2405 default: {
2407
2408 if (isa(MS)) {
2409 const VarRegion *VR = dyn_cast(MR);
2411 if (VR)
2413 else
2414 VD = nullptr;
2415
2416 if (VD)
2417 os << "the address of the local variable '" << VD->getName() << "'";
2418 else
2419 os << "the address of a local stack variable";
2420 return true;
2421 }
2422
2423 if (isa(MS)) {
2424 const VarRegion *VR = dyn_cast(MR);
2426 if (VR)
2428 else
2429 VD = nullptr;
2430
2431 if (VD)
2432 os << "the address of the parameter '" << VD->getName() << "'";
2433 else
2434 os << "the address of a parameter";
2435 return true;
2436 }
2437
2438 if (isa(MS)) {
2439 const VarRegion *VR = dyn_cast(MR);
2441 if (VR)
2443 else
2444 VD = nullptr;
2445
2446 if (VD) {
2448 os << "the address of the static variable '" << VD->getName() << "'";
2449 else
2450 os << "the address of the global variable '" << VD->getName() << "'";
2451 } else
2452 os << "the address of a global variable";
2453 return true;
2454 }
2455
2456 return false;
2457 }
2458 }
2459}
2460
2463 const Expr *DeallocExpr,
2464 AllocationFamily Family) const {
2465
2466 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2467 C.addSink();
2468 return;
2469 }
2470
2471 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(Family);
2472 if (!CheckKind)
2473 return;
2474
2476 if (!BT_BadFree[*CheckKind])
2477 BT_BadFree[*CheckKind].reset(new BugType(
2479
2481 llvm::raw_svector_ostream os(buf);
2482
2484 while (const ElementRegion *ER = dyn_cast_or_null(MR))
2485 MR = ER->getSuperRegion();
2486
2487 os << "Argument to ";
2489 os << "deallocator";
2490
2491 os << " is ";
2492 bool Summarized = MR ? SummarizeRegion(os, MR)
2493 : SummarizeValue(os, ArgVal);
2494 if (Summarized)
2495 os << ", which is not memory allocated by ";
2496 else
2497 os << "not memory allocated by ";
2498
2500
2501 auto R = std::make_unique(*BT_BadFree[*CheckKind],
2502 os.str(), N);
2503 R->markInteresting(MR);
2504 R->addRange(Range);
2505 C.emitReport(std::move(R));
2506 }
2507}
2508
2511
2512 std::optionalMallocChecker::CheckKind CheckKind;
2513
2514 if (ChecksEnabled[CK_MallocChecker])
2515 CheckKind = CK_MallocChecker;
2516 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2517 CheckKind = CK_MismatchedDeallocatorChecker;
2518 else {
2519 C.addSink();
2520 return;
2521 }
2522
2524 if (!BT_FreeAlloca[*CheckKind])
2525 BT_FreeAlloca[*CheckKind].reset(new BugType(
2527
2528 auto R = std::make_unique(
2529 *BT_FreeAlloca[*CheckKind],
2530 "Memory allocated by 'alloca()' should not be deallocated", N);
2531 R->markInteresting(ArgVal.getAsRegion());
2532 R->addRange(Range);
2533 C.emitReport(std::move(R));
2534 }
2535}
2536
2537void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
2539 const Expr *DeallocExpr,
2540 const RefState *RS, SymbolRef Sym,
2541 bool OwnershipTransferred) const {
2542
2543 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2544 C.addSink();
2545 return;
2546 }
2547
2549 if (!BT_MismatchedDealloc)
2550 BT_MismatchedDealloc.reset(
2551 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2553
2555 llvm::raw_svector_ostream os(buf);
2556
2557 const Expr *AllocExpr = cast(RS->getStmt());
2559 llvm::raw_svector_ostream AllocOs(AllocBuf);
2561 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2562
2563 if (OwnershipTransferred) {
2565 os << DeallocOs.str() << " cannot";
2566 else
2567 os << "Cannot";
2568
2569 os << " take ownership of memory";
2570
2572 os << " allocated by " << AllocOs.str();
2573 } else {
2574 os << "Memory";
2576 os << " allocated by " << AllocOs.str();
2577
2578 os << " should be deallocated by ";
2580
2582 os << ", not " << DeallocOs.str();
2583
2585 }
2586
2587 auto R = std::make_unique(*BT_MismatchedDealloc,
2588 os.str(), N);
2589 R->markInteresting(Sym);
2590 R->addRange(Range);
2591 R->addVisitor(Sym);
2592 C.emitReport(std::move(R));
2593 }
2594}
2595
2598 AllocationFamily Family,
2599 const Expr *AllocExpr) const {
2600
2601 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2602 C.addSink();
2603 return;
2604 }
2605
2606 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(Family);
2607 if (!CheckKind)
2608 return;
2609
2611 if (!N)
2612 return;
2613
2614 if (!BT_OffsetFree[*CheckKind])
2615 BT_OffsetFree[*CheckKind].reset(new BugType(
2617
2619 llvm::raw_svector_ostream os(buf);
2621 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2622
2624 assert(MR && "Only MemRegion based symbols can have offset free errors");
2625
2627 assert((Offset.isValid() &&
2628 !Offset.hasSymbolicOffset() &&
2629 Offset.getOffset() != 0) &&
2630 "Only symbols with a valid offset can have offset free errors");
2631
2632 int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
2633
2634 os << "Argument to ";
2636 os << "deallocator";
2637 os << " is offset by "
2638 << offsetBytes
2639 << " "
2640 << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
2641 << " from the start of ";
2642 if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
2643 os << "memory allocated by " << AllocNameOs.str();
2644 else
2645 os << "allocated memory";
2646
2647 auto R = std::make_unique(*BT_OffsetFree[*CheckKind],
2648 os.str(), N);
2650 R->addRange(Range);
2651 C.emitReport(std::move(R));
2652}
2653
2656
2657 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2658 !ChecksEnabled[CK_InnerPointerChecker]) {
2659 C.addSink();
2660 return;
2661 }
2662
2663 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);
2664 if (!CheckKind)
2665 return;
2666
2668 if (!BT_UseFree[*CheckKind])
2669 BT_UseFree[*CheckKind].reset(new BugType(
2671
2672 AllocationFamily AF =
2673 C.getState()->get(Sym)->getAllocationFamily();
2674
2675 auto R = std::make_unique(
2676 *BT_UseFree[*CheckKind],
2677 AF.Kind == AF_InnerBuffer
2678 ? "Inner pointer of container used after re/deallocation"
2679 : "Use of memory after it is freed",
2680 N);
2681
2682 R->markInteresting(Sym);
2683 R->addRange(Range);
2684 R->addVisitor(Sym);
2685
2686 if (AF.Kind == AF_InnerBuffer)
2688
2689 C.emitReport(std::move(R));
2690 }
2691}
2692
2696
2697 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2698 C.addSink();
2699 return;
2700 }
2701
2702 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);
2703 if (!CheckKind)
2704 return;
2705
2707 if (!BT_DoubleFree[*CheckKind])
2708 BT_DoubleFree[*CheckKind].reset(new BugType(
2710
2711 auto R = std::make_unique(
2712 *BT_DoubleFree[*CheckKind],
2713 (Released ? "Attempt to free released memory"
2714 : "Attempt to free non-owned memory"),
2715 N);
2716 R->addRange(Range);
2717 R->markInteresting(Sym);
2718 if (PrevSym)
2719 R->markInteresting(PrevSym);
2720 R->addVisitor(Sym);
2721 C.emitReport(std::move(R));
2722 }
2723}
2724
2726
2727 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2728 C.addSink();
2729 return;
2730 }
2731
2732 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);
2733 if (!CheckKind)
2734 return;
2735
2737 if (!BT_DoubleDelete)
2738 BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
2739 "Double delete",
2741
2742 auto R = std::make_unique(
2743 *BT_DoubleDelete, "Attempt to delete released memory", N);
2744
2745 R->markInteresting(Sym);
2746 R->addVisitor(Sym);
2747 C.emitReport(std::move(R));
2748 }
2749}
2750
2753
2754 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2755 C.addSink();
2756 return;
2757 }
2758
2759 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);
2760
2761 if (!CheckKind)
2762 return;
2763
2765 if (!BT_UseZerroAllocated[*CheckKind])
2766 BT_UseZerroAllocated[*CheckKind].reset(
2767 new BugType(CheckNames[*CheckKind], "Use of zero allocated",
2769
2770 auto R = std::make_unique(
2771 *BT_UseZerroAllocated[*CheckKind],
2772 "Use of memory allocated with size zero", N);
2773
2774 R->addRange(Range);
2775 if (Sym) {
2776 R->markInteresting(Sym);
2777 R->addVisitor(Sym);
2778 }
2779 C.emitReport(std::move(R));
2780 }
2781}
2782
2783void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
2785 const Expr *FreeExpr,
2786 AllocationFamily Family) const {
2787 if (!ChecksEnabled[CK_MallocChecker]) {
2788 C.addSink();
2789 return;
2790 }
2791
2792 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(Family);
2793 if (!CheckKind)
2794 return;
2795
2797 if (!BT_BadFree[*CheckKind])
2798 BT_BadFree[*CheckKind].reset(new BugType(
2800
2802 llvm::raw_svector_ostream Os(Buf);
2803
2805 while (const ElementRegion *ER = dyn_cast_or_null(MR))
2806 MR = ER->getSuperRegion();
2807
2808 Os << "Argument to ";
2810 Os << "deallocator";
2811
2812 Os << " is a function pointer";
2813
2814 auto R = std::make_unique(*BT_BadFree[*CheckKind],
2815 Os.str(), N);
2816 R->markInteresting(MR);
2817 R->addRange(Range);
2818 C.emitReport(std::move(R));
2819 }
2820}
2821
2825 AllocationFamily Family, bool SuffixWithN) const {
2826 if (!State)
2827 return nullptr;
2828
2829 const CallExpr *CE = cast(Call.getOriginExpr());
2830
2831 if (SuffixWithN && CE->getNumArgs() < 3)
2832 return nullptr;
2834 return nullptr;
2835
2836 const Expr *arg0Expr = CE->getArg(0);
2837 SVal Arg0Val = C.getSVal(arg0Expr);
2838 if (!isa(Arg0Val))
2839 return nullptr;
2841
2842 SValBuilder &svalBuilder = C.getSValBuilder();
2843
2845 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));
2846
2847
2849
2850
2851 SVal TotalSize = C.getSVal(Arg1);
2852 if (SuffixWithN)
2853 TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
2854 if (!isa(TotalSize))
2855 return nullptr;
2856
2857
2860 svalBuilder.makeIntValWithWidth(
2861 svalBuilder.getContext().getSizeType(), 0));
2862
2864 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2866 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2867
2868
2869 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2870 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2871
2872
2873
2874 if (PrtIsNull && !SizeIsZero) {
2877 return stateMalloc;
2878 }
2879
2880
2881 if (PrtIsNull && SizeIsZero)
2882 return State;
2883
2884 assert(!PrtIsNull);
2885
2886 bool IsKnownToBeAllocated = false;
2887
2888
2889 if (SizeIsZero)
2890
2891
2892
2893
2895 C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))
2896 return stateFree;
2897
2898
2900 FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {
2901
2903 MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);
2904 if (!stateRealloc)
2905 return nullptr;
2906
2907 OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
2908 if (ShouldFreeOnFail)
2909 Kind = OAR_FreeOnFailure;
2910 else if (!IsKnownToBeAllocated)
2911 Kind = OAR_DoNotTrackAfterFailure;
2912
2913
2915 SVal RetVal = stateRealloc->getSVal(CE, C.getLocationContext());
2917 assert(FromPtr && ToPtr &&
2918 "By this point, FreeMemAux and MallocMemAux should have checked "
2919 "whether the argument or the return value is symbolic!");
2920
2921
2922
2923 stateRealloc = stateRealloc->set(ToPtr,
2924 ReallocPair(FromPtr, Kind));
2925
2926 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2927 return stateRealloc;
2928 }
2929 return nullptr;
2930}
2931
2935 if (!State)
2936 return nullptr;
2937
2938 if (Call.getNumArgs() < 2)
2939 return nullptr;
2940
2941 SValBuilder &svalBuilder = C.getSValBuilder();
2943 SVal TotalSize =
2944 evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
2945
2946 return MallocMemAux(C, Call, TotalSize, zeroVal, State,
2947 AllocationFamily(AF_Malloc));
2948}
2949
2950MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
2954
2955
2957 const MemRegion *ReferenceRegion = nullptr;
2958
2959 while (N) {
2961 if (!State->get(Sym))
2962 break;
2963
2964
2965
2966 if (!ReferenceRegion) {
2967 if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
2968 SVal Val = State->getSVal(MR);
2971
2972
2974 ReferenceRegion = MR;
2975 }
2976 }
2977 }
2978
2979
2980
2982 if (NContext == LeakContext ||
2984 AllocNode = N;
2986 }
2987
2988 return LeakInfo(AllocNode, ReferenceRegion);
2989}
2990
2993
2994 if (!ChecksEnabled[CK_MallocChecker] &&
2995 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2996 return;
2997
2998 const RefState *RS = C.getState()->get(Sym);
2999 assert(RS && "cannot leak an untracked symbol");
3000 AllocationFamily Family = RS->getAllocationFamily();
3001
3002 if (Family.Kind == AF_Alloca)
3003 return;
3004
3005 std::optionalMallocChecker::CheckKind CheckKind =
3006 getCheckIfTracked(Family, true);
3007
3008 if (!CheckKind)
3009 return;
3010
3011 assert(N);
3012 if (!BT_Leak[*CheckKind]) {
3013
3014
3015
3016
3017
3018 BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
3020 true));
3021 }
3022
3023
3024
3025
3028 const MemRegion *Region = nullptr;
3029 std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
3030
3032 if (AllocationStmt)
3034 C.getSourceManager(),
3036
3038 llvm::raw_svector_ostream os(buf);
3040 os << "Potential leak of memory pointed to by ";
3042 } else {
3043 os << "Potential memory leak";
3044 }
3045
3046 auto R = std::make_unique(
3047 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
3049 R->markInteresting(Sym);
3050 R->addVisitor(Sym, true);
3051 if (ShouldRegisterNoOwnershipChangeVisitor)
3052 R->addVisitor(Sym, this);
3053 C.emitReport(std::move(R));
3054}
3055
3056void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3058{
3060 RegionStateTy OldRS = state->get();
3061 RegionStateTy::Factory &F = state->get_context();
3062
3063 RegionStateTy RS = OldRS;
3065 for (auto [Sym, State] : RS) {
3066 if (SymReaper.isDead(Sym)) {
3067 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3068 Errors.push_back(Sym);
3069
3070 RS = F.remove(RS, Sym);
3071 }
3072 }
3073
3074 if (RS == OldRS) {
3075
3076 assert(state->get() ==
3077 C.getState()->get());
3078 assert(state->get() ==
3079 C.getState()->get());
3080 return;
3081 }
3082
3083
3084 ReallocPairsTy RP = state->get();
3085 for (auto [Sym, ReallocPair] : RP) {
3086 if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {
3087 state = state->remove(Sym);
3088 }
3089 }
3090
3091
3092 FreeReturnValueTy FR = state->get();
3093 for (auto [Sym, RetSym] : FR) {
3094 if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {
3095 state = state->remove(Sym);
3096 }
3097 }
3098
3099
3101 if (!Errors.empty()) {
3103 N = C.generateNonFatalErrorNode(C.getState(), &Tag);
3104 if (N) {
3106 HandleLeak(Sym, N, C);
3107 }
3108 }
3109 }
3110
3111 C.addTransition(state->set(RS), N);
3112}
3113
3114void MallocChecker::checkPostCall(const CallEvent &Call,
3116 if (const auto *PostFN = PostFnMap.lookup(Call)) {
3117 (*PostFN)(this, C.getState(), Call, C);
3118 return;
3119 }
3120}
3121
3122void MallocChecker::checkPreCall(const CallEvent &Call,
3124
3125 if (const auto *DC = dyn_cast(&Call)) {
3127
3128 if (!ChecksEnabled[CK_NewDeleteChecker])
3130 checkUseAfterFree(Sym, C, DE->getArgument());
3131
3133 return;
3134
3136 bool IsKnownToBeAllocated;
3137 State = FreeMemAux(
3139 false, IsKnownToBeAllocated,
3140 AllocationFamily(DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3141
3142 C.addTransition(State);
3143 return;
3144 }
3145
3146 if (const auto *DC = dyn_cast(&Call)) {
3147 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3148 if (!Sym || checkDoubleDelete(Sym, C))
3149 return;
3150 }
3151
3152
3153
3154 if (const auto *PreFN = PreFnMap.lookup(Call)) {
3155 (*PreFN)(this, C.getState(), Call, C);
3156 return;
3157 }
3158
3159
3162 if (!FD)
3163 return;
3164
3165 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call))
3166 return;
3167 }
3168
3169
3171 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3172 if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))
3173 return;
3174 }
3175
3176
3177 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3178 SVal ArgSVal = Call.getArgSVal(I);
3179 if (isa(ArgSVal)) {
3181 if (!Sym)
3182 continue;
3183 if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
3184 return;
3185 }
3186 }
3187}
3188
3189void MallocChecker::checkPreStmt(const ReturnStmt *S,
3191 checkEscapeOnReturn(S, C);
3192}
3193
3194
3195
3196
3197void MallocChecker::checkEndFunction(const ReturnStmt *S,
3199 checkEscapeOnReturn(S, C);
3200}
3201
3202void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
3204 if (!S)
3205 return;
3206
3207 const Expr *E = S->getRetValue();
3208 if ()
3209 return;
3210
3211
3213 SVal RetVal = C.getSVal(E);
3215 if (!Sym)
3216
3217
3218
3220 if (isa<FieldRegion, ElementRegion>(MR))
3223 Sym = BMR->getSymbol();
3224
3225
3226 if (Sym)
3227 checkUseAfterFree(Sym, C, E);
3228}
3229
3230
3231
3232
3233void MallocChecker::checkPostStmt(const BlockExpr *BE,
3235
3236
3237
3239 return;
3240
3243 cast(C.getSVal(BE).getAsRegion());
3244
3246 if (ReferencedVars.empty())
3247 return;
3248
3251 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
3252
3253 for (const auto &Var : ReferencedVars) {
3254 const VarRegion *VR = Var.getCapturedRegion();
3257 }
3258 Regions.push_back(VR);
3259 }
3260
3261 state =
3262 state->scanReachableSymbols(Regions).getState();
3263 C.addTransition(state);
3264}
3265
3267 assert(Sym);
3268 const RefState *RS = C.getState()->get(Sym);
3269 return (RS && RS->isReleased());
3270}
3271
3272bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3274 if (Call.getNumArgs() == 0)
3275 return false;
3276
3277 StringRef FunctionStr = "";
3278 if (const auto *FD = dyn_cast(C.getStackFrame()->getDecl()))
3280 if (Body->getBeginLoc().isValid())
3281 FunctionStr =
3283 {FD->getBeginLoc(), Body->getBeginLoc()}),
3284 C.getSourceManager(), C.getLangOpts());
3285
3286
3287 if (!FunctionStr.contains("__isl_"))
3288 return false;
3289
3291
3292 for (const Expr *Arg : cast(Call.getOriginExpr())->arguments())
3293 if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())
3294 if (const RefState *RS = State->get(Sym))
3295 State = State->set(Sym, RefState::getEscaped(RS));
3296
3297 C.addTransition(State);
3298 return true;
3299}
3300
3302 const Stmt *S) const {
3303
3305 HandleUseAfterFree(C, S->getSourceRange(), Sym);
3306 return true;
3307 }
3308
3309 return false;
3310}
3311
3313 const Stmt *S) const {
3314 assert(Sym);
3315
3316 if (const RefState *RS = C.getState()->get(Sym)) {
3317 if (RS->isAllocatedOfSizeZero())
3318 HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
3319 }
3320 else if (C.getState()->contains(Sym)) {
3321 HandleUseZeroAlloc(C, S->getSourceRange(), Sym);
3322 }
3323}
3324
3326
3328 HandleDoubleDelete(C, Sym);
3329 return true;
3330 }
3331 return false;
3332}
3333
3334
3335void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
3338 if (Sym) {
3339 checkUseAfterFree(Sym, C, S);
3340 checkUseZeroAllocated(Sym, C, S);
3341 }
3342}
3343
3344
3345
3348 bool Assumption) const {
3349 RegionStateTy RS = state->get();
3350 for (SymbolRef Sym : llvm::make_first_range(RS)) {
3351
3355 state = state->remove(Sym);
3356 }
3357
3358
3359
3360 ReallocPairsTy RP = state->get();
3361 for (auto [Sym, ReallocPair] : RP) {
3362
3366 continue;
3367
3368 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3369 if (const RefState *RS = state->get(ReallocSym)) {
3370 if (RS->isReleased()) {
3371 switch (ReallocPair.Kind) {
3372 case OAR_ToBeFreedAfterFailure:
3373 state = state->set(ReallocSym,
3374 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3375 break;
3376 case OAR_DoNotTrackAfterFailure:
3377 state = state->remove(ReallocSym);
3378 break;
3379 default:
3380 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3381 }
3382 }
3383 }
3384 state = state->remove(Sym);
3385 }
3386
3387 return state;
3388}
3389
3390bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3393 SymbolRef &EscapingSymbol) const {
3394 assert(Call);
3395 EscapingSymbol = nullptr;
3396
3397
3398
3399
3400
3401 if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))
3402 return true;
3403
3404
3406
3407
3408 if (->isInSystemHeader() || Call->argumentsMayEscape())
3409 return true;
3410
3411
3412
3414 return false;
3415
3416
3417
3418
3419
3421 return *FreeWhenDone;
3422
3423
3424
3425
3426
3427 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3428 if (FirstSlot.ends_with("NoCopy"))
3429 return true;
3430
3431
3432
3433
3434
3435 if (FirstSlot.starts_with("addPointer") ||
3436 FirstSlot.starts_with("insertPointer") ||
3437 FirstSlot.starts_with("replacePointer") ||
3438 FirstSlot == "valueWithPointer") {
3439 return true;
3440 }
3441
3442
3443
3444
3445 if (Msg->getMethodFamily() == OMF_init) {
3446 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3447 return true;
3448 }
3449
3450
3451
3452 return false;
3453 }
3454
3455
3456 const FunctionDecl *FD = cast(Call)->getDecl();
3457 if (!FD)
3458 return true;
3459
3460
3461
3462 if (isMemCall(*Call))
3463 return false;
3464
3465
3466 if (->isInSystemHeader())
3467 return true;
3468
3469
3471 if (!II)
3472 return true;
3473 StringRef FName = II->getName();
3474
3475
3476
3477 if (FName.ends_with("NoCopy")) {
3478
3479
3480
3481 for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
3482 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
3483 if (const DeclRefExpr *DE = dyn_cast(ArgE)) {
3484 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3485 if (DeallocatorName == "kCFAllocatorNull")
3486 return false;
3487 }
3488 }
3489 return true;
3490 }
3491
3492
3493
3494
3495
3496 if (FName == "funopen")
3497 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
3498 return false;
3499
3500
3501
3502
3503 if (FName == "setbuf" || FName =="setbuffer" ||
3504 FName == "setlinebuf" || FName == "setvbuf") {
3505 if (Call->getNumArgs() >= 1) {
3506 const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
3507 if (const DeclRefExpr *ArgDRE = dyn_cast(ArgE))
3508 if (const VarDecl *D = dyn_cast(ArgDRE->getDecl()))
3510 return true;
3511 }
3512 }
3513
3514
3515
3516
3517
3518
3519 if (FName == "CGBitmapContextCreate" ||
3520 FName == "CGBitmapContextCreateWithData" ||
3521 FName == "CVPixelBufferCreateWithBytes" ||
3522 FName == "CVPixelBufferCreateWithPlanarBytes" ||
3523 FName == "OSAtomicEnqueue") {
3524 return true;
3525 }
3526
3527 if (FName == "postEvent" &&
3529 return true;
3530 }
3531
3532 if (FName == "connectImpl" &&
3534 return true;
3535 }
3536
3537 if (FName == "singleShotImpl" &&
3539 return true;
3540 }
3541
3542
3543
3544
3545
3546 if (Call->argumentsMayEscape())
3547 return true;
3548
3549
3550
3551 return false;
3552}
3553
3558 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3559 false);
3560}
3561
3566
3567 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3568 true);
3569}
3570
3572 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3573 RS->getAllocationFamily().Kind == AF_CXXNew);
3574}
3575
3579 bool IsConstPointerEscape) const {
3580
3581
3582 SymbolRef EscapingSymbol = nullptr;
3584 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3585 EscapingSymbol) &&
3586 !EscapingSymbol) {
3587 return State;
3588 }
3589
3591 if (EscapingSymbol && EscapingSymbol != sym)
3592 continue;
3593
3594 if (const RefState *RS = State->get(sym))
3595 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3597 State = State->set(sym, RefState::getEscaped(RS));
3598 }
3599 return State;
3600}
3601
3603 SVal ArgVal) const {
3604 if (!KernelZeroSizePtrValue)
3605 KernelZeroSizePtrValue =
3607
3608 const llvm::APSInt *ArgValKnown =
3609 C.getSValBuilder().getKnownValue(State, ArgVal);
3610 return ArgValKnown && *KernelZeroSizePtrValue &&
3611 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3612}
3613
3616 ReallocPairsTy currMap = currState->get();
3617 ReallocPairsTy prevMap = prevState->get();
3618
3619 for (const ReallocPairsTy::value_type &Pair : prevMap) {
3621 if (!currMap.lookup(sym))
3622 return sym;
3623 }
3624
3625 return nullptr;
3626}
3627
3630 StringRef N = II->getName();
3631 if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
3632 if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
3633 N.contains_insensitive("intrusive") ||
3634 N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {
3635 return true;
3636 }
3637 }
3638 }
3639 return false;
3640}
3641
3647
3648 const RefState *RSCurr = state->get(Sym);
3649 const RefState *RSPrev = statePrev->get(Sym);
3650
3652
3653
3654 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3655 return nullptr;
3656
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3668 ReleaseFunctionLC->isParentOf(CurrentLC))) {
3669 if (const auto *AE = dyn_cast(S)) {
3670
3672 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3673 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3675
3676
3677 return nullptr;
3678 }
3679 } else if (const auto *CE = dyn_cast(S)) {
3680
3681
3682 if (const auto *MD =
3683 dyn_cast_or_null(CE->getDirectCallee())) {
3685
3686
3689
3690
3691 return nullptr;
3692 }
3693 }
3694 }
3695 }
3696
3697
3698
3699
3700
3701 StringRef Msg;
3702 std::unique_ptr StackHint = nullptr;
3704 llvm::raw_svector_ostream OS(Buf);
3705
3706 if (Mode == Normal) {
3707 if (isAllocated(RSCurr, RSPrev, S)) {
3708 Msg = "Memory is allocated";
3709 StackHint = std::make_unique(
3710 Sym, "Returned allocated memory");
3711 } else if (isReleased(RSCurr, RSPrev, S)) {
3712 const auto Family = RSCurr->getAllocationFamily();
3713 switch (Family.Kind) {
3714 case AF_Alloca:
3715 case AF_Malloc:
3716 case AF_Custom:
3717 case AF_CXXNew:
3718 case AF_CXXNewArray:
3719 case AF_IfNameIndex:
3720 Msg = "Memory is released";
3721 StackHint = std::make_unique(
3722 Sym, "Returning; memory was released");
3723 break;
3724 case AF_InnerBuffer: {
3727 const auto *TypedRegion = cast(ObjRegion);
3729 OS << "Inner buffer of '" << ObjTy << "' ";
3730
3732 OS << "deallocated by call to destructor";
3733 StackHint = std::make_unique(
3734 Sym, "Returning; inner buffer was deallocated");
3735 } else {
3736 OS << "reallocated by call to '";
3737 const Stmt *S = RSCurr->getStmt();
3738 if (const auto *MemCallE = dyn_cast(S)) {
3739 OS << MemCallE->getMethodDecl()->getDeclName();
3740 } else if (const auto *OpCallE = dyn_cast(S)) {
3741 OS << OpCallE->getDirectCallee()->getDeclName();
3742 } else if (const auto *CallE = dyn_cast(S)) {
3745 CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
3746 if (const auto *D = dyn_cast_or_null(Call->getDecl()))
3747 OS << D->getDeclName();
3748 else
3749 OS << "unknown";
3750 }
3751 OS << "'";
3752 StackHint = std::make_unique(
3753 Sym, "Returning; inner buffer was reallocated");
3754 }
3755 Msg = OS.str();
3756 break;
3757 }
3758 case AF_None:
3759 assert(false && "Unhandled allocation family!");
3760 return nullptr;
3761 }
3762
3763
3764 assert(!ReleaseFunctionLC && "There should be only one release point");
3766
3767
3768
3769
3771 if (const auto *DD = dyn_cast(LC->getDecl())) {
3773
3774
3775
3777
3778
3779
3780 return nullptr;
3781 }
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3808 }
3809 }
3810
3811 } else if (isRelinquished(RSCurr, RSPrev, S)) {
3812 Msg = "Memory ownership is transferred";
3813 StackHint = std::make_unique(Sym, "");
3814 } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3815 Mode = ReallocationFailed;
3816 Msg = "Reallocation failed";
3817 StackHint = std::make_unique(
3818 Sym, "Reallocation failed");
3819
3821
3822 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3823 "We only support one failed realloc at a time.");
3825 FailedReallocSymbol = sym;
3826 }
3827 }
3828
3829
3830 } else if (Mode == ReallocationFailed) {
3831 assert(FailedReallocSymbol && "No symbol to look for.");
3832
3833
3834 if (!statePrev->get(FailedReallocSymbol)) {
3835
3836 Msg = "Attempt to reallocate memory";
3837 StackHint = std::make_unique(
3838 Sym, "Returned reallocated memory");
3839 FailedReallocSymbol = nullptr;
3841 }
3842 }
3843
3844 if (Msg.empty()) {
3845 assert(!StackHint);
3846 return nullptr;
3847 }
3848
3849 assert(StackHint);
3850
3851
3853 if (!S) {
3854 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
3856 if (!PostImplCall)
3857 return nullptr;
3860 } else {
3863 }
3864
3865 auto P = std::make_shared(Pos, Msg, true);
3867 return P;
3868}
3869
3870void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
3871 const char *NL, const char *Sep) const {
3872
3873 RegionStateTy RS = State->get();
3874
3875 if (!RS.isEmpty()) {
3876 Out << Sep << "MallocChecker :" << NL;
3877 for (auto [Sym, Data] : RS) {
3878 const RefState *RefS = State->get(Sym);
3879 AllocationFamily Family = RefS->getAllocationFamily();
3880 std::optionalMallocChecker::CheckKind CheckKind =
3881 getCheckIfTracked(Family);
3882 if (!CheckKind)
3883 CheckKind = getCheckIfTracked(Family, true);
3884
3886 Out << " : ";
3887 Data.dump(Out);
3888 if (CheckKind)
3889 Out << " (" << CheckNames[*CheckKind].getName() << ")";
3890 Out << NL;
3891 }
3892 }
3893}
3894
3895namespace clang {
3896namespace ento {
3897namespace allocation_state {
3898
3901 AllocationFamily Family(AF_InnerBuffer);
3902 return State->set(Sym, RefState::getReleased(Family, Origin));
3903}
3904
3905}
3906}
3907}
3908
3909
3910
3912 MallocChecker *checker = mgr.getChecker();
3913 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
3914 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3916}
3917
3918void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
3920 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3922 checker->ShouldRegisterNoOwnershipChangeVisitor =
3924 checker, "AddNoOwnershipChangeNotes");
3925}
3926
3927bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
3928 return true;
3929}
3930
3931#define REGISTER_CHECKER(name) \
3932 void ento::register##name(CheckerManager &mgr) { \
3933 MallocChecker *checker = mgr.getChecker(); \
3934 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3935 checker->CheckNames[MallocChecker::CK_##name] = \
3936 mgr.getCurrentCheckerName(); \
3937 } \
3938 \
3939 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
3940
enum clang::sema::@1725::IndirectLocalPathEntry::EntryKind Kind
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 isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
#define REGISTER_CHECKER(name)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isGRealloc(const CallEvent &Call)
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
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.
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.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#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.
static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)
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 getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
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.
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)
DeclContext * getParent()
getParent - Returns the containing DeclContext.
A reference to a declared variable, function, enum, etc.
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
void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
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.
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
This represents a decl that may have a name.
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
Represents a program point just after an implicit call event.
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.
QualType getDesugaredType(const ASTContext &Context) const
Return the specified type with any "sugar" removed from the type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Smart pointer class that efficiently represents Objective-C method names.
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.
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
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.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isFunctionPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Represents a variable declaration or definition.
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Maps string IDs to AST nodes matched by parts of a matcher.
A record of the "type" of an APSInt, used for conversions.
Represents a call to any sort of function that might have a FunctionDecl.
APSIntPtr getMaxValue(const llvm::APSInt &v)
BlockDataRegion - A region that represents a block instance.
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.
virtual void Profile(llvm::FoldingSetNodeID &ID) const =0
virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0
Return a diagnostic piece which should be associated with the given node.
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)
Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...
Represents the memory allocation call in a C++ new-expression.
Represents a non-static C++ member function call, no matter how it is written.
An immutable map from CallDescriptions to arbitrary data.
Represents an abstract call to a function or method along a particular path.
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
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...
ElementRegion is used to represent both array elements and casts.
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.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
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.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
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()
A Range represents the closed range [from, to].
Represent a region's offset within the top level base 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)
DefinedSVal getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Conjure a symbol representing heap allocated memory region.
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.
Constructs a Stack hint for the given symbol.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual void dumpToStream(raw_ostream &os) const
virtual QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
virtual bool VisitSymbol(SymbolRef sym)=0
A visitor method invoked by ProgramStateManager::scanReachableSymbols.
SymbolicRegion - A special, "non-concrete" region.
SymbolRef getSymbol() const
It might return null.
TypedRegion - An abstract class representing regions that are typed.
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Value representing integer constant.
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)
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.
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.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
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)
bool Zero(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.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
bool operator!=(CanQual< T > x, CanQual< U > y)
const FunctionProtoType * T
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
@ Other
Other implicit parameter.