29 changes: 29 additions & 0 deletions lib/StaticAnalyzer/Core/MemRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,18 @@ void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
}

void GhostFieldRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
const SmartStateTrait &Trait,
const MemRegion *SReg) {
ID.AddInteger(GhostFieldRegionKind);
ID.AddInteger(Trait.getTraitID());
ID.AddPointer(SReg);
}

void GhostFieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
ProfileRegion(ID, Trait, getSuperRegion());
}

void GhostSymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
SymbolRef Sym, const MemRegion *SReg) {
ID.AddInteger(GhostSymbolicRegionKind);
Expand Down Expand Up @@ -539,6 +551,10 @@ void VarRegion::dumpToStream(raw_ostream &os) const {
os << *cast<VarDecl>(D);
}

void GhostFieldRegion::dumpToStream(raw_ostream &os) const {
os << getTrait().getTraitDescription() << '{' << getSuperRegion() << '}';
}

void GhostSymbolicRegion::dumpToStream(raw_ostream &os) const {
os << getTrait().getTraitDescription() << '{' << Sym << '}';
}
Expand Down Expand Up @@ -920,6 +936,12 @@ MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) {
Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
}

const GhostFieldRegion *
MemRegionManager::getGhostFieldRegion(const SmartStateTrait &Trait,
const MemRegion *superRegion) {
return getSubRegion<GhostFieldRegion>(Trait, superRegion);
}

const GhostSymbolicRegion *
MemRegionManager::getGhostSymbolicRegion(const SmartStateTrait &Trait,
SymbolRef Sym) {
Expand Down Expand Up @@ -1119,6 +1141,7 @@ const MemRegion *MemRegion::getBaseRegion() const {
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
case MemRegion::CXXBaseObjectRegionKind:
case MemRegion::GhostFieldRegionKind:
R = cast<SubRegion>(R)->getSuperRegion();
continue;
default:
Expand Down Expand Up @@ -1388,6 +1411,12 @@ RegionOffset MemRegion::getAsOffset() const {
Offset += Layout.getFieldOffset(idx);
break;
}
case GhostFieldRegionKind: {
const GhostFieldRegion *GR = cast<GhostFieldRegion>(R);
SymbolicOffsetBase = R;
R = GR->getSuperRegion();
continue;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/StaticAnalyzer/Core/Store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
case MemRegion::VarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
case MemRegion::CXXBaseObjectRegionKind:
case MemRegion::GhostFieldRegionKind:
case MemRegion::GhostSymbolicRegionKind:
return MakeElementRegion(R, PointeeTy);

Expand Down
5 changes: 5 additions & 0 deletions test/Analysis/simple-stream-checks.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix.SimpleStream -DFIXIT_V1 -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix.SimpleStreamV2 -DFIXIT_V2 -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix.SimpleStreamV3 -DFIXIT_V3 -verify %s

#include "Inputs/system-header-simulator-for-simple-stream.h"

Expand All @@ -15,6 +16,7 @@ void checkDoubleFClose(int *Data) {
}
}

#ifndef FIXIT_V3
int checkLeak(int *Data) {
FILE *F = fopen("myfile.txt", "w");
if (F != 0) {
Expand All @@ -26,6 +28,7 @@ int checkLeak(int *Data) {
else
return 0;
}
#endif

void checkLeakFollowedByAssert(int *Data) {
FILE *F = fopen("myfile.txt", "w");
Expand Down Expand Up @@ -72,11 +75,13 @@ void SymbolEscapedThroughAssignmentToGloabl() {
return; // no warning
}

#ifndef FIXIT_V3
void SymbolDoesNotEscapeThoughStringAPIs(char *Data) {
FILE *F = fopen("myfile.txt", "w");
fputc(*Data, F);
return; // expected-warning {{Opened file is never closed; potential resource leak}}
}
#endif

void passConstPointer(const FILE * F);
void testPassConstPointer() {
Expand Down