A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://clang.llvm.org/doxygen/MallocChecker_8cpp_source.html below:

clang: lib/StaticAnalyzer/Checkers/MallocChecker.cpp Source File

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" 92using namespace clang

;

94using namespace

std::placeholders;

106enum

AllocationFamilyKind {

117struct

AllocationFamily {

118

AllocationFamilyKind

Kind

;

119

std::optional<StringRef> CustomName;

121 explicit

AllocationFamily(AllocationFamilyKind AKind,

122

std::optional<StringRef> Name = std::nullopt)

123

:

Kind

(AKind), CustomName(Name) {

124

assert((Kind != AF_Custom || CustomName.has_value()) &&

125 "Custom family must specify also the name"

);

128 if

(Kind == AF_Custom && CustomName.value() ==

"malloc"

) {

130

CustomName = std::nullopt;

135 return

std::tie(Kind, CustomName) == std::tie(

Other

.Kind,

Other

.CustomName);

139 return

!(*

this

==

Other

);

142 void

Profile(llvm::FoldingSetNodeID &ID)

const

{

143 ID

.AddInteger(Kind);

145 if

(Kind == AF_Custom)

146 ID

.AddString(CustomName.value());

191

AllocationFamily Family;

193

RefState(Kind k,

const Stmt

*

s

, AllocationFamily family)

194

: S(

s

), K(k), Family(family) {

195

assert(family.Kind != AF_None);

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; }

208 return

K ==

X

.K && S ==

X

.S && Family ==

X

.Family;

211 static

RefState getAllocated(AllocationFamily family,

const Stmt

*

s

) {

212 return

RefState(Allocated,

s

, family);

214 static

RefState getAllocatedOfSizeZero(

const

RefState *RS) {

215 return

RefState(AllocatedOfSizeZero, RS->getStmt(),

216

RS->getAllocationFamily());

218 static

RefState getReleased(AllocationFamily family,

const Stmt

*

s

) {

219 return

RefState(Released,

s

, family);

221 static

RefState getRelinquished(AllocationFamily family,

const Stmt

*

s

) {

222 return

RefState(Relinquished,

s

, family);

224 static

RefState getEscaped(

const

RefState *RS) {

225 return

RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());

228 void

Profile(llvm::FoldingSetNodeID &ID)

const

{

234

LLVM_DUMP_METHOD

void dump

(raw_ostream &OS)

const

{

236#define CASE(ID) case ID: OS << #ID; break; 238 CASE

(AllocatedOfSizeZero)

245

LLVM_DUMP_METHOD

void dump

()

const

{

dump

(llvm::errs()); }

260

AllocationFamily Family,

261

std::optional<SVal> RetVal = std::nullopt);

275enum

OwnershipAfterReallocKind {

277

OAR_ToBeFreedAfterFailure,

287

OAR_DoNotTrackAfterFailure

300

OwnershipAfterReallocKind

Kind

;

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);

309 return

ReallocatedSym ==

X

.ReallocatedSym &&

320 if

(!

Call

.getDecl() || !isa<FunctionDecl>(

Call

.getDecl()))

327 if

(!

Call

.getDecl() || !isa<FunctionDecl>(

Call

.getDecl()))

345

:

public Checker

<check::DeadSymbols, check::PointerEscape,

346

check::ConstPointerEscape, check::PreStmt<ReturnStmt>,

347

check::EndFunction, check::PreCall, check::PostCall,

348

eval::Call, check::NewAllocator,

349

check::PostStmt<BlockExpr>, check::PostObjCMessage,

350

check::Location, eval::Assume> {

356 bool

ShouldIncludeOwnershipAnnotatedFunctions =

false

;

358 bool

ShouldRegisterNoOwnershipChangeVisitor =

false

;

368

CK_NewDeleteLeaksChecker,

369

CK_MismatchedDeallocatorChecker,

370

CK_InnerPointerChecker,

371

CK_TaintedAllocChecker,

375 using

LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;

377 bool

ChecksEnabled[CK_NumCheckKinds] = {

false

};

390 bool

Assumption)

const

;

391 void

checkLocation(

SVal

l,

bool

isLoad,

const Stmt

*S,

404 const char

*NL,

const char

*Sep)

const override

;

407 mutable

std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];

408 mutable

std::unique_ptr<BugType> BT_DoubleDelete;

409 mutable

std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];

410 mutable

std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];

411 mutable

std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];

412 mutable

std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];

413 mutable

std::unique_ptr<BugType> BT_MismatchedDealloc;

414 mutable

std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];

415 mutable

std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];

416 mutable

std::unique_ptr<BugType> BT_TaintedAlloc;

418#define CHECK_FN(NAME) \ 419 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \ 450

{{CDM::CLibrary, {

"getline"

}, 3}, &MallocChecker::preGetdelim},

451

{{CDM::CLibrary, {

"getdelim"

}, 4}, &MallocChecker::preGetdelim},

457

{{CDM::CLibrary, {

"getline"

}, 3}, &MallocChecker::checkGetdelim},

458

{{CDM::CLibrary, {

"getdelim"

}, 4}, &MallocChecker::checkGetdelim},

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},

471 static bool

isFreeingOwnershipAttrCall(

const CallEvent

&

Call

);

473 static bool

isAllocatingOwnershipAttrCall(

const CallEvent

&

Call

);

475 friend class

NoMemOwnershipChangeVisitor;

478

{{CDM::CLibrary, {

"alloca"

}, 1}, &MallocChecker::checkAlloca},

479

{{CDM::CLibrary, {

"_alloca"

}, 1}, &MallocChecker::checkAlloca},

483

{{CDM::CLibrary, {

"__builtin_alloca_with_align"

}, 2},

484

&MallocChecker::checkAlloca},

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},

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},

525 bool

hasOwnershipTakesHolds(

const CallEvent

&

Call

)

const

;

528

AllocationFamily Family)

const

;

532

AllocationFamily Family)

const

;

535 mutable

std::optional<uint64_t> KernelZeroFlagVal;

537 using

KernelZeroSizePtrValueTy = std::optional<int>;

542 mutable

std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;

548

AllocationFamily Family)

const

;

561

std::optional<SVal> RetVal = std::nullopt);

592 bool

isAlloca)

const

;

619

AllocationFamily Family)

const

;

623

[[nodiscard]] std::optional<ProgramStateRef>

646 const

OwnershipAttr *Att,

670 unsigned Num

,

bool

Hold,

bool

&IsKnownToBeAllocated,

671

AllocationFamily Family,

bool

ReturnsNullOnFailure =

false

)

const

;

697

AllocationFamily Family,

bool

ReturnsNullOnFailure =

false

,

698

std::optional<SVal> ArgValOpt = {})

const

;

716 bool

SuffixWithN =

false

)

const

;

725 const Expr

*BlockBytes);

738 bool

suppressDeallocationsInSuspiciousContexts(

const CallEvent

&

Call

,

747 const Stmt

*S)

const

;

762 bool

mayFreeAnyEscapedMemoryOrIsModeledExplicitly(

const CallEvent

*

Call

,

771 bool

IsConstPointerEscape)

const

;

780

std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,

781 bool

IsALeakCheck =

false

)

const

;

784 bool

IsALeakCheck =

false

)

const

;

786 static bool

SummarizeValue(raw_ostream &os,

SVal V

);

787 static bool

SummarizeRegion(raw_ostream &os,

const MemRegion

*MR);

790 const Expr

*DeallocExpr,

791

AllocationFamily Family)

const

;

797 const Expr

*DeallocExpr,

const

RefState *RS,

798 SymbolRef

Sym,

bool

OwnershipTransferred)

const

;

801 const Expr

*DeallocExpr, AllocationFamily Family,

802 const Expr

*AllocExpr =

nullptr

)

const

;

816 const Expr

*FreeExpr,

817

AllocationFamily Family)

const

;

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

))

852 if

(

const auto

*

Func

=

853

llvm::dyn_cast_or_null<FunctionDecl>(

Call

.getCalleeDecl()))

854 return

MallocChecker::isFreeingOwnershipAttrCall(

Func

);

861 return

CallEnterState->get<RegionState>(Sym) !=

862

CallExitEndState->get<RegionState>(Sym);

869 bool

doesFnIntendToHandleOwnership(

const Decl

*Callee,

871 const FunctionDecl

*FD = dyn_cast<FunctionDecl>(Callee);

890 if

(

const auto

*

Call

= Match.getNodeAs<

CallExpr

>(

"call"

))

891 if

(isFreeingCallAsWritten(*

Call

))

903

N->getState()->getStateManager().getContext().getSourceManager());

904 return

std::make_shared<PathDiagnosticEventPiece>(

905

L,

"Returning without deallocating memory or storing the pointer for " 906 "later deallocation"

);

913 void

Profile(llvm::FoldingSetNodeID &ID)

const override

{

915 ID

.AddPointer(&Tag);

932 enum

NotificationMode {

Normal

, ReallocationFailed };

938

NotificationMode Mode;

950

MallocBugVisitor(

SymbolRef

S,

bool

isLeak =

false

)

951

: Sym(S), Mode(

Normal

), FailedReallocSymbol(nullptr),

952

ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}

954 static void

*getTag() {

959 void Profile

(llvm::FoldingSetNodeID &ID)

const override

{

960 ID

.AddPointer(getTag());

965 static inline bool

isAllocated(

const

RefState *RSCurr,

const

RefState *RSPrev,

967 return

(isa_and_nonnull<CallExpr, CXXNewExpr>(

Stmt

) &&

969

(RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&

971

!(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));

976 static inline bool isReleased

(

const

RefState *RSCurr,

const

RefState *RSPrev,

979

(RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());

980

assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(

Stmt

)) ||

981

(!

Stmt

&& RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));

986 static inline bool

isRelinquished(

const

RefState *RSCurr,

987 const

RefState *RSPrev,

const Stmt

*

Stmt

) {

989

isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(

Stmt

) &&

990

(RSCurr && RSCurr->isRelinquished()) &&

991

(!RSPrev || !RSPrev->isRelinquished()));

998 static inline bool

hasReallocFailed(

const

RefState *RSCurr,

999 const

RefState *RSPrev,

1001 return

((!isa_and_nonnull<CallExpr>(

Stmt

)) &&

1003

(RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&

1005

!(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));

1020 return

std::make_shared<PathDiagnosticEventPiece>(L, BR.

getDescription

(),

1025 class

StackHintGeneratorForReallocationFailed

1028

StackHintGeneratorForReallocationFailed(

SymbolRef

S, StringRef M)

1031

std::string getMessageForArg(

const Expr

*ArgE,

unsigned

ArgIndex)

override

{

1036

llvm::raw_svector_ostream os(buf);

1038

os <<

"Reallocation of "

<< ArgIndex << llvm::getOrdinalSuffix(ArgIndex)

1039

<<

" parameter failed"

;

1041 return

std::string(os.str());

1045 return "Reallocation of returned value failed"

;

1064

state = state->remove<RegionState>(sym);

1075 if

(Kind != OO_New && Kind != OO_Array_New)

1091 if

(Kind != OO_Delete && Kind != OO_Array_Delete)

1094 bool

HasBody = FD->

hasBody

();

1102 return

L.

isInvalid

() || (!HasBody &&

SM

.isInSystemHeader(L));

1109bool

MallocChecker::isFreeingOwnershipAttrCall(

const CallEvent

&

Call

) {

1110 const auto

*

Func

= dyn_cast_or_null<FunctionDecl>(

Call

.getDecl());

1112 return Func

&& isFreeingOwnershipAttrCall(

Func

);

1115bool

MallocChecker::isFreeingOwnershipAttrCall(

const FunctionDecl

*

Func

) {

1116 if

(

Func

->hasAttrs()) {

1117 for

(

const auto

*I :

Func

->specific_attrs<OwnershipAttr>()) {

1118

OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();

1119 if

(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)

1126bool

MallocChecker::isFreeingCall(

const CallEvent

&

Call

)

const

{

1127 if

(FreeingMemFnMap.lookup(

Call

) || ReallocatingMemFnMap.lookup(

Call

))

1130 return

isFreeingOwnershipAttrCall(

Call

);

1133bool

MallocChecker::isAllocatingOwnershipAttrCall(

const CallEvent

&

Call

) {

1134 const auto

*

Func

= dyn_cast_or_null<FunctionDecl>(

Call

.getDecl());

1136 return Func

&& isAllocatingOwnershipAttrCall(

Func

);

1139bool

MallocChecker::isAllocatingOwnershipAttrCall(

const FunctionDecl

*

Func

) {

1140 for

(

const auto

*I :

Func

->specific_attrs<OwnershipAttr>()) {

1141 if

(I->getOwnKind() == OwnershipAttr::Returns)

1148bool

MallocChecker::isMemCall(

const CallEvent

&

Call

)

const

{

1149 if

(FreeingMemFnMap.lookup(

Call

) || AllocatingMemFnMap.lookup(

Call

) ||

1150

AllocaMemFnMap.lookup(

Call

) || ReallocatingMemFnMap.lookup(

Call

))

1153 if

(!ShouldIncludeOwnershipAnnotatedFunctions)

1156 const auto

*

Func

= dyn_cast<FunctionDecl>(

Call

.getDecl());

1157 return Func

&&

Func

->hasAttr<OwnershipAttr>();

1160

std::optional<ProgramStateRef>

1182 if

(!KernelZeroFlagVal) {

1184 case

llvm::Triple::FreeBSD:

1185

KernelZeroFlagVal = 0x0100;

1187 case

llvm::Triple::NetBSD:

1188

KernelZeroFlagVal = 0x0002;

1190 case

llvm::Triple::OpenBSD:

1191

KernelZeroFlagVal = 0x0008;

1193 case

llvm::Triple::Linux:

1195

KernelZeroFlagVal = 0x8000;

1203 return

std::nullopt;

1210 if

(

Call

.getNumArgs() < 2)

1211 return

std::nullopt;

1213 const Expr

*FlagsEx =

Call

.getArgExpr(

Call

.getNumArgs() - 1);

1214 const SVal V

=

C

.getSVal(FlagsEx);

1215 if

(!isa<NonLoc>(

V

)) {

1218 return

std::nullopt;

1222 NonLoc

ZeroFlag =

C

.getSValBuilder()

1223

.makeIntVal(*KernelZeroFlagVal, FlagsEx->

getType

())

1225 SVal

MaskedFlagsUC =

C

.getSValBuilder().evalBinOpNN(State, BO_And,

1229 return

std::nullopt;

1234

std::tie(TrueState, FalseState) = State->assume(MaskedFlags);

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));

1243 return

std::nullopt;

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,

1261

AllocationFamily(AF_Malloc));

1262

State = ProcessZeroAllocCheck(

C

,

Call

, 0, State);

1263 C

.addTransition(State);

1269

std::optional<ProgramStateRef> MaybeState =

1270

performKernelMalloc(

Call

,

C

, State);

1272

State = *MaybeState;

1275

AllocationFamily(AF_Malloc));

1276 C

.addTransition(State);

1303 bool

ShouldFreeOnFail)

const

{

1312

State = ReallocMemAux(

C

,

Call

, ShouldFreeOnFail, State,

1313

AllocationFamily(AF_Malloc));

1314

State = ProcessZeroAllocCheck(

C

,

Call

, 1, State);

1315 C

.addTransition(State);

1320

State = CallocMem(

C

,

Call

, State);

1321

State = ProcessZeroAllocCheck(

C

,

Call

, 0, State);

1322

State = ProcessZeroAllocCheck(

C

,

Call

, 1, State);

1323 C

.addTransition(State);

1328 bool

IsKnownToBeAllocatedMemory =

false

;

1329 if

(suppressDeallocationsInSuspiciousContexts(

Call

,

C

))

1331

State = FreeMemAux(

C

,

Call

, State, 0,

false

, IsKnownToBeAllocatedMemory,

1332

AllocationFamily(AF_Malloc));

1333 C

.addTransition(State);

1339

AllocationFamily(AF_Alloca));

1340

State = ProcessZeroAllocCheck(

C

,

Call

, 0, State);

1341 C

.addTransition(State);

1346 const auto

*CE = dyn_cast_or_null<CallExpr>(

Call

.getOriginExpr());

1350

AllocationFamily(AF_Malloc));

1352 C

.addTransition(State);

1361

AllocationFamily(AF_IfNameIndex));

1363 C

.addTransition(State);

1369 bool

IsKnownToBeAllocatedMemory =

false

;

1370

State = FreeMemAux(

C

,

Call

, State, 0,

false

, IsKnownToBeAllocatedMemory,

1371

AllocationFamily(AF_IfNameIndex));

1372 C

.addTransition(State);

1378 bool

IsKnownToBeAllocatedMemory =

false

;

1379 const auto

*CE = dyn_cast_or_null<CallExpr>(

Call

.getOriginExpr());

1393

AllocationFamily(AF_CXXNew));

1394

State = ProcessZeroAllocCheck(

C

,

Call

, 0, State);

1398

AllocationFamily(AF_CXXNewArray));

1399

State = ProcessZeroAllocCheck(

C

,

Call

, 0, State);

1402

State = FreeMemAux(

C

,

Call

, State, 0,

false

, IsKnownToBeAllocatedMemory,

1403

AllocationFamily(AF_CXXNew));

1405 case

OO_Array_Delete:

1406

State = FreeMemAux(

C

,

Call

, State, 0,

false

, IsKnownToBeAllocatedMemory,

1407

AllocationFamily(AF_CXXNewArray));

1410

assert(

false

&&

"not a new/delete operator"

);

1414 C

.addTransition(State);

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);

1430

AllocationFamily(AF_Malloc));

1431

State = ProcessZeroAllocCheck(

C

,

Call

, 1, State);

1432 C

.addTransition(State);

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);

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);

1460

assert(FD &&

"a CallDescription cannot match a call without a Decl"

);

1479 bool

IsKnownToBeAllocated =

false

;

1480

State = FreeMemAux(

C

,

Call

.getArgExpr(0),

Call

, State,

false

,

1481

IsKnownToBeAllocated, AllocationFamily(AF_Malloc),

false

,

1484 C

.addTransition(State);

1496 const CallExpr

*CE = dyn_cast_or_null<CallExpr>(

Call

.getOriginExpr());

1500 const auto

LinePtr =

1504 if

(!LinePtr || !Size || !LinePtr->getAsRegion())

1509

AllocationFamily(AF_Malloc), *LinePtr));

1514

State = ReallocMemAux(

C

,

Call

,

false

, State,

1515

AllocationFamily(AF_Malloc),

1517

State = ProcessZeroAllocCheck(

C

,

Call

, 1, State);

1518

State = ProcessZeroAllocCheck(

C

,

Call

, 2, State);

1519 C

.addTransition(State);

1525 const auto

*CE = dyn_cast_or_null<CallExpr>(

Call

.getOriginExpr());

1531 if

(ShouldIncludeOwnershipAnnotatedFunctions ||

1532

ChecksEnabled[CK_MismatchedDeallocatorChecker]) {

1537 switch

(I->getOwnKind()) {

1538 case

OwnershipAttr::Returns:

1539

State = MallocMemReturnsAttr(

C

,

Call

, I, State);

1541 case

OwnershipAttr::Takes:

1542 case

OwnershipAttr::Holds:

1543

State = FreeMemAttr(

C

,

Call

, I, State);

1548 C

.addTransition(State);

1552 if

(!

Call

.getOriginExpr())

1557 if

(

const

CheckFn *Callback = FreeingMemFnMap.lookup(

Call

)) {

1558

(*Callback)(

this

, State,

Call

,

C

);

1562 if

(

const

CheckFn *Callback = AllocatingMemFnMap.lookup(

Call

)) {

1563

State = MallocBindRetVal(

C

,

Call

, State,

false

);

1564

(*Callback)(

this

, State,

Call

,

C

);

1568 if

(

const

CheckFn *Callback = ReallocatingMemFnMap.lookup(

Call

)) {

1569

State = MallocBindRetVal(

C

,

Call

, State,

false

);

1570

(*Callback)(

this

, State,

Call

,

C

);

1575

State = MallocBindRetVal(

C

,

Call

, State,

false

);

1576

checkCXXNewOrCXXDelete(State,

Call

,

C

);

1581

checkCXXNewOrCXXDelete(State,

Call

,

C

);

1585 if

(

const

CheckFn *Callback = AllocaMemFnMap.lookup(

Call

)) {

1586

State = MallocBindRetVal(

C

,

Call

, State,

true

);

1587

(*Callback)(

this

, State,

Call

,

C

);

1591 if

(isFreeingOwnershipAttrCall(

Call

)) {

1592

checkOwnershipAttr(State,

Call

,

C

);

1596 if

(isAllocatingOwnershipAttrCall(

Call

)) {

1597

State = MallocBindRetVal(

C

,

Call

, State,

false

);

1598

checkOwnershipAttr(State,

Call

,

C

);

1612 const Expr

*Arg =

nullptr

;

1614 if

(

const CallExpr

*CE = dyn_cast<CallExpr>(

Call

.getOriginExpr())) {

1615

Arg = CE->

getArg

(IndexOfSizeArg);

1617

dyn_cast<CXXNewExpr>(

Call

.getOriginExpr())) {

1618 if

(

NE

->isArray()) {

1619

Arg = *

NE

->getArraySize();

1624

assert(

false

&&

"not a CallExpr or CXXNewExpr"

);

1629

RetVal = State->getSVal(

Call

.getOriginExpr(),

C

.getLocationContext());

1634

State->getSVal(Arg,

Call

.getLocationContext()).getAs<

DefinedSVal

>();

1641 SValBuilder

&SvalBuilder = State->getStateManager().getSValBuilder();

1645

std::tie(TrueState, FalseState) =

1646

State->assume(SvalBuilder.

evalEQ

(State, *DefArgVal, Zero));

1648 if

(TrueState && !FalseState) {

1649 SymbolRef

Sym = RetVal->getAsLocSymbol();

1653 const

RefState *RS = State->get<RegionState>(Sym);

1655 if

(RS->isAllocated())

1656 return

TrueState->set<RegionState>(Sym,

1657

RefState::getAllocatedOfSizeZero(RS));

1665 return

TrueState->add<ReallocSizeZeroSymbols>(Sym);

1676 while

(!PointeeType.isNull()) {

1677

Result = PointeeType;

1678

PointeeType = PointeeType->getPointeeType();

1691 if

(!NE->getAllocatedType()->getAsCXXRecordDecl())

1697 for

(

const auto

*CtorParam : CtorD->

parameters

()) {

1700 if

(CtorParamPointeeT.

isNull

())

1715

AllocationFamily Family)

const

{

1720 const ParentMap

&PM =

C

.getLocationContext()->getParentMap();

1735 if

(

Call

.getOriginExpr()->isArray()) {

1736 if

(

auto

SizeEx =

NE

->getArraySize())

1737

checkTaintedness(

C

,

Call

,

C

.getSVal(*SizeEx), State,

1738

AllocationFamily(AF_CXXNewArray));

1742

State = ProcessZeroAllocCheck(

C

,

Call

, 0, State,

Target

);

1748 if

(!

C

.wasInlined) {

1751

AllocationFamily(

Call

.getOriginExpr()->isArray() ? AF_CXXNewArray

1753 C

.addTransition(State);

1763

StringRef FirstSlot =

Call

.getSelector().getNameForSlot(0);

1764 return

FirstSlot ==

"dataWithBytesNoCopy"

||

1765

FirstSlot ==

"initWithBytesNoCopy"

||

1766

FirstSlot ==

"initWithCharactersNoCopy"

;

1773 for

(

unsigned

i = 1; i < S.getNumArgs(); ++i)

1774 if

(S.getNameForSlot(i) ==

"freeWhenDone"

)

1775 return

!

Call

.getArgSVal(i).isZeroConstant();

1777 return

std::nullopt;

1792 if

(

Call

.hasNonZeroCallbackArg())

1795 bool

IsKnownToBeAllocatedMemory;

1797 true

, IsKnownToBeAllocatedMemory,

1798

AllocationFamily(AF_Malloc),

1801 C

.addTransition(State);

1806 const

OwnershipAttr *Att,

1811 auto

attrClassName = Att->getModule()->getName();

1812 auto

Family = AllocationFamily(AF_Custom, attrClassName);

1814 if

(!Att->args().empty()) {

1815 return

MallocMemAux(

C

,

Call

,

1816 Call

.getArgExpr(Att->args_begin()->getASTIndex()),

1825 bool

isAlloca)

const

{

1826 const Expr

*CE =

Call

.getOriginExpr();

1832 unsigned

Count =

C

.blockCount();

1837 return

State->BindExpr(CE,

C

.getLocationContext(), RetVal);

1844

AllocationFamily Family)

const

{

1849 return

MallocMemAux(

C

,

Call

,

C

.getSVal(SizeEx),

Init

, State, Family);

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<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N);

1862 for

(

auto

TaintedSym : TaintedSyms) {

1863

R->markInteresting(TaintedSym);

1865 C

.emitReport(std::move(R));

1871

AllocationFamily Family)

const

{

1872 if

(!ChecksEnabled[CK_TaintedAllocChecker])

1874

std::vector<SymbolRef> TaintedSyms =

1876 if

(TaintedSyms.empty())

1885 const

llvm::APSInt MaxValInt = BVF.

getMaxValue

(SizeTy);

1888

std::optional<NonLoc> SizeNL = SizeSVal.

getAs

<

NonLoc

>();

1889 auto

Cmp = SVB.

evalBinOpNN

(State, BO_GE, *SizeNL, MaxLength, CmpTy)

1893 auto

[StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);

1894 if

(!StateTooLarge && StateNotTooLarge) {

1899

std::string

Callee

=

"Memory allocation function"

;

1900 if

(

Call

.getCalleeIdentifier())

1901

Callee =

Call

.getCalleeIdentifier()->getName().str();

1903

Callee +

" is called with a tainted (potentially attacker controlled) " 1904 "value. Make sure the value is bound checked."

,

1905

State,

C

, TaintedSyms, Family);

1911

AllocationFamily Family)

const

{

1915 const Expr

*CE =

Call

.getOriginExpr();

1920 "Allocation functions must return a pointer"

);

1923 SVal

RetVal = State->getSVal(CE,

C

.getLocationContext());

1926

State = State->bindDefaultInitial(RetVal,

Init

, LCtx);

1929 if

(

Size

.isUndef())

1932

checkTaintedness(

C

,

Call

, Size, State, AllocationFamily(AF_Malloc));

1943

AllocationFamily Family,

1944

std::optional<SVal> RetVal) {

1950

RetVal = State->getSVal(

E

,

C

.getLocationContext());

1953 if

(!RetVal->getAs<

Loc

>())

1956 SymbolRef

Sym = RetVal->getAsLocSymbol();

1964 return

State->set<RegionState>(Sym, RefState::getAllocated(Family,

E

));

1971 const

OwnershipAttr *Att,

1976 auto

attrClassName = Att->getModule()->getName();

1977 auto

Family = AllocationFamily(AF_Custom, attrClassName);

1979 bool

IsKnownToBeAllocated =

false

;

1981 for

(

const auto

&Arg : Att->args()) {

1983

FreeMemAux(

C

,

Call

, State, Arg.getASTIndex(),

1984

Att->getOwnKind() == OwnershipAttr::Holds,

1985

IsKnownToBeAllocated, Family);

1995 bool

Hold,

bool

&IsKnownToBeAllocated,

1996

AllocationFamily Family,

1997 bool

ReturnsNullOnFailure)

const

{

2001 if

(

Call

.getNumArgs() < (

Num

+ 1))

2004 return

FreeMemAux(

C

,

Call

.getArgExpr(

Num

),

Call

, State, Hold,

2005

IsKnownToBeAllocated, Family, ReturnsNullOnFailure);

2012 const SymbolRef

*Ret = State->get<FreeReturnValue>(Sym);

2014

assert(*Ret &&

"We should not store the null return symbol"

);

2017

RetStatusSymbol = *Ret;

2025 const CallExpr

*CE = dyn_cast<CallExpr>(

E

);

2036 if

(I->getOwnKind() != OwnershipAttr::Takes)

2039

os <<

", which takes ownership of '"

<< I->getModule()->

getName

() <<

'\''

;

2045 if

(

const CallExpr

*CE = dyn_cast<CallExpr>(

E

)) {

2061 if

(Msg->isInstanceMessage())

2065

Msg->getSelector().

print

(os);

2069 if

(

const CXXNewExpr

*NE = dyn_cast<CXXNewExpr>(

E

)) {

2088 switch

(Family.Kind) {

2090

os <<

"'malloc()'"

;

2095 case

AF_CXXNewArray:

2098 case

AF_IfNameIndex:

2099

os <<

"'if_nameindex()'"

;

2101 case

AF_InnerBuffer:

2102

os <<

"container-specific allocator"

;

2105

os << Family.CustomName.value();

2109

assert(

false

&&

"not a deallocation expression"

);

2114 switch

(Family.Kind) {

2121 case

AF_CXXNewArray:

2122

os <<

"'delete[]'"

;

2124 case

AF_IfNameIndex:

2125

os <<

"'if_freenameindex()'"

;

2127 case

AF_InnerBuffer:

2128

os <<

"container-specific deallocator"

;

2131

os <<

"function that takes ownership of '"

<< Family.CustomName.value()

2136

assert(

false

&&

"not a deallocation expression"

);

2143 bool

Hold,

bool

&IsKnownToBeAllocated,

2144

AllocationFamily Family,

bool

ReturnsNullOnFailure,

2145

std::optional<SVal> ArgValOpt)

const

{

2150 SVal

ArgVal = ArgValOpt.value_or(

C

.getSVal(ArgExpr));

2151 if

(!isa<DefinedOrUnknownSVal>(ArgVal))

2156 if

(!isa<Loc>(location))

2161

std::tie(notNullState, nullState) = State->assume(location);

2162 if

(nullState && !notNullState)

2171 const Expr

*ParentExpr =

Call

.getOriginExpr();

2190 if

(Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State,

C

, ArgVal))

2191

HandleNonHeapDealloc(

C

, ArgVal, ArgExpr->

getSourceRange

(), ParentExpr,

2199 if

(isa<BlockDataRegion>(R)) {

2200

HandleNonHeapDealloc(

C

, ArgVal, ArgExpr->

getSourceRange

(), ParentExpr,

2209 if

(!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {

2215 if

(isa<AllocaRegion>(R))

2218

HandleNonHeapDealloc(

C

, ArgVal, ArgExpr->

getSourceRange

(), ParentExpr,

2231 const

RefState *RsBase = State->get<RegionState>(SymBase);

2232 SymbolRef

PreviousRetStatusSymbol =

nullptr

;

2234

IsKnownToBeAllocated =

2235

RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());

2240 if

(RsBase->getAllocationFamily().Kind == AF_Alloca) {

2246 if

((RsBase->isReleased() || RsBase->isRelinquished()) &&

2248

HandleDoubleFree(

C

, ParentExpr->

getSourceRange

(), RsBase->isReleased(),

2249

SymBase, PreviousRetStatusSymbol);

2254

}

else if

(RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||

2255

RsBase->isEscaped()) {

2258 bool

DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;

2259 if

(!DeallocMatchesAlloc) {

2261

RsBase, SymBase, Hold);

2268 if

(Offset.isValid() &&

2269

!Offset.hasSymbolicOffset() &&

2270

Offset.getOffset() != 0) {

2271 const Expr

*AllocExpr = cast<Expr>(RsBase->getStmt());

2272

HandleOffsetFree(

C

, ArgVal, ArgExpr->

getSourceRange

(), ParentExpr,

2280

HandleFunctionPtrFree(

C

, ArgVal, ArgExpr->

getSourceRange

(), ParentExpr,

2286

State = State->remove<FreeReturnValue>(SymBase);

2290 if

(ReturnsNullOnFailure) {

2291 SVal

RetVal =

C

.getSVal(ParentExpr);

2293 if

(RetStatusSymbol) {

2294 C

.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);

2295

State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);

2303

assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));

2308

State = State->invalidateRegions({location},

Call

.getOriginExpr(),

2309 C

.blockCount(),

C

.getLocationContext(),

2315 return

State->set<RegionState>(SymBase,

2316

RefState::getRelinquished(Family,

2319 return

State->set<RegionState>(SymBase,

2320

RefState::getReleased(Family, ParentExpr));

2323

std::optional<MallocChecker::CheckKind>

2324

MallocChecker::getCheckIfTracked(AllocationFamily Family,

2325 bool

IsALeakCheck)

const

{

2326 switch

(Family.Kind) {

2330 case

AF_IfNameIndex: {

2331 if

(ChecksEnabled[CK_MallocChecker])

2332 return

CK_MallocChecker;

2333 return

std::nullopt;

2336 case

AF_CXXNewArray: {

2338 if

(ChecksEnabled[CK_NewDeleteLeaksChecker])

2339 return

CK_NewDeleteLeaksChecker;

2342 if

(ChecksEnabled[CK_NewDeleteChecker])

2343 return

CK_NewDeleteChecker;

2345 return

std::nullopt;

2347 case

AF_InnerBuffer: {

2348 if

(ChecksEnabled[CK_InnerPointerChecker])

2349 return

CK_InnerPointerChecker;

2350 return

std::nullopt;

2353

assert(

false

&&

"no family"

);

2354 return

std::nullopt;

2357

assert(

false

&&

"unhandled family"

);

2358 return

std::nullopt;

2361

std::optional<MallocChecker::CheckKind>

2363 bool

IsALeakCheck)

const

{

2364 if

(

C

.getState()->contains<ReallocSizeZeroSymbols>(Sym))

2365 return

CK_MallocChecker;

2367 const

RefState *RS =

C

.getState()->get<RegionState>(Sym);

2369 return

getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);

2372bool

MallocChecker::SummarizeValue(raw_ostream &os,

SVal V

) {

2373 if

(std::optional<nonloc::ConcreteInt> IntVal =

2375

os <<

"an integer ("

<< IntVal->getValue() <<

")"

;

2376 else if

(std::optional<loc::ConcreteInt> ConstAddr =

2378

os <<

"a constant address ("

<< ConstAddr->getValue() <<

")"

;

2380

os <<

"the address of the label '"

<<

Label

->getLabel()->getName() <<

"'"

;

2387bool

MallocChecker::SummarizeRegion(raw_ostream &os,

2390 case

MemRegion::FunctionCodeRegionKind: {

2391 const NamedDecl

*FD = cast<FunctionCodeRegion>(MR)->getDecl();

2393

os <<

"the address of the function '"

<< *FD <<

'\''

;

2395

os <<

"the address of a function"

;

2398 case

MemRegion::BlockCodeRegionKind:

2399

os <<

"block text"

;

2401 case

MemRegion::BlockDataRegionKind:

2408 if

(isa<StackLocalsSpaceRegion>(MS)) {

2409 const VarRegion

*VR = dyn_cast<VarRegion>(MR);

2417

os <<

"the address of the local variable '"

<< VD->

getName

() <<

"'"

;

2419

os <<

"the address of a local stack variable"

;

2423 if

(isa<StackArgumentsSpaceRegion>(MS)) {

2424 const VarRegion

*VR = dyn_cast<VarRegion>(MR);

2432

os <<

"the address of the parameter '"

<< VD->

getName

() <<

"'"

;

2434

os <<

"the address of a parameter"

;

2438 if

(isa<GlobalsSpaceRegion>(MS)) {

2439 const VarRegion

*VR = dyn_cast<VarRegion>(MR);

2448

os <<

"the address of the static variable '"

<< VD->

getName

() <<

"'"

;

2450

os <<

"the address of the global variable '"

<< VD->

getName

() <<

"'"

;

2452

os <<

"the address of a global variable"

;

2463 const Expr

*DeallocExpr,

2464

AllocationFamily Family)

const

{

2466 if

(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2471

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);

2476 if

(!BT_BadFree[*CheckKind])

2477

BT_BadFree[*CheckKind].reset(

new BugType

(

2481

llvm::raw_svector_ostream os(buf);

2484 while

(

const ElementRegion

*ER = dyn_cast_or_null<ElementRegion>(MR))

2485

MR = ER->getSuperRegion();

2487

os <<

"Argument to "

;

2489

os <<

"deallocator"

;

2492 bool

Summarized = MR ? SummarizeRegion(os, MR)

2493

: SummarizeValue(os, ArgVal);

2495

os <<

", which is not memory allocated by "

;

2497

os <<

"not memory allocated by "

;

2501 auto

R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],

2503

R->markInteresting(MR);

2504

R->addRange(

Range

);

2505 C

.emitReport(std::move(R));

2512

std::optional<MallocChecker::CheckKind> CheckKind;

2514 if

(ChecksEnabled[CK_MallocChecker])

2515

CheckKind = CK_MallocChecker;

2516 else if

(ChecksEnabled[CK_MismatchedDeallocatorChecker])

2517

CheckKind = CK_MismatchedDeallocatorChecker;

2524 if

(!BT_FreeAlloca[*CheckKind])

2525

BT_FreeAlloca[*CheckKind].reset(

new BugType

(

2528 auto

R = std::make_unique<PathSensitiveBugReport>(

2529

*BT_FreeAlloca[*CheckKind],

2530 "Memory allocated by 'alloca()' should not be deallocated"

, N);

2532

R->addRange(

Range

);

2533 C

.emitReport(std::move(R));

2539 const Expr

*DeallocExpr,

2541 bool

OwnershipTransferred)

const

{

2543 if

(!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {

2549 if

(!BT_MismatchedDealloc)

2550

BT_MismatchedDealloc.reset(

2551 new BugType

(CheckNames[CK_MismatchedDeallocatorChecker],

2555

llvm::raw_svector_ostream os(buf);

2557 const Expr

*AllocExpr = cast<Expr>(RS->getStmt());

2559

llvm::raw_svector_ostream AllocOs(AllocBuf);

2561

llvm::raw_svector_ostream DeallocOs(DeallocBuf);

2563 if

(OwnershipTransferred) {

2565

os << DeallocOs.str() <<

" cannot"

;

2569

os <<

" take ownership of memory"

;

2572

os <<

" allocated by "

<< AllocOs.str();

2576

os <<

" allocated by "

<< AllocOs.str();

2578

os <<

" should be deallocated by "

;

2582

os <<

", not "

<< DeallocOs.str();

2587 auto

R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,

2589

R->markInteresting(Sym);

2590

R->addRange(

Range

);

2591

R->addVisitor<MallocBugVisitor>(Sym);

2592 C

.emitReport(std::move(R));

2598

AllocationFamily Family,

2599 const Expr

*AllocExpr)

const

{

2601 if

(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2606

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);

2614 if

(!BT_OffsetFree[*CheckKind])

2615

BT_OffsetFree[*CheckKind].reset(

new BugType

(

2619

llvm::raw_svector_ostream os(buf);

2621

llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);

2624

assert(MR &&

"Only MemRegion based symbols can have offset free errors"

);

2627

assert((Offset.isValid() &&

2628

!Offset.hasSymbolicOffset() &&

2629

Offset.getOffset() != 0) &&

2630 "Only symbols with a valid offset can have offset free errors"

);

2632 int

offsetBytes = Offset.getOffset() /

C

.getASTContext().getCharWidth();

2634

os <<

"Argument to "

;

2636

os <<

"deallocator"

;

2637

os <<

" is offset by " 2640

<< ((

abs

(offsetBytes) > 1) ?

"bytes"

:

"byte"

)

2641

<<

" from the start of "

;

2643

os <<

"memory allocated by "

<< AllocNameOs.str();

2645

os <<

"allocated memory"

;

2647 auto

R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],

2650

R->addRange(

Range

);

2651 C

.emitReport(std::move(R));

2657 if

(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&

2658

!ChecksEnabled[CK_InnerPointerChecker]) {

2663

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(

C

, Sym);

2668 if

(!BT_UseFree[*CheckKind])

2669

BT_UseFree[*CheckKind].reset(

new BugType

(

2672

AllocationFamily AF =

2673 C

.getState()->get<RegionState>(Sym)->getAllocationFamily();

2675 auto

R = std::make_unique<PathSensitiveBugReport>(

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"

,

2682

R->markInteresting(Sym);

2683

R->addRange(

Range

);

2684

R->addVisitor<MallocBugVisitor>(Sym);

2686 if

(AF.Kind == AF_InnerBuffer)

2689 C

.emitReport(std::move(R));

2697 if

(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2702

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(

C

, Sym);

2707 if

(!BT_DoubleFree[*CheckKind])

2708

BT_DoubleFree[*CheckKind].reset(

new BugType

(

2711 auto

R = std::make_unique<PathSensitiveBugReport>(

2712

*BT_DoubleFree[*CheckKind],

2713

(Released ?

"Attempt to free released memory" 2714

:

"Attempt to free non-owned memory"

),

2716

R->addRange(

Range

);

2717

R->markInteresting(Sym);

2719

R->markInteresting(PrevSym);

2720

R->addVisitor<MallocBugVisitor>(Sym);

2721 C

.emitReport(std::move(R));

2727 if

(!ChecksEnabled[CK_NewDeleteChecker]) {

2732

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(

C

, Sym);

2737 if

(!BT_DoubleDelete)

2738

BT_DoubleDelete.reset(

new BugType

(CheckNames[CK_NewDeleteChecker],

2742 auto

R = std::make_unique<PathSensitiveBugReport>(

2743

*BT_DoubleDelete,

"Attempt to delete released memory"

, N);

2745

R->markInteresting(Sym);

2746

R->addVisitor<MallocBugVisitor>(Sym);

2747 C

.emitReport(std::move(R));

2754 if

(!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2759

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(

C

, Sym);

2765 if

(!BT_UseZerroAllocated[*CheckKind])

2766

BT_UseZerroAllocated[*CheckKind].reset(

2767 new BugType

(CheckNames[*CheckKind],

"Use of zero allocated"

,

2770 auto

R = std::make_unique<PathSensitiveBugReport>(

2771

*BT_UseZerroAllocated[*CheckKind],

2772 "Use of memory allocated with size zero"

, N);

2774

R->addRange(

Range

);

2776

R->markInteresting(Sym);

2777

R->addVisitor<MallocBugVisitor>(Sym);

2779 C

.emitReport(std::move(R));

2785 const Expr

*FreeExpr,

2786

AllocationFamily Family)

const

{

2787 if

(!ChecksEnabled[CK_MallocChecker]) {

2792

std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);

2797 if

(!BT_BadFree[*CheckKind])

2798

BT_BadFree[*CheckKind].reset(

new BugType

(

2802

llvm::raw_svector_ostream Os(Buf);

2805 while

(

const ElementRegion

*ER = dyn_cast_or_null<ElementRegion>(MR))

2806

MR = ER->getSuperRegion();

2808

Os <<

"Argument to "

;

2810

Os <<

"deallocator"

;

2812

Os <<

" is a function pointer"

;

2814 auto

R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],

2816

R->markInteresting(MR);

2817

R->addRange(

Range

);

2818 C

.emitReport(std::move(R));

2825

AllocationFamily Family,

bool

SuffixWithN)

const

{

2829 const CallExpr

*CE = cast<CallExpr>(

Call

.getOriginExpr());

2837 SVal

Arg0Val =

C

.getSVal(arg0Expr);

2838 if

(!isa<DefinedOrUnknownSVal>(Arg0Val))

2845

State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->

getType

()));

2851 SVal

TotalSize =

C

.getSVal(Arg1);

2853

TotalSize = evalMulForBufferSize(

C

, Arg1, CE->

getArg

(2));

2854 if

(!isa<DefinedOrUnknownSVal>(TotalSize))

2860

svalBuilder.makeIntValWithWidth(

2861

svalBuilder.getContext().getSizeType(), 0));

2864

std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);

2866

std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);

2869 bool

PrtIsNull = StatePtrIsNull && !StatePtrNotNull;

2870 bool

SizeIsZero = StateSizeIsZero && !StateSizeNotZero;

2874 if

(PrtIsNull && !SizeIsZero) {

2881 if

(PrtIsNull && SizeIsZero)

2886 bool

IsKnownToBeAllocated =

false

;

2895 C

,

Call

, StateSizeIsZero, 0,

false

, IsKnownToBeAllocated, Family))

2900

FreeMemAux(

C

,

Call

, State, 0,

false

, IsKnownToBeAllocated, Family)) {

2903

MallocMemAux(

C

,

Call

, TotalSize,

UnknownVal

(), stateFree, Family);

2907

OwnershipAfterReallocKind

Kind

= OAR_ToBeFreedAfterFailure;

2908 if

(ShouldFreeOnFail)

2909 Kind

= OAR_FreeOnFailure;

2910 else if

(!IsKnownToBeAllocated)

2911 Kind

= OAR_DoNotTrackAfterFailure;

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!"

);

2923

stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,

2924

ReallocPair(FromPtr, Kind));

2926 C

.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);

2927 return

stateRealloc;

2938 if

(

Call

.getNumArgs() < 2)

2944

evalMulForBufferSize(

C

,

Call

.getArgExpr(0),

Call

.getArgExpr(1));

2946 return

MallocMemAux(

C

,

Call

, TotalSize, zeroVal, State,

2947

AllocationFamily(AF_Malloc));

2950

MallocChecker::LeakInfo MallocChecker::getAllocationSite(

const ExplodedNode

*N,

2957 const MemRegion

*ReferenceRegion =

nullptr

;

2961 if

(!State->get<RegionState>(Sym))

2966 if

(!ReferenceRegion) {

2967 if

(

const MemRegion

*MR =

C

.getLocationRegionIfPostStore(N)) {

2968 SVal

Val = State->getSVal(MR);

2974

ReferenceRegion = MR;

2982 if

(NContext == LeakContext ||

2988 return

LeakInfo(AllocNode, ReferenceRegion);

2994 if

(!ChecksEnabled[CK_MallocChecker] &&

2995

!ChecksEnabled[CK_NewDeleteLeaksChecker])

2998 const

RefState *RS =

C

.getState()->get<RegionState>(Sym);

2999

assert(RS &&

"cannot leak an untracked symbol"

);

3000

AllocationFamily Family = RS->getAllocationFamily();

3002 if

(Family.Kind == AF_Alloca)

3005

std::optional<MallocChecker::CheckKind> CheckKind =

3006

getCheckIfTracked(Family,

true

);

3012 if

(!BT_Leak[*CheckKind]) {

3018

BT_Leak[*CheckKind].reset(

new BugType

(CheckNames[*CheckKind],

"Memory leak"

,

3029

std::tie(AllocNode, Region) = getAllocationSite(N, Sym,

C

);

3034 C

.getSourceManager(),

3038

llvm::raw_svector_ostream os(buf);

3040

os <<

"Potential leak of memory pointed to by "

;

3043

os <<

"Potential memory leak"

;

3046 auto

R = std::make_unique<PathSensitiveBugReport>(

3047

*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,

3049

R->markInteresting(Sym);

3050

R->addVisitor<MallocBugVisitor>(Sym,

true

);

3051 if

(ShouldRegisterNoOwnershipChangeVisitor)

3052

R->addVisitor<NoMemOwnershipChangeVisitor>(Sym,

this

);

3053 C

.emitReport(std::move(R));

3056void

MallocChecker::checkDeadSymbols(

SymbolReaper

&SymReaper,

3060

RegionStateTy OldRS = state->get<RegionState>();

3061

RegionStateTy::Factory &F = state->get_context<RegionState>();

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);

3070

RS = F.remove(RS, Sym);

3076

assert(state->get<ReallocPairs>() ==

3077 C

.getState()->get<ReallocPairs>());

3078

assert(state->get<FreeReturnValue>() ==

3079 C

.getState()->get<FreeReturnValue>());

3084

ReallocPairsTy RP = state->get<ReallocPairs>();

3085 for

(

auto

[Sym, ReallocPair] : RP) {

3086 if

(SymReaper.

isDead

(Sym) || SymReaper.

isDead

(ReallocPair.ReallocatedSym)) {

3087

state = state->remove<ReallocPairs>(Sym);

3092

FreeReturnValueTy FR = state->get<FreeReturnValue>();

3093 for

(

auto

[Sym, RetSym] : FR) {

3094 if

(SymReaper.

isDead

(Sym) || SymReaper.

isDead

(RetSym)) {

3095

state = state->remove<FreeReturnValue>(Sym);

3101 if

(!Errors.empty()) {

3103

N =

C

.generateNonFatalErrorNode(

C

.getState(), &Tag);

3106

HandleLeak(Sym, N,

C

);

3111 C

.addTransition(state->set<RegionState>(RS), N);

3116 if

(

const auto

*PostFN = PostFnMap.lookup(

Call

)) {

3117

(*PostFN)(

this

,

C

.getState(),

Call

,

C

);

3125 if

(

const auto

*DC = dyn_cast<CXXDeallocatorCall>(&

Call

)) {

3128 if

(!ChecksEnabled[CK_NewDeleteChecker])

3136 bool

IsKnownToBeAllocated;

3139 false

, IsKnownToBeAllocated,

3140

AllocationFamily(DE->

isArrayForm

() ? AF_CXXNewArray : AF_CXXNew));

3142 C

.addTransition(State);

3146 if

(

const auto

*DC = dyn_cast<CXXDestructorCall>(&

Call

)) {

3147 SymbolRef

Sym = DC->getCXXThisVal().getAsSymbol();

3148 if

(!Sym || checkDoubleDelete(Sym,

C

))

3154 if

(

const auto

*PreFN = PreFnMap.lookup(

Call

)) {

3155

(*PreFN)(

this

,

C

.getState(),

Call

,

C

);

3165 if

(ChecksEnabled[CK_MallocChecker] && isFreeingCall(

Call

))

3171 SymbolRef

Sym = CC->getCXXThisVal().getAsSymbol();

3172 if

(!Sym || checkUseAfterFree(Sym,

C

, CC->getCXXThisExpr()))

3177 for

(

unsigned

I = 0,

E

=

Call

.getNumArgs(); I !=

E

; ++I) {

3178 SVal

ArgSVal =

Call

.getArgSVal(I);

3179 if

(isa<Loc>(ArgSVal)) {

3183 if

(checkUseAfterFree(Sym,

C

,

Call

.getArgExpr(I)))

3189void

MallocChecker::checkPreStmt(

const ReturnStmt

*S,

3191

checkEscapeOnReturn(S,

C

);

3197void

MallocChecker::checkEndFunction(

const ReturnStmt

*S,

3199

checkEscapeOnReturn(S,

C

);

3202void

MallocChecker::checkEscapeOnReturn(

const ReturnStmt

*S,

3207 const Expr

*

E

= S->getRetValue();

3213 SVal

RetVal =

C

.getSVal(

E

);

3220 if

(isa<FieldRegion, ElementRegion>(MR))

3223

Sym = BMR->getSymbol();

3227

checkUseAfterFree(Sym,

C

,

E

);

3233void

MallocChecker::checkPostStmt(

const BlockExpr

*BE,

3243

cast<BlockDataRegion>(

C

.getSVal(BE).getAsRegion());

3246 if

(ReferencedVars.empty())

3253 for

(

const auto

&Var : ReferencedVars) {

3254 const VarRegion

*VR = Var.getCapturedRegion();

3258

Regions.push_back(VR);

3262

state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();

3263 C

.addTransition(state);

3268 const

RefState *RS =

C

.getState()->get<RegionState>(Sym);

3269 return

(RS && RS->isReleased());

3272bool

MallocChecker::suppressDeallocationsInSuspiciousContexts(

3274 if

(

Call

.getNumArgs() == 0)

3277

StringRef FunctionStr =

""

;

3278 if

(

const auto

*FD = dyn_cast<FunctionDecl>(

C

.getStackFrame()->getDecl()))

3280 if

(Body->getBeginLoc().isValid())

3284 C

.getSourceManager(),

C

.getLangOpts());

3287 if

(!FunctionStr.contains(

"__isl_"

))

3292 for

(

const Expr

*Arg : cast<CallExpr>(

Call

.getOriginExpr())->arguments())

3293 if

(

SymbolRef

Sym =

C

.getSVal(Arg).getAsSymbol())

3294 if

(

const

RefState *RS = State->get<RegionState>(Sym))

3295

State = State->set<RegionState>(Sym, RefState::getEscaped(RS));

3297 C

.addTransition(State);

3302 const Stmt

*S)

const

{

3305

HandleUseAfterFree(

C

, S->getSourceRange(), Sym);

3313 const Stmt

*S)

const

{

3316 if

(

const

RefState *RS =

C

.getState()->get<RegionState>(Sym)) {

3317 if

(RS->isAllocatedOfSizeZero())

3318

HandleUseZeroAlloc(

C

, RS->getStmt()->getSourceRange(), Sym);

3320 else if

(

C

.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {

3321

HandleUseZeroAlloc(

C

, S->getSourceRange(), Sym);

3328

HandleDoubleDelete(

C

, Sym);

3335void

MallocChecker::checkLocation(

SVal

l,

bool

isLoad,

const Stmt

*S,

3339

checkUseAfterFree(Sym,

C

, S);

3340

checkUseZeroAllocated(Sym,

C

, S);

3348 bool

Assumption)

const

{

3349

RegionStateTy RS = state->get<RegionState>();

3350 for

(

SymbolRef

Sym : llvm::make_first_range(RS)) {

3355

state = state->remove<RegionState>(Sym);

3360

ReallocPairsTy RP = state->get<ReallocPairs>();

3361 for

(

auto

[Sym, ReallocPair] : RP) {

3368 SymbolRef

ReallocSym = ReallocPair.ReallocatedSym;

3369 if

(

const

RefState *RS = state->get<RegionState>(ReallocSym)) {

3370 if

(RS->isReleased()) {

3371 switch

(ReallocPair.Kind) {

3372 case

OAR_ToBeFreedAfterFailure:

3373

state = state->set<RegionState>(ReallocSym,

3374

RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));

3376 case

OAR_DoNotTrackAfterFailure:

3377

state = state->remove<RegionState>(ReallocSym);

3380

assert(ReallocPair.Kind == OAR_FreeOnFailure);

3384

state = state->remove<ReallocPairs>(Sym);

3390bool

MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(

3395

EscapingSymbol =

nullptr

;

3401 if

(!isa<SimpleFunctionCall, ObjCMethodCall>(

Call

))

3408 if

(!

Call

->isInSystemHeader() ||

Call

->argumentsMayEscape())

3421 return

*FreeWhenDone;

3427

StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);

3428 if

(FirstSlot.ends_with(

"NoCopy"

))

3435 if

(FirstSlot.starts_with(

"addPointer"

) ||

3436

FirstSlot.starts_with(

"insertPointer"

) ||

3437

FirstSlot.starts_with(

"replacePointer"

) ||

3438

FirstSlot ==

"valueWithPointer"

) {

3445 if

(Msg->getMethodFamily() ==

OMF_init

) {

3446

EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();

3462 if

(isMemCall(*

Call

))

3466 if

(!

Call

->isInSystemHeader())

3473

StringRef FName = II->

getName

();

3477 if

(FName.ends_with(

"NoCopy"

)) {

3481 for

(

unsigned

i = 1; i <

Call

->getNumArgs(); ++i) {

3482 const Expr

*ArgE =

Call

->getArgExpr(i)->IgnoreParenCasts();

3483 if

(

const DeclRefExpr

*DE = dyn_cast<DeclRefExpr>(ArgE)) {

3484

StringRef DeallocatorName = DE->getFoundDecl()->getName();

3485 if

(DeallocatorName ==

"kCFAllocatorNull"

)

3496 if

(FName ==

"funopen"

)

3497 if

(

Call

->getNumArgs() >= 4 &&

Call

->getArgSVal(4).isConstant(0))

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<DeclRefExpr>(ArgE))

3508 if

(

const VarDecl

*

D

= dyn_cast<VarDecl>(ArgDRE->getDecl()))

3519 if

(FName ==

"CGBitmapContextCreate"

||

3520

FName ==

"CGBitmapContextCreateWithData"

||

3521

FName ==

"CVPixelBufferCreateWithBytes"

||

3522

FName ==

"CVPixelBufferCreateWithPlanarBytes"

||

3523

FName ==

"OSAtomicEnqueue"

) {

3527 if

(FName ==

"postEvent"

&&

3532 if

(FName ==

"connectImpl"

&&

3537 if

(FName ==

"singleShotImpl"

&&

3546 if

(

Call

->argumentsMayEscape())

3558 return

checkPointerEscapeAux(State, Escaped,

Call

, Kind,

3567 return

checkPointerEscapeAux(State, Escaped,

Call

, Kind,

3572 return

(RS->getAllocationFamily().Kind == AF_CXXNewArray ||

3573

RS->getAllocationFamily().Kind == AF_CXXNew);

3579 bool

IsConstPointerEscape)

const

{

3584

!mayFreeAnyEscapedMemoryOrIsModeledExplicitly(

Call

, State,

3591 if

(EscapingSymbol && EscapingSymbol != sym)

3594 if

(

const

RefState *RS = State->get<RegionState>(sym))

3595 if

(RS->isAllocated() || RS->isAllocatedOfSizeZero())

3597

State = State->set<RegionState>(sym, RefState::getEscaped(RS));

3603 SVal

ArgVal)

const

{

3604 if

(!KernelZeroSizePtrValue)

3605

KernelZeroSizePtrValue =

3608 const

llvm::APSInt *ArgValKnown =

3609 C

.getSValBuilder().getKnownValue(State, ArgVal);

3610 return

ArgValKnown && *KernelZeroSizePtrValue &&

3611

ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;

3616

ReallocPairsTy currMap = currState->get<ReallocPairs>();

3617

ReallocPairsTy prevMap = prevState->get<ReallocPairs>();

3619 for

(

const

ReallocPairsTy::value_type &Pair : prevMap) {

3621 if

(!currMap.lookup(sym))

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"

)) {

3648 const

RefState *RSCurr = state->get<RegionState>(Sym);

3649 const

RefState *RSPrev = statePrev->get<RegionState>(Sym);

3654 if

(!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))

3667 if

(ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||

3668

ReleaseFunctionLC->

isParentOf

(CurrentLC))) {

3669 if

(

const auto

*AE = dyn_cast<AtomicExpr>(S)) {

3672 if

(Op == AtomicExpr::AO__c11_atomic_fetch_add ||

3673

Op == AtomicExpr::AO__c11_atomic_fetch_sub) {

3679

}

else if

(

const auto

*CE = dyn_cast<CallExpr>(S)) {

3682 if

(

const auto

*MD =

3702

std::unique_ptr<StackHintGeneratorForSymbol> StackHint =

nullptr

;

3704

llvm::raw_svector_ostream OS(Buf);

3707 if

(isAllocated(RSCurr, RSPrev, S)) {

3708

Msg =

"Memory is allocated"

;

3709

StackHint = std::make_unique<StackHintGeneratorForSymbol>(

3710

Sym,

"Returned allocated memory"

);

3711

}

else if

(

isReleased

(RSCurr, RSPrev, S)) {

3712 const auto

Family = RSCurr->getAllocationFamily();

3713 switch

(Family.Kind) {

3718 case

AF_CXXNewArray:

3719 case

AF_IfNameIndex:

3720

Msg =

"Memory is released"

;

3721

StackHint = std::make_unique<StackHintGeneratorForSymbol>(

3722

Sym,

"Returning; memory was released"

);

3724 case

AF_InnerBuffer: {

3727 const auto

*

TypedRegion

= cast<TypedValueRegion>(ObjRegion);

3729

OS <<

"Inner buffer of '"

<< ObjTy <<

"' "

;

3732

OS <<

"deallocated by call to destructor"

;

3733

StackHint = std::make_unique<StackHintGeneratorForSymbol>(

3734

Sym,

"Returning; inner buffer was deallocated"

);

3736

OS <<

"reallocated by call to '"

;

3737 const Stmt

*S = RSCurr->getStmt();

3738 if

(

const auto

*MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {

3739

OS << MemCallE->getMethodDecl()->getDeclName();

3740

}

else if

(

const auto

*OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {

3741

OS << OpCallE->getDirectCallee()->getDeclName();

3742

}

else if

(

const auto

*CallE = dyn_cast<CallExpr>(S)) {

3745

CEMgr.getSimpleCall(CallE, state, CurrentLC, {

nullptr

, 0});

3746 if

(

const auto

*

D

= dyn_cast_or_null<NamedDecl>(

Call

->getDecl()))

3747

OS <<

D

->getDeclName();

3752

StackHint = std::make_unique<StackHintGeneratorForSymbol>(

3753

Sym,

"Returning; inner buffer was reallocated"

);

3759

assert(

false

&&

"Unhandled allocation family!"

);

3764

assert(!ReleaseFunctionLC &&

"There should be only one release point"

);

3771 if

(

const auto

*DD = dyn_cast<CXXDestructorDecl>(LC->

getDecl

())) {

3811

}

else if

(isRelinquished(RSCurr, RSPrev, S)) {

3812

Msg =

"Memory ownership is transferred"

;

3813

StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym,

""

);

3814

}

else if

(hasReallocFailed(RSCurr, RSPrev, S)) {

3815

Mode = ReallocationFailed;

3816

Msg =

"Reallocation failed"

;

3817

StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(

3818

Sym,

"Reallocation failed"

);

3822

assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&

3823 "We only support one failed realloc at a time."

);

3825

FailedReallocSymbol = sym;

3830

}

else if

(Mode == ReallocationFailed) {

3831

assert(FailedReallocSymbol &&

"No symbol to look for."

);

3834 if

(!statePrev->get<RegionState>(FailedReallocSymbol)) {

3836

Msg =

"Attempt to reallocate memory"

;

3837

StackHint = std::make_unique<StackHintGeneratorForSymbol>(

3838

Sym,

"Returned reallocated memory"

);

3839

FailedReallocSymbol =

nullptr

;

3854

assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);

3865 auto P

= std::make_shared<PathDiagnosticEventPiece>(Pos, Msg,

true

);

3870void

MallocChecker::printState(raw_ostream &Out,

ProgramStateRef

State,

3871 const char

*NL,

const char

*Sep)

const

{

3873

RegionStateTy RS = State->get<RegionState>();

3875 if

(!RS.isEmpty()) {

3876

Out << Sep <<

"MallocChecker :"

<< NL;

3877 for

(

auto

[Sym,

Data

] : RS) {

3878 const

RefState *RefS = State->get<RegionState>(Sym);

3879

AllocationFamily Family = RefS->getAllocationFamily();

3880

std::optional<MallocChecker::CheckKind> CheckKind =

3881

getCheckIfTracked(Family);

3883

CheckKind = getCheckIfTracked(Family,

true

);

3889

Out <<

" ("

<< CheckNames[*CheckKind].getName() <<

")"

;

3897namespace

allocation_state {

3901

AllocationFamily Family(AF_InnerBuffer);

3902 return

State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));

3912

MallocChecker *checker = mgr.

getChecker

<MallocChecker>();

3913

checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] =

true

;

3914

checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =

3920

checker->ShouldIncludeOwnershipAnnotatedFunctions =

3922

checker->ShouldRegisterNoOwnershipChangeVisitor =

3924

checker,

"AddNoOwnershipChangeNotes"

);

3927bool

ento::shouldRegisterDynamicMemoryModeling(

const CheckerManager

&mgr) {

3931#define REGISTER_CHECKER(name) \ 3932 void ento::register##name(CheckerManager &mgr) { \ 3933 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \ 3934 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \ 3935 checker->CheckNames[MallocChecker::CK_##name] = \ 3936 mgr.getCurrentCheckerName(); \ 3939 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }

enum clang::sema::@1704::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.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4