80#include "llvm/ADT/STLExtras.h"
81#include "llvm/ADT/StringExtras.h"
82#include "llvm/Support/Casting.h"
83#include "llvm/Support/Compiler.h"
84#include "llvm/Support/ErrorHandling.h"
85#include "llvm/Support/raw_ostream.h"
92using namespace std::placeholders;
104enum AllocationFamilyKind {
115struct AllocationFamily {
116 AllocationFamilyKind
Kind;
117 std::optional<StringRef> CustomName;
119 explicit AllocationFamily(AllocationFamilyKind AKind,
120 std::optional<StringRef> Name = std::nullopt)
121 :
Kind(AKind), CustomName(Name) {
122 assert((Kind != AF_Custom || CustomName.has_value()) &&
123 "Custom family must specify also the name");
126 if (Kind == AF_Custom && CustomName.value() ==
"malloc") {
128 CustomName = std::nullopt;
133 return std::tie(Kind, CustomName) == std::tie(
Other.Kind,
Other.CustomName);
137 return !(*
this ==
Other);
140 void Profile(llvm::FoldingSetNodeID &ID)
const {
143 if (Kind == AF_Custom)
144 ID.AddString(CustomName.value());
189 AllocationFamily Family;
191 RefState(Kind k,
const Stmt *
s, AllocationFamily family)
192 : S(
s), K(k), Family(family) {
193 assert(family.Kind != AF_None);
197 bool isAllocated()
const {
return K == Allocated; }
198 bool isAllocatedOfSizeZero()
const {
return K == AllocatedOfSizeZero; }
199 bool isReleased()
const {
return K == Released; }
200 bool isRelinquished()
const {
return K == Relinquished; }
201 bool isEscaped()
const {
return K == Escaped; }
202 AllocationFamily getAllocationFamily()
const {
return Family; }
203 const Stmt *getStmt()
const {
return S; }
206 return K ==
X.K && S ==
X.S && Family ==
X.Family;
209 static RefState getAllocated(AllocationFamily family,
const Stmt *
s) {
210 return RefState(Allocated,
s, family);
212 static RefState getAllocatedOfSizeZero(
const RefState *RS) {
213 return RefState(AllocatedOfSizeZero, RS->getStmt(),
214 RS->getAllocationFamily());
216 static RefState getReleased(AllocationFamily family,
const Stmt *
s) {
217 return RefState(Released,
s, family);
219 static RefState getRelinquished(AllocationFamily family,
const Stmt *
s) {
220 return RefState(Relinquished,
s, family);
222 static RefState getEscaped(
const RefState *RS) {
223 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
226 void Profile(llvm::FoldingSetNodeID &ID)
const {
232 LLVM_DUMP_METHOD
void dump(raw_ostream &OS)
const {
234#define CASE(ID) case ID: OS << #ID; break;
236 CASE(AllocatedOfSizeZero)
243 LLVM_DUMP_METHOD
void dump()
const {
dump(llvm::errs()); }
258 AllocationFamily Family,
259 std::optional<SVal> RetVal = std::nullopt);
273enum OwnershipAfterReallocKind {
275 OAR_ToBeFreedAfterFailure,
285 OAR_DoNotTrackAfterFailure
298 OwnershipAfterReallocKind
Kind;
300 ReallocPair(
SymbolRef S, OwnershipAfterReallocKind K)
301 : ReallocatedSym(S),
Kind(K) {}
302 void Profile(llvm::FoldingSetNodeID &ID)
const {
304 ID.AddPointer(ReallocatedSym);
307 return ReallocatedSym ==
X.ReallocatedSym &&
318 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
325 if (!
Call.getDecl() || !isa<FunctionDecl>(
Call.getDecl()))
343#define BUGTYPE_PROVIDER(NAME, DEF) \
344 struct NAME : virtual public CheckerFrontend { \
345 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
367#undef BUGTYPE_PROVIDER
369template <
typename... BT_PROVIDERS>
370struct DynMemFrontend :
virtual public CheckerFrontend,
public BT_PROVIDERS... {
371 template <
typename T>
const T *getAs()
const {
372 if constexpr (std::is_same_v<T, CheckerFrontend> ||
373 (std::is_same_v<T, BT_PROVIDERS> || ...))
374 return static_cast<const T *
>(
this);
385 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
386 check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,
387 check::PostCall, eval::Call, check::NewAllocator,
388 check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,
395 bool ShouldIncludeOwnershipAnnotatedFunctions =
false;
397 bool ShouldRegisterNoOwnershipChangeVisitor =
false;
406 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
409 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
411 DynMemFrontend<Leak> NewDeleteLeaksChecker;
412 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
413 DynMemFrontend<UseFree> InnerPointerChecker;
419 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
431 bool Assumption)
const;
432 void checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
445 const char *NL,
const char *Sep)
const override;
447 StringRef
getDebugTag()
const override {
return "MallocChecker"; }
450#define CHECK_FN(NAME) \
451 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
482 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
483 {{CDM::CLibrary, {
"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
489 {{CDM::CLibrary, {
"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
490 {{CDM::CLibrary, {
"getdelim"}, 4},
491 &MallocChecker::checkGetDelimOrGetLine},
495 {{CDM::CLibrary, {
"free"}, 1}, &MallocChecker::checkFree},
496 {{CDM::CLibrary, {
"if_freenameindex"}, 1},
497 &MallocChecker::checkIfFreeNameIndex},
498 {{CDM::CLibrary, {
"kfree"}, 1}, &MallocChecker::checkFree},
499 {{CDM::CLibrary, {
"g_free"}, 1}, &MallocChecker::checkFree},
504 static bool isFreeingOwnershipAttrCall(
const CallEvent &
Call);
506 static bool isAllocatingOwnershipAttrCall(
const CallEvent &
Call);
508 friend class NoMemOwnershipChangeVisitor;
511 {{CDM::CLibrary, {
"alloca"}, 1}, &MallocChecker::checkAlloca},
512 {{CDM::CLibrary, {
"_alloca"}, 1}, &MallocChecker::checkAlloca},
516 {{CDM::CLibrary, {
"__builtin_alloca_with_align"}, 2},
517 &MallocChecker::checkAlloca},
521 {{CDM::CLibrary, {
"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
522 {{CDM::CLibrary, {
"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
523 {{CDM::CLibrary, {
"calloc"}, 2}, &MallocChecker::checkCalloc},
524 {{CDM::CLibrary, {
"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
525 {{CDM::CLibrary, {
"strndup"}, 2}, &MallocChecker::checkStrdup},
526 {{CDM::CLibrary, {
"strdup"}, 1}, &MallocChecker::checkStrdup},
527 {{CDM::CLibrary, {
"_strdup"}, 1}, &MallocChecker::checkStrdup},
528 {{CDM::CLibrary, {
"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
529 {{CDM::CLibrary, {
"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
530 {{CDM::CLibrary, {
"wcsdup"}, 1}, &MallocChecker::checkStrdup},
531 {{CDM::CLibrary, {
"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
532 {{CDM::CLibrary, {
"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
533 {{CDM::CLibrary, {
"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
534 {{CDM::CLibrary, {
"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
535 {{CDM::CLibrary, {
"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
536 {{CDM::CLibrary, {
"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
537 {{CDM::CLibrary, {
"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
538 {{CDM::CLibrary, {
"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
539 {{CDM::CLibrary, {
"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
540 {{CDM::CLibrary, {
"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
544 {{CDM::CLibrary, {
"realloc"}, 2},
545 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
546 {{CDM::CLibrary, {
"reallocf"}, 2},
547 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
true)},
548 {{CDM::CLibrary, {
"g_realloc"}, 2},
549 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
550 {{CDM::CLibrary, {
"g_try_realloc"}, 2},
551 std::bind(&MallocChecker::checkRealloc, _1,
_2, _3, _4,
false)},
552 {{CDM::CLibrary, {
"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
553 {{CDM::CLibrary, {
"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
561 AllocationFamily Family)
const;
565 AllocationFamily Family)
const;
568 mutable std::optional<uint64_t> KernelZeroFlagVal;
570 using KernelZeroSizePtrValueTy = std::optional<int>;
575 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
581 AllocationFamily Family)
const;
594 std::optional<SVal> RetVal = std::nullopt);
625 bool isAlloca)
const;
652 AllocationFamily Family)
const;
656 [[nodiscard]] std::optional<ProgramStateRef>
679 const OwnershipAttr *Att,
703 unsigned Num,
bool Hold,
bool &IsKnownToBeAllocated,
704 AllocationFamily Family,
bool ReturnsNullOnFailure =
false)
const;
730 AllocationFamily Family,
bool ReturnsNullOnFailure =
false,
731 std::optional<SVal> ArgValOpt = {})
const;
749 bool SuffixWithN =
false)
const;
758 const Expr *BlockBytes);
771 bool suppressDeallocationsInSuspiciousContexts(
const CallEvent &
Call,
780 const Stmt *S)
const;
792 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *
Call,
801 bool IsConstPointerEscape)
const;
813 const T *getRelevantFrontendAs(AllocationFamily Family)
const;
818 static bool SummarizeValue(raw_ostream &os,
SVal V);
823 const Expr *DeallocExpr,
824 AllocationFamily Family)
const;
830 const Expr *DeallocExpr,
const RefState *RS,
831 SymbolRef Sym,
bool OwnershipTransferred)
const;
834 const Expr *DeallocExpr, AllocationFamily Family,
835 const Expr *AllocExpr =
nullptr)
const;
847 const Expr *FreeExpr,
848 AllocationFamily Family)
const;
877 bool isFreeingCallAsWritten(
const CallExpr &
Call)
const {
878 const auto *MallocChk =
static_cast<const MallocChecker *
>(&
Checker);
879 if (MallocChk->FreeingMemFnMap.lookupAsWritten(
Call) ||
880 MallocChk->ReallocatingMemFnMap.lookupAsWritten(
Call))
883 if (
const auto *
Func =
884 llvm::dyn_cast_or_null<FunctionDecl>(
Call.getCalleeDecl()))
885 return MallocChecker::isFreeingOwnershipAttrCall(
Func);
892 return CallEnterState->get<RegionState>(Sym) !=
893 CallExitEndState->get<RegionState>(Sym);
900 bool doesFnIntendToHandleOwnership(
const Decl *Callee,
902 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
922 if (isFreeingCallAsWritten(*
Call))
934 N->getState()->getStateManager().getContext().getSourceManager());
935 return std::make_shared<PathDiagnosticEventPiece>(
936 L,
"Returning without deallocating memory or storing the pointer for "
937 "later deallocation");
944 void Profile(llvm::FoldingSetNodeID &ID)
const override {
963 enum NotificationMode {
Normal, ReallocationFailed };
969 NotificationMode Mode;
981 MallocBugVisitor(
SymbolRef S,
bool isLeak =
false)
982 : Sym(S), Mode(
Normal), FailedReallocSymbol(nullptr),
983 ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
985 static void *getTag() {
990 void Profile(llvm::FoldingSetNodeID &ID)
const override {
991 ID.AddPointer(getTag());
996 static inline bool isAllocated(
const RefState *RSCurr,
const RefState *RSPrev,
998 return (isa_and_nonnull<CallExpr, CXXNewExpr>(
Stmt) &&
1000 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1002 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1007 static inline bool isReleased(
const RefState *RSCurr,
const RefState *RSPrev,
1010 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1011 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(
Stmt)) ||
1012 (!
Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1017 static inline bool isRelinquished(
const RefState *RSCurr,
1018 const RefState *RSPrev,
const Stmt *
Stmt) {
1020 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(
Stmt) &&
1021 (RSCurr && RSCurr->isRelinquished()) &&
1022 (!RSPrev || !RSPrev->isRelinquished()));
1029 static inline bool hasReallocFailed(
const RefState *RSCurr,
1030 const RefState *RSPrev,
1032 return ((!isa_and_nonnull<CallExpr>(
Stmt)) &&
1034 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1036 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1051 return std::make_shared<PathDiagnosticEventPiece>(L, BR.
getDescription(),
1056 class StackHintGeneratorForReallocationFailed
1059 StackHintGeneratorForReallocationFailed(
SymbolRef S, StringRef M)
1062 std::string getMessageForArg(
const Expr *ArgE,
unsigned ArgIndex)
override {
1067 llvm::raw_svector_ostream os(buf);
1069 os <<
"Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1070 <<
" parameter failed";
1072 return std::string(os.str());
1076 return "Reallocation of returned value failed";
1095 state = state->remove<RegionState>(sym);
1106 if (Kind != OO_New && Kind != OO_Array_New)
1122 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1133 return L.
isInvalid() || (!HasBody &&
SM.isInSystemHeader(L));
1140bool MallocChecker::isFreeingOwnershipAttrCall(
const CallEvent &
Call) {
1141 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1143 return Func && isFreeingOwnershipAttrCall(
Func);
1147 if (
Func->hasAttrs()) {
1148 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1149 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1150 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1157bool MallocChecker::isFreeingCall(
const CallEvent &
Call)
const {
1158 if (FreeingMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1161 return isFreeingOwnershipAttrCall(
Call);
1164bool MallocChecker::isAllocatingOwnershipAttrCall(
const CallEvent &
Call) {
1165 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
1167 return Func && isAllocatingOwnershipAttrCall(
Func);
1170bool MallocChecker::isAllocatingOwnershipAttrCall(
const FunctionDecl *
Func) {
1171 for (
const auto *I :
Func->specific_attrs<OwnershipAttr>()) {
1172 if (I->getOwnKind() == OwnershipAttr::Returns)
1180 if (FreeingMemFnMap.lookup(
Call) || AllocatingMemFnMap.lookup(
Call) ||
1181 AllocaMemFnMap.lookup(
Call) || ReallocatingMemFnMap.lookup(
Call))
1184 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1187 const auto *
Func = dyn_cast<FunctionDecl>(
Call.getDecl());
1188 return Func &&
Func->hasAttr<OwnershipAttr>();
1191std::optional<ProgramStateRef>
1213 if (!KernelZeroFlagVal) {
1215 case llvm::Triple::FreeBSD:
1216 KernelZeroFlagVal = 0x0100;
1218 case llvm::Triple::NetBSD:
1219 KernelZeroFlagVal = 0x0002;
1221 case llvm::Triple::OpenBSD:
1222 KernelZeroFlagVal = 0x0008;
1224 case llvm::Triple::Linux:
1226 KernelZeroFlagVal = 0x8000;
1234 return std::nullopt;
1241 if (
Call.getNumArgs() < 2)
1242 return std::nullopt;
1244 const Expr *FlagsEx =
Call.getArgExpr(
Call.getNumArgs() - 1);
1245 const SVal V =
C.getSVal(FlagsEx);
1246 if (!isa<NonLoc>(
V)) {
1249 return std::nullopt;
1253 NonLoc ZeroFlag =
C.getSValBuilder()
1254 .makeIntVal(*KernelZeroFlagVal, FlagsEx->
getType())
1256 SVal MaskedFlagsUC =
C.getSValBuilder().evalBinOpNN(State, BO_And,
1260 return std::nullopt;
1265 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1268 if (TrueState && !FalseState) {
1269 SVal ZeroVal =
C.getSValBuilder().makeZeroVal(Ctx.
CharTy);
1270 return MallocMemAux(
C,
Call,
Call.getArgExpr(0), ZeroVal, TrueState,
1271 AllocationFamily(AF_Malloc));
1274 return std::nullopt;
1278 const Expr *BlockBytes) {
1280 SVal BlocksVal =
C.getSVal(Blocks);
1281 SVal BlockBytesVal =
C.getSVal(BlockBytes);
1283 SVal TotalSize = SB.
evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1292 AllocationFamily(AF_Malloc));
1293 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1294 C.addTransition(State);
1300 std::optional<ProgramStateRef> MaybeState =
1301 performKernelMalloc(
Call,
C, State);
1303 State = *MaybeState;
1306 AllocationFamily(AF_Malloc));
1307 C.addTransition(State);
1331 bool ShouldFreeOnFail)
const {
1340 State = ReallocMemAux(
C,
Call, ShouldFreeOnFail, State,
1341 AllocationFamily(AF_Malloc));
1342 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1343 C.addTransition(State);
1348 State = CallocMem(
C,
Call, State);
1349 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1350 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1351 C.addTransition(State);
1356 bool IsKnownToBeAllocatedMemory =
false;
1357 if (suppressDeallocationsInSuspiciousContexts(
Call,
C))
1359 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1360 AllocationFamily(AF_Malloc));
1361 C.addTransition(State);
1367 AllocationFamily(AF_Alloca));
1368 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1369 C.addTransition(State);
1374 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1378 AllocationFamily(AF_Malloc));
1380 C.addTransition(State);
1389 AllocationFamily(AF_IfNameIndex));
1391 C.addTransition(State);
1397 bool IsKnownToBeAllocatedMemory =
false;
1398 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1399 AllocationFamily(AF_IfNameIndex));
1400 C.addTransition(State);
1412 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1420 bool IsKnownToBeAllocatedMemory =
false;
1421 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1434 auto RetVal = State->getSVal(BufArg,
Call.getLocationContext());
1435 State = State->BindExpr(CE,
C.getLocationContext(), RetVal);
1436 C.addTransition(State);
1443 AllocationFamily(AF_CXXNew));
1444 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1448 AllocationFamily(AF_CXXNewArray));
1449 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1452 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1453 AllocationFamily(AF_CXXNew));
1455 case OO_Array_Delete:
1456 State = FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocatedMemory,
1457 AllocationFamily(AF_CXXNewArray));
1460 assert(
false &&
"not a new/delete operator");
1464 C.addTransition(State);
1471 State = MallocMemAux(
C,
Call,
Call.getArgExpr(0), zeroVal, State,
1472 AllocationFamily(AF_Malloc));
1473 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1474 C.addTransition(State);
1480 AllocationFamily(AF_Malloc));
1481 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1482 C.addTransition(State);
1488 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1489 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1490 AllocationFamily(AF_Malloc));
1491 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1492 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1493 C.addTransition(State);
1500 SVal TotalSize = evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
1501 State = MallocMemAux(
C,
Call, TotalSize,
Init, State,
1502 AllocationFamily(AF_Malloc));
1503 State = ProcessZeroAllocCheck(
C,
Call, 0, State);
1504 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1505 C.addTransition(State);
1510 assert(FD &&
"a CallDescription cannot match a call without a Decl");
1530 bool IsKnownToBeAllocated =
false;
1531 State = FreeMemAux(
C,
Call.getArgExpr(0),
Call, State,
false,
1532 IsKnownToBeAllocated, AllocationFamily(AF_Malloc),
false,
1535 C.addTransition(State);
1548 const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1554 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1555 SizeOpt->isUnknownOrUndef())
1558 const auto LinePtr = LinePtrOpt->getAs<
DefinedSVal>();
1560 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1566 AllocationFamily(AF_Malloc), *LinePtr));
1571 State = ReallocMemAux(
C,
Call,
false, State,
1572 AllocationFamily(AF_Malloc),
1574 State = ProcessZeroAllocCheck(
C,
Call, 1, State);
1575 State = ProcessZeroAllocCheck(
C,
Call, 2, State);
1576 C.addTransition(State);
1582 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
1588 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1589 MismatchedDeallocatorChecker.isEnabled()) {
1594 switch (I->getOwnKind()) {
1595 case OwnershipAttr::Returns:
1596 State = MallocMemReturnsAttr(
C,
Call, I, State);
1598 case OwnershipAttr::Takes:
1599 case OwnershipAttr::Holds:
1600 State = FreeMemAttr(
C,
Call, I, State);
1605 C.addTransition(State);
1609 if (!
Call.getOriginExpr())
1614 if (
const CheckFn *Callback = FreeingMemFnMap.lookup(
Call)) {
1615 (*Callback)(
this, State,
Call,
C);
1619 if (
const CheckFn *Callback = AllocatingMemFnMap.lookup(
Call)) {
1620 State = MallocBindRetVal(
C,
Call, State,
false);
1621 (*Callback)(
this, State,
Call,
C);
1625 if (
const CheckFn *Callback = ReallocatingMemFnMap.lookup(
Call)) {
1626 State = MallocBindRetVal(
C,
Call, State,
false);
1627 (*Callback)(
this, State,
Call,
C);
1632 State = MallocBindRetVal(
C,
Call, State,
false);
1633 checkCXXNewOrCXXDelete(State,
Call,
C);
1638 checkCXXNewOrCXXDelete(State,
Call,
C);
1642 if (
const CheckFn *Callback = AllocaMemFnMap.lookup(
Call)) {
1643 State = MallocBindRetVal(
C,
Call, State,
true);
1644 (*Callback)(
this, State,
Call,
C);
1648 if (isFreeingOwnershipAttrCall(
Call)) {
1649 checkOwnershipAttr(State,
Call,
C);
1653 if (isAllocatingOwnershipAttrCall(
Call)) {
1654 State = MallocBindRetVal(
C,
Call, State,
false);
1655 checkOwnershipAttr(State,
Call,
C);
1669 const Expr *Arg =
nullptr;
1671 if (
const CallExpr *CE = dyn_cast<CallExpr>(
Call.getOriginExpr())) {
1672 Arg = CE->
getArg(IndexOfSizeArg);
1674 dyn_cast<CXXNewExpr>(
Call.getOriginExpr())) {
1675 if (
NE->isArray()) {
1676 Arg = *
NE->getArraySize();
1681 assert(
false &&
"not a CallExpr or CXXNewExpr");
1686 RetVal = State->getSVal(
Call.getOriginExpr(),
C.getLocationContext());
1698 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1702 std::tie(TrueState, FalseState) =
1703 State->assume(SvalBuilder.
evalEQ(State, *DefArgVal,
Zero));
1705 if (TrueState && !FalseState) {
1706 SymbolRef Sym = RetVal->getAsLocSymbol();
1710 const RefState *RS = State->get<RegionState>(Sym);
1712 if (RS->isAllocated())
1713 return TrueState->set<RegionState>(
1714 Sym, RefState::getAllocatedOfSizeZero(RS));
1721 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1731 while (!PointeeType.isNull()) {
1732 Result = PointeeType;
1733 PointeeType = PointeeType->getPointeeType();
1746 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1752 for (
const auto *CtorParam : CtorD->
parameters()) {
1755 if (CtorParamPointeeT.
isNull())
1770 AllocationFamily Family)
const {
1775 const ParentMap &PM =
C.getLocationContext()->getParentMap();
1790 if (
Call.getOriginExpr()->isArray()) {
1791 if (
auto SizeEx =
NE->getArraySize())
1792 checkTaintedness(
C,
Call,
C.getSVal(*SizeEx), State,
1793 AllocationFamily(AF_CXXNewArray));
1797 State = ProcessZeroAllocCheck(
C,
Call, 0, State,
Target);
1803 if (!
C.wasInlined) {
1806 AllocationFamily(
Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1808 C.addTransition(State);
1818 StringRef FirstSlot =
Call.getSelector().getNameForSlot(0);
1819 return FirstSlot ==
"dataWithBytesNoCopy" ||
1820 FirstSlot ==
"initWithBytesNoCopy" ||
1821 FirstSlot ==
"initWithCharactersNoCopy";
1828 for (
unsigned i = 1; i < S.getNumArgs(); ++i)
1829 if (S.getNameForSlot(i) ==
"freeWhenDone")
1830 return !
Call.getArgSVal(i).isZeroConstant();
1832 return std::nullopt;
1847 if (
Call.hasNonZeroCallbackArg())
1850 bool IsKnownToBeAllocatedMemory;
1852 true, IsKnownToBeAllocatedMemory,
1853 AllocationFamily(AF_Malloc),
1856 C.addTransition(State);
1861 const OwnershipAttr *Att,
1866 auto attrClassName = Att->getModule()->getName();
1867 auto Family = AllocationFamily(AF_Custom, attrClassName);
1869 if (!Att->args().empty()) {
1870 return MallocMemAux(
C,
Call,
1871 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1880 bool isAlloca)
const {
1881 const Expr *CE =
Call.getOriginExpr();
1887 unsigned Count =
C.blockCount();
1894 return State->BindExpr(CE,
C.getLocationContext(), RetVal);
1901 AllocationFamily Family)
const {
1906 return MallocMemAux(
C,
Call,
C.getSVal(SizeEx),
Init, State, Family);
1909void MallocChecker::reportTaintBug(StringRef Msg,
ProgramStateRef State,
1912 AllocationFamily Family)
const {
1913 if (
ExplodedNode *N =
C.generateNonFatalErrorNode(State,
this)) {
1915 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
1916 for (
const auto *TaintedSym : TaintedSyms) {
1917 R->markInteresting(TaintedSym);
1919 C.emitReport(std::move(R));
1925 AllocationFamily Family)
const {
1926 if (!TaintedAllocChecker.isEnabled())
1928 std::vector<SymbolRef> TaintedSyms =
1930 if (TaintedSyms.empty())
1939 const llvm::APSInt MaxValInt = BVF.
getMaxValue(SizeTy);
1942 std::optional<NonLoc> SizeNL = SizeSVal.
getAs<
NonLoc>();
1943 auto Cmp = SVB.
evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
1947 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
1948 if (!StateTooLarge && StateNotTooLarge) {
1953 std::string
Callee =
"Memory allocation function";
1954 if (
Call.getCalleeIdentifier())
1955 Callee =
Call.getCalleeIdentifier()->getName().str();
1957 Callee +
" is called with a tainted (potentially attacker controlled) "
1958 "value. Make sure the value is bound checked.",
1959 State,
C, TaintedSyms, Family);
1965 AllocationFamily Family)
const {
1969 const Expr *CE =
Call.getOriginExpr();
1974 "Allocation functions must return a pointer");
1977 SVal RetVal = State->getSVal(CE,
C.getLocationContext());
1980 State = State->bindDefaultInitial(RetVal,
Init, LCtx);
1986 checkTaintedness(
C,
Call, Size, State, AllocationFamily(AF_Malloc));
1997 AllocationFamily Family,
1998 std::optional<SVal> RetVal) {
2004 RetVal = State->getSVal(
E,
C.getLocationContext());
2007 if (!RetVal->getAs<
Loc>())
2010 SymbolRef Sym = RetVal->getAsLocSymbol();
2018 return State->set<RegionState>(Sym, RefState::getAllocated(Family,
E));
2025 const OwnershipAttr *Att,
2030 auto attrClassName = Att->getModule()->getName();
2031 auto Family = AllocationFamily(AF_Custom, attrClassName);
2033 bool IsKnownToBeAllocated =
false;
2035 for (
const auto &Arg : Att->args()) {
2037 FreeMemAux(
C,
Call, State, Arg.getASTIndex(),
2038 Att->getOwnKind() == OwnershipAttr::Holds,
2039 IsKnownToBeAllocated, Family);
2049 bool Hold,
bool &IsKnownToBeAllocated,
2050 AllocationFamily Family,
2051 bool ReturnsNullOnFailure)
const {
2055 if (
Call.getNumArgs() < (
Num + 1))
2058 return FreeMemAux(
C,
Call.getArgExpr(
Num),
Call, State, Hold,
2059 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2066 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2068 assert(*Ret &&
"We should not store the null return symbol");
2071 RetStatusSymbol = *Ret;
2079 const CallExpr *CE = dyn_cast<CallExpr>(
E);
2090 if (I->getOwnKind() != OwnershipAttr::Takes)
2093 os <<
", which takes ownership of '" << I->getModule()->
getName() <<
'\'';
2099 if (
const CallExpr *CE = dyn_cast<CallExpr>(
E)) {
2115 if (Msg->isInstanceMessage())
2119 Msg->getSelector().
print(os);
2123 if (
const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(
E)) {
2142 switch (Family.Kind) {
2149 case AF_CXXNewArray:
2152 case AF_IfNameIndex:
2153 os <<
"'if_nameindex()'";
2155 case AF_InnerBuffer:
2156 os <<
"container-specific allocator";
2159 os << Family.CustomName.value();
2163 assert(
false &&
"not a deallocation expression");
2168 switch (Family.Kind) {
2175 case AF_CXXNewArray:
2178 case AF_IfNameIndex:
2179 os <<
"'if_freenameindex()'";
2181 case AF_InnerBuffer:
2182 os <<
"container-specific deallocator";
2185 os <<
"function that takes ownership of '" << Family.CustomName.value()
2190 assert(
false &&
"not a deallocation expression");
2197 bool Hold,
bool &IsKnownToBeAllocated,
2198 AllocationFamily Family,
bool ReturnsNullOnFailure,
2199 std::optional<SVal> ArgValOpt)
const {
2204 SVal ArgVal = ArgValOpt.value_or(
C.getSVal(ArgExpr));
2205 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2210 if (!isa<Loc>(location))
2215 std::tie(notNullState, nullState) = State->assume(location);
2216 if (nullState && !notNullState)
2225 const Expr *ParentExpr =
Call.getOriginExpr();
2244 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,
C, ArgVal))
2245 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2253 if (isa<BlockDataRegion>(R)) {
2254 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2267 if (isa<AllocaRegion>(R))
2270 HandleNonHeapDealloc(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2283 const RefState *RsBase = State->get<RegionState>(SymBase);
2284 SymbolRef PreviousRetStatusSymbol =
nullptr;
2286 IsKnownToBeAllocated =
2287 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2292 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2298 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2300 HandleDoubleFree(
C, ParentExpr->
getSourceRange(), RsBase->isReleased(),
2301 SymBase, PreviousRetStatusSymbol);
2307 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2308 RsBase->isEscaped()) {
2311 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2312 if (!DeallocMatchesAlloc) {
2314 RsBase, SymBase, Hold);
2321 if (Offset.isValid() &&
2322 !Offset.hasSymbolicOffset() &&
2323 Offset.getOffset() != 0) {
2324 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2333 HandleFunctionPtrFree(
C, ArgVal, ArgExpr->
getSourceRange(), ParentExpr,
2339 State = State->remove<FreeReturnValue>(SymBase);
2343 if (ReturnsNullOnFailure) {
2344 SVal RetVal =
C.getSVal(ParentExpr);
2346 if (RetStatusSymbol) {
2347 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2348 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2356 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2361 State = State->invalidateRegions({location},
Call.getCFGElementRef(),
2362 C.blockCount(),
C.getLocationContext(),
2368 return State->set<RegionState>(SymBase,
2369 RefState::getRelinquished(Family,
2372 return State->set<RegionState>(SymBase,
2373 RefState::getReleased(Family, ParentExpr));
2377const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family)
const {
2378 switch (Family.Kind) {
2382 case AF_IfNameIndex:
2383 return MallocChecker.
getAs<
T>();
2385 case AF_CXXNewArray: {
2386 const T *ND = NewDeleteChecker.
getAs<
T>();
2387 const T *NDL = NewDeleteLeaksChecker.
getAs<
T>();
2390 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2391 assert(ND && NDL &&
"Casting to CheckerFrontend always succeeds");
2393 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2395 assert(!(ND && NDL) &&
2396 "NewDelete and NewDeleteLeaks must not share a bug type");
2397 return ND ? ND : NDL;
2399 case AF_InnerBuffer:
2400 return InnerPointerChecker.getAs<
T>();
2402 assert(
false &&
"no family");
2405 assert(
false &&
"unhandled family");
2411 if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2412 return MallocChecker.
getAs<
T>();
2414 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2416 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2419bool MallocChecker::SummarizeValue(raw_ostream &os,
SVal V) {
2420 if (std::optional<nonloc::ConcreteInt> IntVal =
2422 os <<
"an integer (" << IntVal->getValue() <<
")";
2423 else if (std::optional<loc::ConcreteInt> ConstAddr =
2425 os <<
"a constant address (" << ConstAddr->getValue() <<
")";
2427 os <<
"the address of the label '" <<
Label->getLabel()->getName() <<
"'";
2434bool MallocChecker::SummarizeRegion(
ProgramStateRef State, raw_ostream &os,
2437 case MemRegion::FunctionCodeRegionKind: {
2438 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2440 os <<
"the address of the function '" << *FD <<
'\'';
2442 os <<
"the address of a function";
2445 case MemRegion::BlockCodeRegionKind:
2448 case MemRegion::BlockDataRegionKind:
2455 if (isa<StackLocalsSpaceRegion>(MS)) {
2456 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2464 os <<
"the address of the local variable '" << VD->
getName() <<
"'";
2466 os <<
"the address of a local stack variable";
2470 if (isa<StackArgumentsSpaceRegion>(MS)) {
2471 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2479 os <<
"the address of the parameter '" << VD->
getName() <<
"'";
2481 os <<
"the address of a parameter";
2485 if (isa<GlobalsSpaceRegion>(MS)) {
2486 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2495 os <<
"the address of the static variable '" << VD->
getName() <<
"'";
2497 os <<
"the address of the global variable '" << VD->
getName() <<
"'";
2499 os <<
"the address of a global variable";
2510 const Expr *DeallocExpr,
2511 AllocationFamily Family)
const {
2512 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2515 if (!Frontend->isEnabled()) {
2522 llvm::raw_svector_ostream os(buf);
2525 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2526 MR = ER->getSuperRegion();
2528 os <<
"Argument to ";
2530 os <<
"deallocator";
2534 MR ? SummarizeRegion(
C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2536 os <<
", which is not memory allocated by ";
2538 os <<
"not memory allocated by ";
2542 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2544 R->markInteresting(MR);
2546 C.emitReport(std::move(R));
2552 const FreeAlloca *Frontend;
2554 if (MallocChecker.isEnabled())
2555 Frontend = &MallocChecker;
2556 else if (MismatchedDeallocatorChecker.isEnabled())
2557 Frontend = &MismatchedDeallocatorChecker;
2564 auto R = std::make_unique<PathSensitiveBugReport>(
2565 Frontend->FreeAllocaBug,
2566 "Memory allocated by 'alloca()' should not be deallocated", N);
2569 C.emitReport(std::move(R));
2575 const Expr *DeallocExpr,
2577 bool OwnershipTransferred)
const {
2578 if (!MismatchedDeallocatorChecker.isEnabled()) {
2585 llvm::raw_svector_ostream os(buf);
2587 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2589 llvm::raw_svector_ostream AllocOs(AllocBuf);
2591 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2593 if (OwnershipTransferred) {
2595 os << DeallocOs.str() <<
" cannot";
2599 os <<
" take ownership of memory";
2602 os <<
" allocated by " << AllocOs.str();
2606 os <<
" allocated by " << AllocOs.str();
2608 os <<
" should be deallocated by ";
2612 os <<
", not " << DeallocOs.str();
2617 auto R = std::make_unique<PathSensitiveBugReport>(
2618 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2619 R->markInteresting(Sym);
2621 R->addVisitor<MallocBugVisitor>(Sym);
2622 C.emitReport(std::move(R));
2628 AllocationFamily Family,
2629 const Expr *AllocExpr)
const {
2630 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2633 if (!Frontend->isEnabled()) {
2643 llvm::raw_svector_ostream os(buf);
2645 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2648 assert(MR &&
"Only MemRegion based symbols can have offset free errors");
2651 assert((Offset.isValid() &&
2652 !Offset.hasSymbolicOffset() &&
2653 Offset.getOffset() != 0) &&
2654 "Only symbols with a valid offset can have offset free errors");
2656 int offsetBytes = Offset.getOffset() /
C.getASTContext().getCharWidth();
2658 os <<
"Argument to ";
2660 os <<
"deallocator";
2661 os <<
" is offset by "
2664 << ((
abs(offsetBytes) > 1) ?
"bytes" :
"byte")
2665 <<
" from the start of ";
2667 os <<
"memory allocated by " << AllocNameOs.str();
2669 os <<
"allocated memory";
2671 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2675 C.emitReport(std::move(R));
2680 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(
C, Sym);
2683 if (!Frontend->isEnabled()) {
2689 AllocationFamily AF =
2690 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2692 auto R = std::make_unique<PathSensitiveBugReport>(
2693 Frontend->UseFreeBug,
2694 AF.Kind == AF_InnerBuffer
2695 ?
"Inner pointer of container used after re/deallocation"
2696 :
"Use of memory after it is released",
2699 R->markInteresting(Sym);
2701 R->addVisitor<MallocBugVisitor>(Sym);
2703 if (AF.Kind == AF_InnerBuffer)
2706 C.emitReport(std::move(R));
2713 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(
C, Sym);
2716 if (!Frontend->isEnabled()) {
2722 auto R = std::make_unique<PathSensitiveBugReport>(
2723 Frontend->DoubleFreeBug,
2724 (Released ?
"Attempt to release already released memory"
2725 :
"Attempt to release non-owned memory"),
2727 if (
Range.isValid())
2729 R->markInteresting(Sym);
2731 R->markInteresting(PrevSym);
2732 R->addVisitor<MallocBugVisitor>(Sym);
2733 C.emitReport(std::move(R));
2739 const UseZeroAllocated *Frontend =
2740 getRelevantFrontendAs<UseZeroAllocated>(
C, Sym);
2743 if (!Frontend->isEnabled()) {
2749 auto R = std::make_unique<PathSensitiveBugReport>(
2750 Frontend->UseZeroAllocatedBug,
"Use of memory allocated with size zero",
2755 R->markInteresting(Sym);
2756 R->addVisitor<MallocBugVisitor>(Sym);
2758 C.emitReport(std::move(R));
2764 const Expr *FreeExpr,
2765 AllocationFamily Family)
const {
2766 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2769 if (!Frontend->isEnabled()) {
2776 llvm::raw_svector_ostream Os(Buf);
2779 while (
const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2780 MR = ER->getSuperRegion();
2782 Os <<
"Argument to ";
2784 Os <<
"deallocator";
2786 Os <<
" is a function pointer";
2788 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2790 R->markInteresting(MR);
2792 C.emitReport(std::move(R));
2799 AllocationFamily Family,
bool SuffixWithN)
const {
2803 const CallExpr *CE = cast<CallExpr>(
Call.getOriginExpr());
2809 SVal Arg0Val =
C.getSVal(arg0Expr);
2810 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2817 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->
getType()));
2823 SVal TotalSize =
C.getSVal(Arg1);
2825 TotalSize = evalMulForBufferSize(
C, Arg1, CE->
getArg(2));
2826 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2832 svalBuilder.makeIntValWithWidth(
2833 svalBuilder.getContext().getCanonicalSizeType(), 0));
2836 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2838 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2841 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2842 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2846 if (PrtIsNull && !SizeIsZero) {
2853 if (PrtIsNull && SizeIsZero)
2858 bool IsKnownToBeAllocated =
false;
2867 C,
Call, StateSizeIsZero, 0,
false, IsKnownToBeAllocated, Family))
2872 FreeMemAux(
C,
Call, State, 0,
false, IsKnownToBeAllocated, Family)) {
2879 OwnershipAfterReallocKind
Kind = OAR_ToBeFreedAfterFailure;
2880 if (ShouldFreeOnFail)
2881 Kind = OAR_FreeOnFailure;
2882 else if (!IsKnownToBeAllocated)
2883 Kind = OAR_DoNotTrackAfterFailure;
2887 SVal RetVal = stateRealloc->getSVal(CE,
C.getLocationContext());
2889 assert(FromPtr && ToPtr &&
2890 "By this point, FreeMemAux and MallocMemAux should have checked "
2891 "whether the argument or the return value is symbolic!");
2895 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2896 ReallocPair(FromPtr, Kind));
2898 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2899 return stateRealloc;
2910 if (
Call.getNumArgs() < 2)
2916 evalMulForBufferSize(
C,
Call.getArgExpr(0),
Call.getArgExpr(1));
2918 return MallocMemAux(
C,
Call, TotalSize, zeroVal, State,
2919 AllocationFamily(AF_Malloc));
2922MallocChecker::LeakInfo MallocChecker::getAllocationSite(
const ExplodedNode *N,
2929 const MemRegion *ReferenceRegion =
nullptr;
2933 if (!State->get<RegionState>(Sym))
2938 if (!ReferenceRegion) {
2939 if (
const MemRegion *MR =
C.getLocationRegionIfPostStore(N)) {
2940 SVal Val = State->getSVal(MR);
2946 ReferenceRegion = MR;
2954 if (NContext == LeakContext ||
2960 return LeakInfo(AllocNode, ReferenceRegion);
2965 assert(N &&
"HandleLeak is only called with a non-null node");
2967 const RefState *RS =
C.getState()->get<RegionState>(Sym);
2968 assert(RS &&
"cannot leak an untracked symbol");
2969 AllocationFamily Family = RS->getAllocationFamily();
2971 if (Family.Kind == AF_Alloca)
2974 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
2978 if (!Frontend || !Frontend->isEnabled())
2987 std::tie(AllocNode, Region) = getAllocationSite(N, Sym,
C);
2992 C.getSourceManager(),
2996 llvm::raw_svector_ostream os(buf);
2998 os <<
"Potential leak of memory pointed to by ";
3001 os <<
"Potential memory leak";
3004 auto R = std::make_unique<PathSensitiveBugReport>(
3005 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3007 R->markInteresting(Sym);
3008 R->addVisitor<MallocBugVisitor>(Sym,
true);
3009 if (ShouldRegisterNoOwnershipChangeVisitor)
3010 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,
this);
3011 C.emitReport(std::move(R));
3014void MallocChecker::checkDeadSymbols(
SymbolReaper &SymReaper,
3018 RegionStateTy OldRS = state->get<RegionState>();
3019 RegionStateTy::Factory &F = state->get_context<RegionState>();
3021 RegionStateTy RS = OldRS;
3023 for (
auto [Sym, State] : RS) {
3024 if (SymReaper.
isDead(Sym)) {
3025 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3026 Errors.push_back(Sym);
3028 RS = F.remove(RS, Sym);
3034 assert(state->get<ReallocPairs>() ==
3035 C.getState()->get<ReallocPairs>());
3036 assert(state->get<FreeReturnValue>() ==
3037 C.getState()->get<FreeReturnValue>());
3042 ReallocPairsTy RP = state->get<ReallocPairs>();
3043 for (
auto [Sym, ReallocPair] : RP) {
3044 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(ReallocPair.ReallocatedSym)) {
3045 state = state->remove<ReallocPairs>(Sym);
3050 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3051 for (
auto [Sym, RetSym] : FR) {
3052 if (SymReaper.
isDead(Sym) || SymReaper.
isDead(RetSym)) {
3053 state = state->remove<FreeReturnValue>(Sym);
3059 if (!Errors.empty()) {
3060 N =
C.generateNonFatalErrorNode(
C.getState());
3063 HandleLeak(Sym, N,
C);
3068 C.addTransition(state->set<RegionState>(RS), N);
3073 if (
const auto *PostFN = PostFnMap.lookup(
Call)) {
3074 (*PostFN)(
this,
C.getState(),
Call,
C);
3082 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call)) {
3089 if (!NewDeleteChecker.isEnabled())
3097 bool IsKnownToBeAllocated;
3100 false, IsKnownToBeAllocated,
3101 AllocationFamily(DE->
isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3103 C.addTransition(State);
3114 if (
const auto *DC = dyn_cast<CXXDestructorCall>(&
Call)) {
3115 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3127 if (
const auto *PreFN = PreFnMap.lookup(
Call)) {
3128 (*PreFN)(
this,
C.getState(),
Call,
C);
3144 if (MallocChecker.isEnabled() && isFreeingCall(
Call))
3150 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3151 if (!Sym || checkUseAfterFree(Sym,
C, CC->getCXXThisExpr()))
3156 for (
unsigned I = 0,
E =
Call.getNumArgs(); I !=
E; ++I) {
3158 if (isa<Loc>(ArgSVal)) {
3162 if (checkUseAfterFree(Sym,
C,
Call.getArgExpr(I)))
3168void MallocChecker::checkPreStmt(
const ReturnStmt *S,
3170 checkEscapeOnReturn(S,
C);
3176void MallocChecker::checkEndFunction(
const ReturnStmt *S,
3178 checkEscapeOnReturn(S,
C);
3181void MallocChecker::checkEscapeOnReturn(
const ReturnStmt *S,
3186 const Expr *
E = S->getRetValue();
3192 SVal RetVal =
C.getSVal(
E);
3199 if (isa<FieldRegion, ElementRegion>(MR))
3202 Sym = BMR->getSymbol();
3206 checkUseAfterFree(Sym,
C,
E);
3212void MallocChecker::checkPostStmt(
const BlockExpr *BE,
3222 cast<BlockDataRegion>(
C.getSVal(BE).getAsRegion());
3225 if (ReferencedVars.empty())
3232 for (
const auto &Var : ReferencedVars) {
3233 const VarRegion *VR = Var.getCapturedRegion();
3237 Regions.push_back(VR);
3241 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3242 C.addTransition(state);
3247 const RefState *RS =
C.getState()->get<RegionState>(Sym);
3248 return (RS && RS->isReleased());
3251bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3253 if (
Call.getNumArgs() == 0)
3256 StringRef FunctionStr =
"";
3257 if (
const auto *FD = dyn_cast<FunctionDecl>(
C.getStackFrame()->getDecl()))
3259 if (Body->getBeginLoc().isValid())
3263 C.getSourceManager(),
C.getLangOpts());
3266 if (!FunctionStr.contains(
"__isl_"))
3271 for (
const Expr *Arg : cast<CallExpr>(
Call.getOriginExpr())->arguments())
3272 if (
SymbolRef Sym =
C.getSVal(Arg).getAsSymbol())
3273 if (
const RefState *RS = State->get<RegionState>(Sym))
3274 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3276 C.addTransition(State);
3281 const Stmt *S)
const {
3284 HandleUseAfterFree(
C, S->getSourceRange(), Sym);
3292 const Stmt *S)
const {
3295 if (
const RefState *RS =
C.getState()->get<RegionState>(Sym)) {
3296 if (RS->isAllocatedOfSizeZero())
3297 HandleUseZeroAlloc(
C, RS->getStmt()->getSourceRange(), Sym);
3299 else if (
C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3300 HandleUseZeroAlloc(
C, S->getSourceRange(), Sym);
3305void MallocChecker::checkLocation(
SVal l,
bool isLoad,
const Stmt *S,
3309 checkUseAfterFree(Sym,
C, S);
3310 checkUseZeroAllocated(Sym,
C, S);
3318 bool Assumption)
const {
3319 RegionStateTy RS = state->get<RegionState>();
3320 for (
SymbolRef Sym : llvm::make_first_range(RS)) {
3325 state = state->remove<RegionState>(Sym);
3330 ReallocPairsTy RP = state->get<ReallocPairs>();
3331 for (
auto [Sym, ReallocPair] : RP) {
3338 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3339 if (
const RefState *RS = state->get<RegionState>(ReallocSym)) {
3340 if (RS->isReleased()) {
3341 switch (ReallocPair.Kind) {
3342 case OAR_ToBeFreedAfterFailure:
3343 state = state->set<RegionState>(ReallocSym,
3344 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3346 case OAR_DoNotTrackAfterFailure:
3347 state = state->remove<RegionState>(ReallocSym);
3350 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3354 state = state->remove<ReallocPairs>(Sym);
3360bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3365 EscapingSymbol =
nullptr;
3371 if (!isa<SimpleFunctionCall, ObjCMethodCall>(
Call))
3378 if (!
Call->isInSystemHeader() ||
Call->argumentsMayEscape())
3391 return *FreeWhenDone;
3397 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3398 if (FirstSlot.ends_with(
"NoCopy"))
3405 if (FirstSlot.starts_with(
"addPointer") ||
3406 FirstSlot.starts_with(
"insertPointer") ||
3407 FirstSlot.starts_with(
"replacePointer") ||
3408 FirstSlot ==
"valueWithPointer") {
3415 if (Msg->getMethodFamily() ==
OMF_init) {
3416 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3432 if (isMemCall(*
Call))
3436 if (!
Call->isInSystemHeader())
3443 StringRef FName = II->
getName();
3447 if (FName.ends_with(
"NoCopy")) {
3451 for (
unsigned i = 1; i <
Call->getNumArgs(); ++i) {
3452 const Expr *ArgE =
Call->getArgExpr(i)->IgnoreParenCasts();
3453 if (
const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3454 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3455 if (DeallocatorName ==
"kCFAllocatorNull")
3466 if (FName ==
"funopen")
3467 if (
Call->getNumArgs() >= 4 &&
Call->getArgSVal(4).isConstant(0))
3473 if (FName ==
"setbuf" || FName ==
"setbuffer" ||
3474 FName ==
"setlinebuf" || FName ==
"setvbuf") {
3475 if (
Call->getNumArgs() >= 1) {
3476 const Expr *ArgE =
Call->getArgExpr(0)->IgnoreParenCasts();
3477 if (
const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3478 if (
const VarDecl *
D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3489 if (FName ==
"CGBitmapContextCreate" ||
3490 FName ==
"CGBitmapContextCreateWithData" ||
3491 FName ==
"CVPixelBufferCreateWithBytes" ||
3492 FName ==
"CVPixelBufferCreateWithPlanarBytes" ||
3493 FName ==
"OSAtomicEnqueue") {
3497 if (FName ==
"postEvent" &&
3502 if (FName ==
"connectImpl" &&
3507 if (FName ==
"singleShotImpl" &&
3516 if (
Call->argumentsMayEscape())
3528 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3537 return checkPointerEscapeAux(State, Escaped,
Call, Kind,
3542 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3543 RS->getAllocationFamily().Kind == AF_CXXNew);
3549 bool IsConstPointerEscape)
const {
3554 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
Call, State,
3561 if (EscapingSymbol && EscapingSymbol != sym)
3564 if (
const RefState *RS = State->get<RegionState>(sym))
3565 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3567 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3573 SVal ArgVal)
const {
3574 if (!KernelZeroSizePtrValue)
3575 KernelZeroSizePtrValue =
3578 const llvm::APSInt *ArgValKnown =
3579 C.getSValBuilder().getKnownValue(State, ArgVal);
3580 return ArgValKnown && *KernelZeroSizePtrValue &&
3581 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3586 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3587 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3589 for (
const ReallocPairsTy::value_type &Pair : prevMap) {
3591 if (!currMap.lookup(sym))
3601 if (N.contains_insensitive(
"ptr") || N.contains_insensitive(
"pointer")) {
3602 if (N.contains_insensitive(
"ref") || N.contains_insensitive(
"cnt") ||
3603 N.contains_insensitive(
"intrusive") ||
3604 N.contains_insensitive(
"shared") || N.ends_with_insensitive(
"rc")) {
3618 const RefState *RSCurr = state->get<RegionState>(Sym);
3619 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3624 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3637 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3639 if (
const auto *AE = dyn_cast<AtomicExpr>(S)) {
3642 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3643 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3649 }
else if (
const auto *CE = dyn_cast<CallExpr>(S)) {
3652 if (
const auto *MD =
3672 std::unique_ptr<StackHintGeneratorForSymbol> StackHint =
nullptr;
3674 llvm::raw_svector_ostream OS(Buf);
3677 if (isAllocated(RSCurr, RSPrev, S)) {
3678 Msg =
"Memory is allocated";
3679 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3680 Sym,
"Returned allocated memory");
3682 const auto Family = RSCurr->getAllocationFamily();
3683 switch (Family.Kind) {
3688 case AF_CXXNewArray:
3689 case AF_IfNameIndex:
3690 Msg =
"Memory is released";
3691 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3692 Sym,
"Returning; memory was released");
3694 case AF_InnerBuffer: {
3697 const auto *
TypedRegion = cast<TypedValueRegion>(ObjRegion);
3699 OS <<
"Inner buffer of '" << ObjTy <<
"' ";
3702 OS <<
"deallocated by call to destructor";
3703 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3704 Sym,
"Returning; inner buffer was deallocated");
3706 OS <<
"reallocated by call to '";
3707 const Stmt *S = RSCurr->getStmt();
3708 if (
const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3709 OS << MemCallE->getMethodDecl()->getDeclName();
3710 }
else if (
const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3711 OS << OpCallE->getDirectCallee()->getDeclName();
3712 }
else if (
const auto *CallE = dyn_cast<CallExpr>(S)) {
3715 CEMgr.getSimpleCall(CallE, state, CurrentLC, {
nullptr, 0});
3716 if (
const auto *
D = dyn_cast_or_null<NamedDecl>(
Call->getDecl()))
3717 OS <<
D->getDeclName();
3722 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3723 Sym,
"Returning; inner buffer was reallocated");
3729 assert(
false &&
"Unhandled allocation family!");
3743 if (
const auto *DD = dyn_cast<CXXDestructorDecl>(LC->
getDecl())) {
3783 }
else if (isRelinquished(RSCurr, RSPrev, S)) {
3784 Msg =
"Memory ownership is transferred";
3785 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,
"");
3786 }
else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3787 Mode = ReallocationFailed;
3788 Msg =
"Reallocation failed";
3789 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3790 Sym,
"Reallocation failed");
3794 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3795 "We only support one failed realloc at a time.");
3797 FailedReallocSymbol = sym;
3802 }
else if (Mode == ReallocationFailed) {
3803 assert(FailedReallocSymbol &&
"No symbol to look for.");
3806 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3808 Msg =
"Attempt to reallocate memory";
3809 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3810 Sym,
"Returned reallocated memory");
3811 FailedReallocSymbol =
nullptr;
3826 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
3837 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,
true);
3842void MallocChecker::printState(raw_ostream &Out,
ProgramStateRef State,
3843 const char *NL,
const char *Sep)
const {
3845 RegionStateTy RS = State->get<RegionState>();
3847 if (!RS.isEmpty()) {
3848 Out << Sep <<
"MallocChecker :" << NL;
3849 for (
auto [Sym,
Data] : RS) {
3850 const RefState *RefS = State->get<RegionState>(Sym);
3851 AllocationFamily Family = RefS->getAllocationFamily();
3854 getRelevantFrontendAs<CheckerFrontend>(Family);
3860 Out <<
" (" << Frontend->
getName() <<
")";
3868namespace allocation_state {
3872 AllocationFamily Family(AF_InnerBuffer);
3873 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3883 Mgr.
getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
3891 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
3893 Chk->ShouldRegisterNoOwnershipChangeVisitor =
3895 DMMName,
"AddNoOwnershipChangeNotes");
3898bool ento::shouldRegisterDynamicMemoryModeling(
const CheckerManager &mgr) {
3902#define REGISTER_CHECKER(NAME) \
3903 void ento::register##NAME(CheckerManager &Mgr) { \
3904 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
3907 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
enum clang::sema::@1840::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)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
#define REGISTER_CHECKER(NAME)
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)
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
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 getCanonicalSizeType() const
QualType 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.
virtual StringRef getDebugTag() const =0
The description of this program point which will be dumped for debugging purposes.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
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.
const T * getAs() const
Member-template getAs<specific type>'.
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
Debug state dump callback, see CheckerManager::runCheckersForPrintState.
Checker families (where a single backend class implements multiple related frontends) should derive f...
Trivial convenience class for the common case when a certain checker frontend always uses the same bu...
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Simple checker classes that implement one frontend (i.e.
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.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
bool hasMemorySpace(ProgramStateRef State) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
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.
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isUnknownOrUndef() const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
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)
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
bool 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.
int const char * function