@@ -70,9 +70,16 @@ class RefState {
70
70
}
71
71
};
72
72
73
+ // / \class ReallocPair
74
+ // / \brief Stores information about the symbol being reallocated by a call to
75
+ // / 'realloc' to allow modeling failed reallocation later in the path.
73
76
struct ReallocPair {
77
+ // \brief The symbol which realloc reallocated.
74
78
SymbolRef ReallocatedSym;
79
+ // \brief The flag is true if the symbol does not need to be freed after
80
+ // reallocation fails.
75
81
bool IsFreeOnFailure;
82
+
76
83
ReallocPair (SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {}
77
84
void Profile (llvm::FoldingSetNodeID &ID) const {
78
85
ID.AddInteger (IsFreeOnFailure);
@@ -177,11 +184,13 @@ class MallocChecker : public Checker<check::DeadSymbols,
177
184
const OwnershipAttr* Att) const ;
178
185
ProgramStateRef FreeMemAux (CheckerContext &C, const CallExpr *CE,
179
186
ProgramStateRef state, unsigned Num,
180
- bool Hold) const ;
187
+ bool Hold,
188
+ bool &ReleasedAllocated) const ;
181
189
ProgramStateRef FreeMemAux (CheckerContext &C, const Expr *Arg,
182
190
const Expr *ParentExpr,
183
191
ProgramStateRef state,
184
- bool Hold) const ;
192
+ bool Hold,
193
+ bool &ReleasedAllocated) const ;
185
194
186
195
ProgramStateRef ReallocMem (CheckerContext &C, const CallExpr *CE,
187
196
bool FreesMemOnFailure) const ;
@@ -431,6 +440,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
431
440
return ;
432
441
433
442
ProgramStateRef State = C.getState ();
443
+ bool ReleasedAllocatedMemory = false ;
434
444
435
445
if (FD->getKind () == Decl::Function) {
436
446
initIdentifierInfo (C.getASTContext ());
@@ -447,7 +457,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
447
457
} else if (FunI == II_calloc) {
448
458
State = CallocMem (C, CE);
449
459
} else if (FunI == II_free) {
450
- State = FreeMemAux (C, CE, State, 0 , false );
460
+ State = FreeMemAux (C, CE, State, 0 , false , ReleasedAllocatedMemory );
451
461
} else if (FunI == II_strdup) {
452
462
State = MallocUpdateRefState (C, CE, State);
453
463
} else if (FunI == II_strndup) {
@@ -494,14 +504,16 @@ void MallocChecker::checkPreObjCMessage(const ObjCMethodCall &Call,
494
504
// Ex: [NSData dataWithBytesNoCopy:bytes length:10];
495
505
// Unless 'freeWhenDone' param set to 0.
496
506
// TODO: Check that the memory was allocated with malloc.
507
+ bool ReleasedAllocatedMemory = false ;
497
508
Selector S = Call.getSelector ();
498
509
if ((S.getNameForSlot (0 ) == " dataWithBytesNoCopy" ||
499
510
S.getNameForSlot (0 ) == " initWithBytesNoCopy" ||
500
511
S.getNameForSlot (0 ) == " initWithCharactersNoCopy" ) &&
501
512
!isFreeWhenDoneSetToZero (Call)){
502
513
unsigned int argIdx = 0 ;
503
514
C.addTransition (FreeMemAux (C, Call.getArgExpr (argIdx),
504
- Call.getOriginExpr (), C.getState (), true ));
515
+ Call.getOriginExpr (), C.getState (), true ,
516
+ ReleasedAllocatedMemory));
505
517
}
506
518
}
507
519
@@ -584,11 +596,13 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
584
596
return 0 ;
585
597
586
598
ProgramStateRef State = C.getState ();
599
+ bool ReleasedAllocated = false ;
587
600
588
601
for (OwnershipAttr::args_iterator I = Att->args_begin (), E = Att->args_end ();
589
602
I != E; ++I) {
590
603
ProgramStateRef StateI = FreeMemAux (C, CE, State, *I,
591
- Att->getOwnKind () == OwnershipAttr::Holds);
604
+ Att->getOwnKind () == OwnershipAttr::Holds,
605
+ ReleasedAllocated);
592
606
if (StateI)
593
607
State = StateI;
594
608
}
@@ -599,18 +613,20 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
599
613
const CallExpr *CE,
600
614
ProgramStateRef state,
601
615
unsigned Num,
602
- bool Hold) const {
616
+ bool Hold,
617
+ bool &ReleasedAllocated) const {
603
618
if (CE->getNumArgs () < (Num + 1 ))
604
619
return 0 ;
605
620
606
- return FreeMemAux (C, CE->getArg (Num), CE, state, Hold);
621
+ return FreeMemAux (C, CE->getArg (Num), CE, state, Hold, ReleasedAllocated );
607
622
}
608
623
609
624
ProgramStateRef MallocChecker::FreeMemAux (CheckerContext &C,
610
625
const Expr *ArgExpr,
611
626
const Expr *ParentExpr,
612
627
ProgramStateRef state,
613
- bool Hold) const {
628
+ bool Hold,
629
+ bool &ReleasedAllocated) const {
614
630
615
631
SVal ArgVal = state->getSVal (ArgExpr, C.getLocationContext ());
616
632
if (!isa<DefinedOrUnknownSVal>(ArgVal))
@@ -691,6 +707,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
691
707
return 0 ;
692
708
}
693
709
710
+ ReleasedAllocated = (RS != 0 );
711
+
694
712
// Normal free.
695
713
if (Hold)
696
714
return state->set <RegionState>(Sym, RefState::getRelinquished (ParentExpr));
@@ -886,9 +904,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
886
904
if (!FromPtr || !ToPtr)
887
905
return 0 ;
888
906
907
+ bool ReleasedAllocated = false ;
908
+
889
909
// If the size is 0, free the memory.
890
910
if (SizeIsZero)
891
- if (ProgramStateRef stateFree = FreeMemAux (C, CE, StateSizeIsZero,0 ,false )){
911
+ if (ProgramStateRef stateFree = FreeMemAux (C, CE, StateSizeIsZero, 0 ,
912
+ false , ReleasedAllocated)){
892
913
// The semantics of the return value are:
893
914
// If size was equal to 0, either NULL or a pointer suitable to be passed
894
915
// to free() is returned. We just free the input pointer and do not add
@@ -897,14 +918,19 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
897
918
}
898
919
899
920
// Default behavior.
900
- if (ProgramStateRef stateFree = FreeMemAux (C, CE, state, 0 , false )) {
901
- // FIXME: We should copy the content of the original buffer.
921
+ if (ProgramStateRef stateFree =
922
+ FreeMemAux (C, CE, state, 0 , false , ReleasedAllocated)) {
923
+
902
924
ProgramStateRef stateRealloc = MallocMemAux (C, CE, CE->getArg (1 ),
903
925
UnknownVal (), stateFree);
904
926
if (!stateRealloc)
905
927
return 0 ;
928
+
929
+ // Record the info about the reallocated symbol so that we could properly
930
+ // process failed reallocation.
906
931
stateRealloc = stateRealloc->set <ReallocPairs>(ToPtr,
907
- ReallocPair (FromPtr, FreesOnFail));
932
+ ReallocPair (FromPtr, FreesOnFail || !ReleasedAllocated));
933
+ // The reallocated symbol should stay alive for as long as the new symbol.
908
934
C.getSymbolManager ().addSymbolDependency (ToPtr, FromPtr);
909
935
return stateRealloc;
910
936
}
0 commit comments