Skip to content

Commit 3563fde

Browse files
committed
[analyzer] Anti-aliasing: different heap allocations do not alias
Add a concept of symbolic memory region belonging to heap memory space. When comparing symbolic regions allocated on the heap, assume that they do not alias. Use symbolic heap region to suppress a common false positive pattern in the malloc checker, in code that relies on malloc not returning the memory aliased to other malloc allocations, stack. llvm-svn: 158136
1 parent 5fb2e4d commit 3563fde

File tree

7 files changed

+110
-31
lines changed

7 files changed

+110
-31
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,8 +1130,11 @@ class MemRegionManager {
11301130
const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
11311131
const LocationContext *LC);
11321132

1133-
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
1134-
const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
1133+
/// \brief Retrieve or create a "symbolic" memory region.
1134+
const SymbolicRegion* getSymbolicRegion(SymbolRef Sym);
1135+
1136+
/// \brief Return a unique symbolic region belonging to heap memory space.
1137+
const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym);
11351138

11361139
const StringRegion *getStringRegion(const StringLiteral* Str);
11371140

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ class SValBuilder {
182182
const LocationContext *LCtx,
183183
QualType type,
184184
unsigned visitCount);
185+
/// \brief Conjure a symbol representing heap allocated memory region.
186+
///
187+
/// Note, the expression should represent a location.
188+
DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E,
189+
const LocationContext *LCtx,
190+
unsigned Count);
185191

186192
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
187193
SymbolRef parentSymbol, const TypedValueRegion *region);

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,19 +477,27 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
477477
const CallExpr *CE,
478478
SVal Size, SVal Init,
479479
ProgramStateRef state) {
480-
// Get the return value.
481-
SVal retVal = state->getSVal(CE, C.getLocationContext());
480+
481+
// Bind the return value to the symbolic value from the heap region.
482+
// TODO: We could rewrite post visit to eval call; 'malloc' does not have
483+
// side effects other than what we model here.
484+
unsigned Count = C.getCurrentBlockCount();
485+
SValBuilder &svalBuilder = C.getSValBuilder();
486+
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
487+
DefinedSVal RetVal =
488+
cast<DefinedSVal>(svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count));
489+
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
482490

483491
// We expect the malloc functions to return a pointer.
484-
if (!isa<Loc>(retVal))
492+
if (!isa<Loc>(RetVal))
485493
return 0;
486494

487495
// Fill the region with the initialization value.
488-
state = state->bindDefault(retVal, Init);
496+
state = state->bindDefault(RetVal, Init);
489497

490498
// Set the region's extent equal to the Size parameter.
491499
const SymbolicRegion *R =
492-
dyn_cast_or_null<SymbolicRegion>(retVal.getAsRegion());
500+
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
493501
if (!R)
494502
return 0;
495503
if (isa<DefinedOrUnknownSVal>(Size)) {

clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,10 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
849849
return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
850850
}
851851

852+
const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
853+
return getSubRegion<SymbolicRegion>(Sym, getHeapRegion());
854+
}
855+
852856
const FieldRegion*
853857
MemRegionManager::getFieldRegion(const FieldDecl *d,
854858
const MemRegion* superRegion){

clang/lib/StaticAnalyzer/Core/SValBuilder.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,18 @@ SValBuilder::getConjuredSymbolVal(const Stmt *stmt,
148148
return nonloc::SymbolVal(sym);
149149
}
150150

151+
DefinedOrUnknownSVal
152+
SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
153+
const LocationContext *LCtx,
154+
unsigned VisitCount) {
155+
QualType T = E->getType();
156+
assert(Loc::isLocType(T));
157+
assert(SymbolManager::canSymbolicate(T));
158+
159+
SymbolRef sym = SymMgr.getConjuredSymbol(E, LCtx, T, VisitCount);
160+
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
161+
}
162+
151163
DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag,
152164
const MemRegion *region,
153165
const Expr *expr, QualType type,

clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -673,11 +673,18 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
673673
// regions, though.
674674
return UnknownVal();
675675

676-
// If both values wrap regions, see if they're from different base regions.
676+
const MemSpaceRegion *LeftMS = LeftMR->getMemorySpace();
677+
const MemSpaceRegion *RightMS = RightMR->getMemorySpace();
678+
const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
677679
const MemRegion *LeftBase = LeftMR->getBaseRegion();
678680
const MemRegion *RightBase = RightMR->getBaseRegion();
679-
if (LeftBase != RightBase &&
680-
!isa<SymbolicRegion>(LeftBase) && !isa<SymbolicRegion>(RightBase)) {
681+
682+
// If the two regions are from different known memory spaces they cannot be
683+
// equal. Also, assume that no symbolic region (whose memory space is
684+
// unknown) is on the stack.
685+
if (LeftMS != RightMS &&
686+
((LeftMS != UnknownMS && RightMS != UnknownMS) ||
687+
(isa<StackSpaceRegion>(LeftMS) || isa<StackSpaceRegion>(RightMS)))) {
681688
switch (op) {
682689
default:
683690
return UnknownVal();
@@ -688,24 +695,20 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
688695
}
689696
}
690697

691-
// The two regions are from the same base region. See if they're both a
692-
// type of region we know how to compare.
693-
const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
694-
const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
695-
696-
// Heuristic: assume that no symbolic region (whose memory space is
697-
// unknown) is on the stack.
698-
// FIXME: we should be able to be more precise once we can do better
699-
// aliasing constraints for symbolic regions, but this is a reasonable,
700-
// albeit unsound, assumption that holds most of the time.
701-
if (isa<StackSpaceRegion>(LeftMS) ^ isa<StackSpaceRegion>(RightMS)) {
698+
// If both values wrap regions, see if they're from different base regions.
699+
// Note, heap base symbolic regions are assumed to not alias with
700+
// each other; for example, we assume that malloc returns different address
701+
// on each invocation.
702+
if (LeftBase != RightBase &&
703+
((!isa<SymbolicRegion>(LeftBase) && !isa<SymbolicRegion>(RightBase)) ||
704+
isa<HeapSpaceRegion>(LeftMS)) ){
702705
switch (op) {
703-
default:
704-
break;
705-
case BO_EQ:
706-
return makeTruthVal(false, resultTy);
707-
case BO_NE:
708-
return makeTruthVal(true, resultTy);
706+
default:
707+
return UnknownVal();
708+
case BO_EQ:
709+
return makeTruthVal(false, resultTy);
710+
case BO_NE:
711+
return makeTruthVal(true, resultTy);
709712
}
710713
}
711714

clang/test/Analysis/malloc.c

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,10 +839,8 @@ int fPtr(unsigned cond, int x) {
839839
return (cond ? mySub : myAdd)(x, x);
840840
}
841841

842-
// ----------------------------------------------------------------------------
843-
// Below are the known false positives.
842+
// Test anti-aliasing.
844843

845-
// TODO: There should be no warning here. This one might be difficult to get rid of.
846844
void dependsOnValueOfPtr(int *g, unsigned f) {
847845
int *p;
848846

@@ -855,10 +853,55 @@ void dependsOnValueOfPtr(int *g, unsigned f) {
855853
if (p != g)
856854
free(p);
857855
else
858-
return; // expected-warning{{Memory is never released; potential leak}}
856+
return; // no warning
859857
return;
860858
}
861859

860+
int CMPRegionHeapToStack() {
861+
int x = 0;
862+
int *x1 = malloc(8);
863+
int *x2 = &x;
864+
if (x1 == x2)
865+
return 5/x; // expected-warning{{This statement is never executed}}
866+
free(x1);
867+
return x;
868+
}
869+
870+
int CMPRegionHeapToHeap2() {
871+
int x = 0;
872+
int *x1 = malloc(8);
873+
int *x2 = malloc(8);
874+
int *x4 = x1;
875+
int *x5 = x2;
876+
if (x4 == x5)
877+
return 5/x; // expected-warning{{This statement is never executed}}
878+
free(x1);
879+
free(x2);
880+
return x;
881+
}
882+
883+
int CMPRegionHeapToHeap() {
884+
int x = 0;
885+
int *x1 = malloc(8);
886+
int *x4 = x1;
887+
if (x1 == x4) {
888+
free(x1);
889+
return 5/x; // expected-warning{{Division by zero}}
890+
}
891+
return x;// expected-warning{{This statement is never executed}}
892+
}
893+
894+
int HeapAssignment() {
895+
int m = 0;
896+
int *x = malloc(4);
897+
int *y = x;
898+
*x = 5;
899+
if (*x != *y)
900+
return 5/m; // expected-warning{{This statement is never executed}}
901+
free(x);
902+
return 0;
903+
}
904+
862905
// ----------------------------------------------------------------------------
863906
// False negatives.
864907

0 commit comments

Comments
 (0)