#include "AllocationState.h"
#include "InterCheckerAPI.h"
#include "NoOwnershipChangeVisitor.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Checkers/Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
#include <optional>
#include <utility>
usingnamespaceclang;
usingnamespaceento;
usingnamespacestd::placeholders;
namespace {
enum AllocationFamilyKind { … };
struct AllocationFamily { … };
}
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E);
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family);
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);
namespace {
class RefState { … };
}
REGISTER_MAP_WITH_PROGRAMSTATE(…)
static bool isReleased(SymbolRef Sym, CheckerContext &C);
static ProgramStateRef
MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
AllocationFamily Family,
std::optional<SVal> RetVal = std::nullopt);
REGISTER_SET_WITH_PROGRAMSTATE(…)
namespace {
enum OwnershipAfterReallocKind { … };
struct ReallocPair { … };
}
REGISTER_MAP_WITH_PROGRAMSTATE(…)
static bool isStandardNew(const FunctionDecl *FD);
static bool isStandardNew(const CallEvent &Call) { … }
static bool isStandardDelete(const FunctionDecl *FD);
static bool isStandardDelete(const CallEvent &Call) { … }
template <typename T> static bool isStandardNewDelete(const T &FD) { … }
namespace {
class MallocChecker
: public Checker<check::DeadSymbols, check::PointerEscape,
check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
check::EndFunction, check::PreCall, check::PostCall,
eval::Call, check::NewAllocator,
check::PostStmt<BlockExpr>, check::PostObjCMessage,
check::Location, eval::Assume> { … };
}
namespace {
class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor { … };
}
namespace {
class MallocBugVisitor final : public BugReporterVisitor { … };
}
REGISTER_MAP_WITH_PROGRAMSTATE(…)
namespace {
class StopTrackingCallback final : public SymbolVisitor { … };
}
static bool isStandardNew(const FunctionDecl *FD) { … }
static bool isStandardDelete(const FunctionDecl *FD) { … }
bool MallocChecker::isFreeingOwnershipAttrCall(const CallEvent &Call) { … }
bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) { … }
bool MallocChecker::isFreeingCall(const CallEvent &Call) const { … }
bool MallocChecker::isAllocatingOwnershipAttrCall(const CallEvent &Call) { … }
bool MallocChecker::isAllocatingOwnershipAttrCall(const FunctionDecl *Func) { … }
bool MallocChecker::isMemCall(const CallEvent &Call) const { … }
std::optional<ProgramStateRef>
MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
const ProgramStateRef &State) const { … }
SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
const Expr *BlockBytes) { … }
void MallocChecker::checkBasicAlloc(ProgramStateRef State,
const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkKernelMalloc(ProgramStateRef State,
const CallEvent &Call,
CheckerContext &C) const { … }
static bool isStandardRealloc(const CallEvent &Call) { … }
static bool isGRealloc(const CallEvent &Call) { … }
void MallocChecker::checkRealloc(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C,
bool ShouldFreeOnFail) const { … }
void MallocChecker::checkCalloc(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkFree(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkAlloca(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkStrdup(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkIfNameIndex(ProgramStateRef State,
const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,
const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkGMalloc0(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkGMemdup(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkGMallocN(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkGMallocN0(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
static bool isFromStdNamespace(const CallEvent &Call) { … }
void MallocChecker::preGetdelim(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkGetdelim(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkReallocN(ProgramStateRef State, const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkOwnershipAttr(ProgramStateRef State,
const CallEvent &Call,
CheckerContext &C) const { … }
bool MallocChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { … }
ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
CheckerContext &C, const CallEvent &Call, const unsigned IndexOfSizeArg,
ProgramStateRef State, std::optional<SVal> RetVal) { … }
static QualType getDeepPointeeType(QualType T) { … }
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) { … }
ProgramStateRef
MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
CheckerContext &C,
AllocationFamily Family) const { … }
void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
CheckerContext &C) const { … }
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) { … }
static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) { … }
void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
CheckerContext &C) const { … }
ProgramStateRef
MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
const OwnershipAttr *Att,
ProgramStateRef State) const { … }
ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
const CallEvent &Call,
ProgramStateRef State,
bool isAlloca) const { … }
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallEvent &Call,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family) const { … }
void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,
CheckerContext &C,
llvm::ArrayRef<SymbolRef> TaintedSyms,
AllocationFamily Family) const { … }
void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call,
const SVal SizeSVal, ProgramStateRef State,
AllocationFamily Family) const { … }
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallEvent &Call, SVal Size,
SVal Init, ProgramStateRef State,
AllocationFamily Family) const { … }
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
ProgramStateRef State,
AllocationFamily Family,
std::optional<SVal> RetVal) { … }
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
const CallEvent &Call,
const OwnershipAttr *Att,
ProgramStateRef State) const { … }
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const CallEvent &Call,
ProgramStateRef State, unsigned Num,
bool Hold, bool &IsKnownToBeAllocated,
AllocationFamily Family,
bool ReturnsNullOnFailure) const { … }
static bool didPreviousFreeFail(ProgramStateRef State,
SymbolRef Sym, SymbolRef &RetStatusSymbol) { … }
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C,
const Expr *E) { … }
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) { … }
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) { … }
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) { … }
ProgramStateRef
MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
const CallEvent &Call, ProgramStateRef State,
bool Hold, bool &IsKnownToBeAllocated,
AllocationFamily Family, bool ReturnsNullOnFailure,
std::optional<SVal> ArgValOpt) const { … }
std::optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(AllocationFamily Family,
bool IsALeakCheck) const { … }
std::optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
bool IsALeakCheck) const { … }
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { … }
bool MallocChecker::SummarizeRegion(raw_ostream &os,
const MemRegion *MR) { … }
void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
SourceRange Range,
const Expr *DeallocExpr,
AllocationFamily Family) const { … }
void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const { … }
void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
SourceRange Range,
const Expr *DeallocExpr,
const RefState *RS, SymbolRef Sym,
bool OwnershipTransferred) const { … }
void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
SourceRange Range, const Expr *DeallocExpr,
AllocationFamily Family,
const Expr *AllocExpr) const { … }
void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const { … }
void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
bool Released, SymbolRef Sym,
SymbolRef PrevSym) const { … }
void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const { … }
void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const { … }
void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
SourceRange Range,
const Expr *FreeExpr,
AllocationFamily Family) const { … }
ProgramStateRef
MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,
bool ShouldFreeOnFail, ProgramStateRef State,
AllocationFamily Family, bool SuffixWithN) const { … }
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,
const CallEvent &Call,
ProgramStateRef State) const { … }
MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
SymbolRef Sym,
CheckerContext &C) { … }
void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
CheckerContext &C) const { … }
void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
CheckerContext &C) const
{ … }
void MallocChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const { … }
void MallocChecker::checkPreStmt(const ReturnStmt *S,
CheckerContext &C) const { … }
void MallocChecker::checkEndFunction(const ReturnStmt *S,
CheckerContext &C) const { … }
void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
CheckerContext &C) const { … }
void MallocChecker::checkPostStmt(const BlockExpr *BE,
CheckerContext &C) const { … }
static bool isReleased(SymbolRef Sym, CheckerContext &C) { … }
bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
const CallEvent &Call, CheckerContext &C) const { … }
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const { … }
void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const { … }
bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const { … }
void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const { … }
ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
SVal Cond,
bool Assumption) const { … }
bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const CallEvent *Call,
ProgramStateRef State,
SymbolRef &EscapingSymbol) const { … }
ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const { … }
ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const { … }
static bool checkIfNewOrNewArrayFamily(const RefState *RS) { … }
ProgramStateRef MallocChecker::checkPointerEscapeAux(
ProgramStateRef State, const InvalidatedSymbols &Escaped,
const CallEvent *Call, PointerEscapeKind Kind,
bool IsConstPointerEscape) const { … }
bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
SVal ArgVal) const { … }
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
ProgramStateRef prevState) { … }
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) { … }
PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
PathSensitiveBugReport &BR) { … }
void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const { … }
namespace clang {
namespace ento {
namespace allocation_state {
ProgramStateRef
markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) { … }
}
}
}
void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) { … }
void ento::registerDynamicMemoryModeling(CheckerManager &mgr) { … }
bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) { … }
#define REGISTER_CHECKER(name) …
REGISTER_CHECKER(MallocChecker)
REGISTER_CHECKER(NewDeleteChecker)
REGISTER_CHECKER(NewDeleteLeaksChecker)
REGISTER_CHECKER(MismatchedDeallocatorChecker)
REGISTER_CHECKER(TaintedAllocChecker)