forked from OSchip/llvm-project
Revert r246345 until an assertion is fixed.
llvm-svn: 246479
This commit is contained in:
parent
e00faf8ce1
commit
742fd989b5
|
@ -1333,9 +1333,7 @@ public:
|
|||
/// Tells that a region's contents is not changed.
|
||||
TK_PreserveContents = 0x1,
|
||||
/// Suppress pointer-escaping of a region.
|
||||
TK_SuppressEscape = 0x2,
|
||||
// Do not invalidate super region.
|
||||
TK_DoNotInvalidateSuperRegion = 0x4
|
||||
TK_SuppressEscape = 0x2
|
||||
|
||||
// Do not forget to extend StorageTypeForKinds if number of traits exceed
|
||||
// the number of bits StorageTypeForKinds can store.
|
||||
|
|
|
@ -145,8 +145,7 @@ public:
|
|||
static ProgramStateRef InvalidateBuffer(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
const Expr *Ex, SVal V,
|
||||
bool IsSourceBuffer,
|
||||
const Expr *Size);
|
||||
bool IsSourceBuffer);
|
||||
|
||||
static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
|
||||
const MemRegion *MR);
|
||||
|
@ -194,14 +193,6 @@ public:
|
|||
ProgramStateRef state,
|
||||
NonLoc left,
|
||||
NonLoc right) const;
|
||||
|
||||
// Return true if destination buffer of copy function is in bound.
|
||||
// Expects SVal of Size to be positive and unsigned.
|
||||
// Expects SVal of FirstBuf to be a FieldRegion.
|
||||
static bool IsFirstBufInBound(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
const Expr *FirstBuf,
|
||||
const Expr *Size);
|
||||
};
|
||||
|
||||
} //end anonymous namespace
|
||||
|
@ -823,68 +814,10 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
|
|||
return strRegion->getStringLiteral();
|
||||
}
|
||||
|
||||
bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
const Expr *FirstBuf,
|
||||
const Expr *Size) {
|
||||
|
||||
// Originally copied from CheckBufferAccess and CheckLocation.
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
ASTContext &Ctx = svalBuilder.getContext();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
|
||||
QualType sizeTy = Size->getType();
|
||||
QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
|
||||
SVal BufVal = state->getSVal(FirstBuf, LCtx);
|
||||
|
||||
SVal LengthVal = state->getSVal(Size, LCtx);
|
||||
// Cast is safe as the size argument to copy functions are of integral type.
|
||||
NonLoc Length = LengthVal.castAs<NonLoc>();
|
||||
|
||||
// Compute the offset of the last element to be accessed: size-1.
|
||||
NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
|
||||
NonLoc LastOffset =
|
||||
svalBuilder.evalBinOpNN(state, BO_Sub, Length, One, sizeTy)
|
||||
.castAs<NonLoc>();
|
||||
|
||||
// Check that the first buffer is sufficiently long.
|
||||
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
|
||||
// Cast is safe as caller checks BufVal is a MemRegionVal.
|
||||
Loc BufLoc = BufStart.castAs<Loc>();
|
||||
|
||||
SVal BufEnd =
|
||||
svalBuilder.evalBinOpLN(state, BO_Add, BufLoc, LastOffset, PtrTy);
|
||||
|
||||
// Check for out of bound array element access.
|
||||
const MemRegion *R = BufEnd.getAsRegion();
|
||||
// BufStart is a MemRegionVal so BufEnd should be one too.
|
||||
assert(R && "BufEnd should be a MemRegion");
|
||||
|
||||
// Cast is safe as BufVal's region is a FieldRegion.
|
||||
const ElementRegion *ER = cast<ElementRegion>(R);
|
||||
|
||||
assert(ER->getValueType() == C.getASTContext().CharTy &&
|
||||
"IsFirstBufInBound should only be called with char* ElementRegions");
|
||||
|
||||
// Get the size of the array.
|
||||
const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
|
||||
SVal Extent =
|
||||
svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
|
||||
DefinedOrUnknownSVal ExtentSize = Extent.castAs<DefinedOrUnknownSVal>();
|
||||
|
||||
// Get the index of the accessed element.
|
||||
DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
|
||||
|
||||
ProgramStateRef StInBound = state->assumeInBound(Idx, ExtentSize, true);
|
||||
|
||||
return static_cast<bool>(StInBound);
|
||||
}
|
||||
|
||||
ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
|
||||
ProgramStateRef state,
|
||||
const Expr *E, SVal V,
|
||||
bool IsSourceBuffer,
|
||||
const Expr *Size) {
|
||||
bool IsSourceBuffer) {
|
||||
Optional<Loc> L = V.getAs<Loc>();
|
||||
if (!L)
|
||||
return state;
|
||||
|
@ -914,16 +847,6 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
|
|||
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
|
||||
ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
|
||||
CausesPointerEscape = true;
|
||||
} else {
|
||||
const MemRegion::Kind& K = R->getKind();
|
||||
if (K == MemRegion::FieldRegionKind)
|
||||
if (Size && IsFirstBufInBound(C, state, E, Size)) {
|
||||
// If destination buffer is a field region and access is in bound,
|
||||
// do not invalidate its super region.
|
||||
ITraits.setTrait(
|
||||
R,
|
||||
RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
|
||||
}
|
||||
}
|
||||
|
||||
return state->invalidateRegions(R, E, C.blockCount(), LCtx,
|
||||
|
@ -1077,12 +1000,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
|
|||
// This would probably remove any existing bindings past the end of the
|
||||
// copied region, but that's still an improvement over blank invalidation.
|
||||
state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest),
|
||||
/*IsSourceBuffer*/false, Size);
|
||||
/*IsSourceBuffer*/false);
|
||||
|
||||
// Invalidate the source (const-invalidation without const-pointer-escaping
|
||||
// the address of the top-level region).
|
||||
state = InvalidateBuffer(C, state, Source, C.getSVal(Source),
|
||||
/*IsSourceBuffer*/true, nullptr);
|
||||
/*IsSourceBuffer*/true);
|
||||
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
@ -1697,12 +1620,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
|
|||
// This would probably remove any existing bindings past the end of the
|
||||
// string, but that's still an improvement over blank invalidation.
|
||||
state = InvalidateBuffer(C, state, Dst, *dstRegVal,
|
||||
/*IsSourceBuffer*/false, nullptr);
|
||||
/*IsSourceBuffer*/false);
|
||||
|
||||
// Invalidate the source (const-invalidation without const-pointer-escaping
|
||||
// the address of the top-level region).
|
||||
state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true,
|
||||
nullptr);
|
||||
state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true);
|
||||
|
||||
// Set the C string length of the destination, if we know it.
|
||||
if (isBounded && !isAppending) {
|
||||
|
@ -1926,7 +1848,7 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
|
|||
// Invalidate the search string, representing the change of one delimiter
|
||||
// character to NUL.
|
||||
State = InvalidateBuffer(C, State, SearchStrPtr, Result,
|
||||
/*IsSourceBuffer*/false, nullptr);
|
||||
/*IsSourceBuffer*/false);
|
||||
|
||||
// Overwrite the search string pointer. The new value is either an address
|
||||
// further along in the same string, or NULL if there are no more tokens.
|
||||
|
|
|
@ -710,7 +710,8 @@ public:
|
|||
}
|
||||
|
||||
bool AddToWorkList(const MemRegion *R) {
|
||||
return static_cast<DERIVED*>(this)->AddToWorkList(R);
|
||||
const MemRegion *BaseR = R->getBaseRegion();
|
||||
return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
|
||||
}
|
||||
|
||||
void RunWorkList() {
|
||||
|
@ -955,20 +956,9 @@ public:
|
|||
|
||||
void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
|
||||
void VisitBinding(SVal V);
|
||||
|
||||
using ClusterAnalysis::AddToWorkList;
|
||||
|
||||
bool AddToWorkList(const MemRegion *R);
|
||||
};
|
||||
}
|
||||
|
||||
bool invalidateRegionsWorker::AddToWorkList(const MemRegion *R) {
|
||||
bool doNotInvalidateSuperRegion = ITraits.hasTrait(
|
||||
R, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
|
||||
const MemRegion *BaseR = doNotInvalidateSuperRegion ? R : R->getBaseRegion();
|
||||
return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
|
||||
}
|
||||
|
||||
void invalidateRegionsWorker::VisitBinding(SVal V) {
|
||||
// A symbol? Mark it touched by the invalidation.
|
||||
if (SymbolRef Sym = V.getAsSymbol())
|
||||
|
@ -1081,66 +1071,6 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
|
|||
}
|
||||
|
||||
if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
|
||||
bool doNotInvalidateSuperRegion = ITraits.hasTrait(
|
||||
baseR,
|
||||
RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
|
||||
|
||||
if (doNotInvalidateSuperRegion) {
|
||||
// We are not doing blank invalidation of the whole array region so we
|
||||
// have to manually invalidate each elements.
|
||||
Optional<uint64_t> NumElements;
|
||||
|
||||
// Compute lower and upper offsets for region within array.
|
||||
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
|
||||
NumElements = CAT->getSize().getZExtValue();
|
||||
if (!NumElements) // We are not dealing with a constant size array
|
||||
goto conjure_default;
|
||||
QualType ElementTy = AT->getElementType();
|
||||
uint64_t ElemSize = Ctx.getTypeSize(ElementTy);
|
||||
const RegionOffset &RO = baseR->getAsOffset();
|
||||
const MemRegion *SuperR = baseR->getBaseRegion();
|
||||
if (RO.hasSymbolicOffset()) {
|
||||
// If base region has a symbolic offset,
|
||||
// we revert to invalidating the super region.
|
||||
if (SuperR)
|
||||
AddToWorkList(SuperR);
|
||||
goto conjure_default;
|
||||
}
|
||||
assert(RO.getOffset() >= 0 && "Offset should not be negative");
|
||||
uint64_t LowerOffset = RO.getOffset();
|
||||
uint64_t UpperOffset = LowerOffset + *NumElements * ElemSize;
|
||||
|
||||
// Invalidate regions which are within array boundaries,
|
||||
// or have a symbolic offset.
|
||||
if (!SuperR)
|
||||
goto conjure_default;
|
||||
|
||||
const ClusterBindings *C = B.lookup(SuperR);
|
||||
if (!C)
|
||||
goto conjure_default;
|
||||
|
||||
for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E;
|
||||
++I) {
|
||||
const BindingKey &BK = I.getKey();
|
||||
Optional<uint64_t> ROffset =
|
||||
BK.hasSymbolicOffset() ? Optional<uint64_t>() : BK.getOffset();
|
||||
// Check offset is not symbolic and within array's boundaries.
|
||||
// Handles arrays of 0 elements and of 0-sized elements as well.
|
||||
if (!ROffset ||
|
||||
(ROffset &&
|
||||
((*ROffset >= LowerOffset && *ROffset < UpperOffset) ||
|
||||
(LowerOffset == UpperOffset && *ROffset == LowerOffset)))) {
|
||||
B = B.removeBinding(I.getKey());
|
||||
// Bound symbolic regions need to be invalidated for dead symbol
|
||||
// detection.
|
||||
SVal V = I.getData();
|
||||
const MemRegion *R = V.getAsRegion();
|
||||
if (R && isa<SymbolicRegion>(R))
|
||||
VisitBinding(V);
|
||||
}
|
||||
}
|
||||
}
|
||||
conjure_default:
|
||||
// Set the default value of the array to conjured symbol.
|
||||
DefinedOrUnknownSVal V =
|
||||
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
|
||||
|
@ -2257,20 +2187,11 @@ public:
|
|||
void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
|
||||
using ClusterAnalysis<removeDeadBindingsWorker>::VisitCluster;
|
||||
|
||||
using ClusterAnalysis::AddToWorkList;
|
||||
|
||||
bool AddToWorkList(const MemRegion *R);
|
||||
|
||||
bool UpdatePostponed();
|
||||
void VisitBinding(SVal V);
|
||||
};
|
||||
}
|
||||
|
||||
bool removeDeadBindingsWorker::AddToWorkList(const MemRegion *R) {
|
||||
const MemRegion *BaseR = R->getBaseRegion();
|
||||
return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
|
||||
}
|
||||
|
||||
void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
|
||||
const ClusterBindings &C) {
|
||||
|
||||
|
|
|
@ -1,697 +0,0 @@
|
|||
// Given code 'struct aa { char s1[4]; char * s2;} a; memcpy(a.s1, ...);',
|
||||
// this test checks that the CStringChecker only invalidates the destination buffer array a.s1 (instead of a.s1 and a.s2).
|
||||
// At the moment the whole of the destination array content is invalidated.
|
||||
// If a.s1 region has a symbolic offset, the whole region of 'a' is invalidated.
|
||||
// Specific triple set to test structures of size 0.
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s
|
||||
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
|
||||
char *strdup(const char *s);
|
||||
void free(void *);
|
||||
void *memcpy(void *dst, const void *src, size_t n); // expected-note{{passing argument to parameter 'dst' here}}
|
||||
void *malloc(size_t n);
|
||||
|
||||
void clang_analyzer_eval(int);
|
||||
|
||||
struct aa {
|
||||
char s1[4];
|
||||
char *s2;
|
||||
};
|
||||
|
||||
// Test different types of structure initialisation.
|
||||
int f0() {
|
||||
struct aa a0 = {{1, 2, 3, 4}, 0};
|
||||
a0.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a0.s1, input, 4);
|
||||
clang_analyzer_eval(a0.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a0.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a0.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a0.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a0.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(a0.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f1() {
|
||||
struct aa a1;
|
||||
a1.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a1.s1, input, 4);
|
||||
clang_analyzer_eval(a1.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a1.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a1.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a1.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a1.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(a1.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2() {
|
||||
struct aa a2 = {{1, 2}};
|
||||
a2.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a2.s1, input, 4);
|
||||
clang_analyzer_eval(a2.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a2.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a2.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a2.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a2.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(a2.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f3() {
|
||||
struct aa a3 = {{1, 2, 3, 4}, 0};
|
||||
a3.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
int * dest = (int*)a3.s1;
|
||||
memcpy(dest, input, 4);
|
||||
clang_analyzer_eval(a3.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a3.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a3.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a3.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a3.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(a3.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bb {
|
||||
struct aa a;
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f4() {
|
||||
struct bb b0 = {{1, 2, 3, 4}, 0};
|
||||
b0.s2 = strdup("hello");
|
||||
b0.a.s2 = strdup("hola");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
char * dest = (char*)(b0.a.s1);
|
||||
memcpy(dest, input, 4);
|
||||
clang_analyzer_eval(b0.a.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(b0.a.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(b0.a.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(b0.a.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(dest[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(b0.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(b0.a.s2); // no warning
|
||||
free(b0.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test that memory leaks are caught.
|
||||
int f5() {
|
||||
struct aa a0 = {{1, 2, 3, 4}, 0};
|
||||
a0.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a0.s1, input, 4);
|
||||
return 0; // expected-warning{{Potential leak of memory pointed to by 'a0.s2'}}
|
||||
}
|
||||
|
||||
int f6() {
|
||||
struct aa a1;
|
||||
a1.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a1.s1, input, 4);
|
||||
return 0; // expected-warning{{Potential leak of memory pointed to by 'a1.s2'}}
|
||||
}
|
||||
|
||||
int f7() {
|
||||
struct aa a2 = {{1, 2}};
|
||||
a2.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a2.s1, input, 4);
|
||||
return 0; // expected-warning{{Potential leak of memory pointed to by 'a2.s2'}}
|
||||
}
|
||||
|
||||
int f8() {
|
||||
struct aa a3 = {{1, 2, 3, 4}, 0};
|
||||
a3.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
int * dest = (int*)a3.s1;
|
||||
memcpy(dest, input, 4);
|
||||
return 0; // expected-warning{{Potential leak of memory pointed to by 'a3.s2'}}
|
||||
}
|
||||
|
||||
int f9() {
|
||||
struct bb b0 = {{1, 2, 3, 4}, 0};
|
||||
b0.s2 = strdup("hello");
|
||||
b0.a.s2 = strdup("hola");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
char * dest = (char*)(b0.a.s1);
|
||||
memcpy(dest, input, 4);
|
||||
free(b0.a.s2); // expected-warning{{Potential leak of memory pointed to by 'b0.s2'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f10() {
|
||||
struct bb b0 = {{1, 2, 3, 4}, 0};
|
||||
b0.s2 = strdup("hello");
|
||||
b0.a.s2 = strdup("hola");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
char * dest = (char*)(b0.a.s1);
|
||||
memcpy(dest, input, 4);
|
||||
free(b0.s2); // expected-warning{{Potential leak of memory pointed to by 'b0.a.s2'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test invalidating fields being addresses of array.
|
||||
struct cc {
|
||||
char * s1;
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f11() {
|
||||
char x[4] = {1, 2};
|
||||
x[0] = 1;
|
||||
x[1] = 2;
|
||||
struct cc c0;
|
||||
c0.s2 = strdup("hello");
|
||||
c0.s1 = &x[0];
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(c0.s1, input, 4);
|
||||
clang_analyzer_eval(x[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(x[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(c0.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(c0.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(c0.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(c0.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
free(c0.s2); // no-warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test inverting field position between s1 and s2.
|
||||
struct dd {
|
||||
char *s2;
|
||||
char s1[4];
|
||||
};
|
||||
|
||||
int f12() {
|
||||
struct dd d0 = {0, {1, 2, 3, 4}};
|
||||
d0.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(d0.s1, input, 4);
|
||||
clang_analyzer_eval(d0.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(d0.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(d0.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(d0.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(d0.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(d0.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test arrays of structs.
|
||||
struct ee {
|
||||
int a;
|
||||
char b;
|
||||
};
|
||||
|
||||
struct EE {
|
||||
struct ee s1[2];
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f13() {
|
||||
struct EE E0 = {{{1, 2}, {3, 4}}, 0};
|
||||
E0.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(E0.s1, input, 4);
|
||||
clang_analyzer_eval(E0.s1[0].a == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(E0.s1[0].b == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(E0.s1[1].a == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(E0.s1[1].b == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(E0.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(E0.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test global parameters.
|
||||
struct aa a15 = {{1, 2, 3, 4}, 0};
|
||||
|
||||
int f15() {
|
||||
a15.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a15.s1, input, 4);
|
||||
clang_analyzer_eval(a15.s1[0] == 'a'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a15.s1[1] == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a15.s1[2] == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a15.s1[3] == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a15.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(a15.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test array of 0 sized elements.
|
||||
struct empty {};
|
||||
struct gg {
|
||||
struct empty s1[4];
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f16() {
|
||||
struct gg g0 = {{}, 0};
|
||||
g0.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(g0.s1, input, 4);
|
||||
clang_analyzer_eval(*(int*)(&g0.s1[0]) == 'a'); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'g0.s2'}}
|
||||
clang_analyzer_eval(*(int*)(&g0.s1[1]) == 'b'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(*(int*)(&g0.s1[2]) == 'c'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(*(int*)(&g0.s1[3]) == 'd'); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(g0.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(g0.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test array of 0 elements.
|
||||
struct hh {
|
||||
char s1[0];
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f17() {
|
||||
struct hh h0;
|
||||
h0.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(h0.s1, input, 4);
|
||||
clang_analyzer_eval(h0.s1[0] == 'a'); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'h0.s2'}}
|
||||
clang_analyzer_eval(h0.s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
free(h0.s2); // no warning
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test writing past the array.
|
||||
struct ii {
|
||||
char s1[4];
|
||||
int i;
|
||||
int j;
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f18() {
|
||||
struct ii i18 = {{1, 2, 3, 4}, 5, 6};
|
||||
i18.i = 10;
|
||||
i18.j = 11;
|
||||
i18.s2 = strdup("hello");
|
||||
char input[100] = {3};
|
||||
memcpy(i18.s1, input, 100);
|
||||
clang_analyzer_eval(i18.s1[0] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'i18.s2'}}
|
||||
clang_analyzer_eval(i18.s1[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i18.s1[2] == 3); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i18.s1[3] == 4); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i18.i == 10); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i18.j == 11); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f181() {
|
||||
struct ii i181 = {{1, 2, 3, 4}, 5, 6};
|
||||
i181.i = 10;
|
||||
i181.j = 11;
|
||||
i181.s2 = strdup("hello");
|
||||
char input[100] = {3};
|
||||
memcpy(i181.s1, input, 5); // invalidate the whole region of i181
|
||||
clang_analyzer_eval(i181.s1[0] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'i181.s2'}}
|
||||
clang_analyzer_eval(i181.s1[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i181.s1[2] == 3); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i181.s1[3] == 4); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i181.i == 10); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(i181.j == 11); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test array with a symbolic offset.
|
||||
struct jj {
|
||||
char s1[2];
|
||||
char * s2;
|
||||
};
|
||||
|
||||
struct JJ {
|
||||
struct jj s1[3];
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f19(int i) {
|
||||
struct JJ J0 = {{{1, 2, 0}, {3, 4, 0}, {5, 6, 0}}, 0};
|
||||
J0.s2 = strdup("hello");
|
||||
J0.s1[0].s2 = strdup("hello");
|
||||
J0.s1[1].s2 = strdup("hi");
|
||||
J0.s1[2].s2 = strdup("world");
|
||||
char input[2] = {'a', 'b'};
|
||||
memcpy(J0.s1[i].s1, input, 2);
|
||||
clang_analyzer_eval(J0.s1[0].s1[0] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by field 's2'}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'J0.s2'}}
|
||||
clang_analyzer_eval(J0.s1[0].s1[1] == 2); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(J0.s1[1].s1[0] == 3); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(J0.s1[1].s1[1] == 4); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(J0.s1[2].s1[0] == 5); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(J0.s1[2].s1[1] == 6); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(J0.s1[i].s1[0] == 5); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(J0.s1[i].s1[1] == 6); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: memory leak warning for J0.s2 should be emitted here instead of after memcpy call.
|
||||
return 0; // no warning
|
||||
}
|
||||
|
||||
// Test array with its super region having symbolic offseted regions.
|
||||
int f20(int i) {
|
||||
struct aa * a20 = malloc(sizeof(struct aa) * 2);
|
||||
a20[0].s1[0] = 1;
|
||||
a20[0].s1[1] = 2;
|
||||
a20[0].s1[2] = 3;
|
||||
a20[0].s1[3] = 4;
|
||||
a20[0].s2 = strdup("hello");
|
||||
a20[1].s1[0] = 5;
|
||||
a20[1].s1[1] = 6;
|
||||
a20[1].s1[2] = 7;
|
||||
a20[1].s1[3] = 8;
|
||||
a20[1].s2 = strdup("world");
|
||||
a20[i].s2 = strdup("hola");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a20[0].s1, input, 4);
|
||||
clang_analyzer_eval(a20[0].s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[0].s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[0].s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[0].s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[0].s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[1].s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[1].s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[1].s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[1].s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[1].s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[i].s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[i].s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[i].s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[i].s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a20[i].s2 == 0); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'a20'}}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test array's region and super region both having symbolic offsets.
|
||||
int f21(int i) {
|
||||
struct aa * a21 = malloc(sizeof(struct aa) * 2);
|
||||
a21[0].s1[0] = 1;
|
||||
a21[0].s1[1] = 2;
|
||||
a21[0].s1[2] = 3;
|
||||
a21[0].s1[3] = 4;
|
||||
a21[0].s2 = 0;
|
||||
a21[1].s1[0] = 5;
|
||||
a21[1].s1[1] = 6;
|
||||
a21[1].s1[2] = 7;
|
||||
a21[1].s1[3] = 8;
|
||||
a21[1].s2 = 0;
|
||||
a21[i].s2 = strdup("hello");
|
||||
a21[i].s1[0] = 1;
|
||||
a21[i].s1[1] = 2;
|
||||
a21[i].s1[2] = 3;
|
||||
a21[i].s1[3] = 4;
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a21[i].s1, input, 4);
|
||||
clang_analyzer_eval(a21[0].s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[0].s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[0].s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[0].s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[0].s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[1].s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[1].s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[1].s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[1].s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[1].s2 == 0); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[i].s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[i].s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[i].s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[i].s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a21[i].s2 == 0); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'a21'}}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test regions aliasing other regions.
|
||||
struct ll {
|
||||
char s1[4];
|
||||
char * s2;
|
||||
};
|
||||
|
||||
struct mm {
|
||||
char s3[4];
|
||||
char * s4;
|
||||
};
|
||||
|
||||
int f24() {
|
||||
struct ll l24 = {{1, 2, 3, 4}, 0};
|
||||
struct mm * m24 = (struct mm *)&l24;
|
||||
m24->s4 = strdup("hello");
|
||||
char input[] = {1, 2, 3, 4};
|
||||
memcpy(m24->s3, input, 4);
|
||||
clang_analyzer_eval(m24->s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m24->s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m24->s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m24->s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l24.s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l24.s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l24.s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l24.s1[3] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by field 's4'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test region with potential aliasing and symbolic offsets.
|
||||
// Store assumes no aliasing.
|
||||
int f25(int i, int j, struct ll * l, struct mm * m) {
|
||||
m->s4 = strdup("hola"); // m->s4 not tracked
|
||||
m->s3[0] = 1;
|
||||
m->s3[1] = 2;
|
||||
m->s3[2] = 3;
|
||||
m->s3[3] = 4;
|
||||
m->s3[j] = 5; // invalidates m->s3
|
||||
l->s2 = strdup("hello"); // l->s2 not tracked
|
||||
l->s1[0] = 6;
|
||||
l->s1[1] = 7;
|
||||
l->s1[2] = 8;
|
||||
l->s1[3] = 9;
|
||||
l->s1[i] = 10; // invalidates l->s1
|
||||
char input[] = {1, 2, 3, 4};
|
||||
memcpy(m->s3, input, 4); // does not invalidate l->s1[i]
|
||||
clang_analyzer_eval(m->s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m->s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m->s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m->s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m->s3[i] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m->s3[j] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l->s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l->s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l->s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l->s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l->s1[i] == 1); // expected-warning{{FALSE}}
|
||||
clang_analyzer_eval(l->s1[j] == 1); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test size with symbolic size argument.
|
||||
int f26(int i) {
|
||||
struct aa a26 = {{1, 2, 3, 4}, 0};
|
||||
a26.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a26.s1, input, i); // i assumed in bound
|
||||
clang_analyzer_eval(a26.s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a26.s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a26.s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a26.s1[3] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'a26.s2'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test sizeof as a size argument.
|
||||
int f261() {
|
||||
struct aa a261 = {{1, 2, 3, 4}, 0};
|
||||
a261.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a261.s1, input, sizeof(a261.s1));
|
||||
clang_analyzer_eval(a261.s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a261.s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a261.s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a261.s1[3] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'a261.s2'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test negative size argument.
|
||||
int f262() {
|
||||
struct aa a262 = {{1, 2, 3, 4}, 0};
|
||||
a262.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(a262.s1, input, -1);
|
||||
clang_analyzer_eval(a262.s1[0] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'a262.s2'}}
|
||||
clang_analyzer_eval(a262.s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a262.s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(a262.s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test casting regions with symbolic offseted sub regions.
|
||||
int f27(int i) {
|
||||
struct mm m27 = {{1, 2, 3, 4}, 0};
|
||||
m27.s4 = strdup("hello");
|
||||
m27.s3[i] = 5;
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(((struct ll*)(&m27))->s1, input, 4);
|
||||
clang_analyzer_eval(m27.s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m27.s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m27.s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m27.s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m27.s3[i] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'm27.s4'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f28(int i, int j, int k, int l) {
|
||||
struct mm m28[2];
|
||||
m28[i].s4 = strdup("hello");
|
||||
m28[j].s3[k] = 1;
|
||||
struct ll * l28 = (struct ll*)(&m28[1]);
|
||||
l28->s1[l] = 2;
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(l28->s1, input, 4);
|
||||
clang_analyzer_eval(m28[0].s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[0].s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[0].s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[0].s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[1].s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[1].s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[1].s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[1].s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[i].s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[i].s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[i].s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[i].s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m28[j].s3[k] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(l28->s1[l] == 2); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f29(int i, int j, int k, int l, int m) {
|
||||
struct mm m29[2];
|
||||
m29[i].s4 = strdup("hello");
|
||||
m29[j].s3[k] = 1;
|
||||
struct ll * l29 = (struct ll*)(&m29[l]);
|
||||
l29->s1[m] = 2;
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(l29->s1, input, 4);
|
||||
clang_analyzer_eval(m29[0].s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[0].s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[0].s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[0].s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[1].s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[1].s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[1].s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[1].s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[i].s3[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[i].s3[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[i].s3[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[i].s3[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(m29[j].s3[k] == 1); // expected-warning{{TRUE}}\
|
||||
expected-warning{{Potential leak of memory pointed to by field 's4'}}
|
||||
clang_analyzer_eval(l29->s1[m] == 2); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Test unions' fields.
|
||||
union uu {
|
||||
char x;
|
||||
char s1[4];
|
||||
};
|
||||
|
||||
int f30() {
|
||||
union uu u30 = { .s1 = {1, 2, 3, 4}};
|
||||
char input[] = {1, 2, 3, 4};
|
||||
memcpy(u30.s1, input, 4);
|
||||
clang_analyzer_eval(u30.s1[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(u30.s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(u30.s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(u30.s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(u30.x == 1); // expected-warning{{UNKNOWN}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct kk {
|
||||
union uu u;
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f31() {
|
||||
struct kk k31;
|
||||
k31.s2 = strdup("hello");
|
||||
k31.u.x = 1;
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(k31.u.s1, input, 4);
|
||||
clang_analyzer_eval(k31.u.s1[0] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'k31.s2'}}
|
||||
clang_analyzer_eval(k31.u.s1[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(k31.u.s1[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(k31.u.s1[3] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(k31.u.x == 1); // expected-warning{{UNKNOWN}}
|
||||
// FIXME: memory leak warning for k31.s2 should be emitted here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
union vv {
|
||||
int x;
|
||||
char * s2;
|
||||
};
|
||||
|
||||
int f32() {
|
||||
union vv v32;
|
||||
v32.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(v32.s2, input, 4);
|
||||
clang_analyzer_eval(v32.s2[0] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(v32.s2[1] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(v32.s2[2] == 1); // expected-warning{{UNKNOWN}}
|
||||
clang_analyzer_eval(v32.s2[3] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{Potential leak of memory pointed to by 'v32.s2'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nn {
|
||||
int s1;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
char * s2;
|
||||
};
|
||||
|
||||
// Test bad types to dest buffer.
|
||||
int f33() {
|
||||
struct nn n33 = {1, 2, 3, 4, 0};
|
||||
n33.s2 = strdup("hello");
|
||||
char input[] = {'a', 'b', 'c', 'd'};
|
||||
memcpy(n33.s1, input, 4); // expected-warning{{incompatible integer to pointer conversion passing 'int' to parameter of type 'void *'}}
|
||||
clang_analyzer_eval(n33.i == 2); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(n33.j == 3); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(n33.k == 4); // expected-warning{{TRUE}}
|
||||
clang_analyzer_eval(((char*)(n33.s1))[0] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{cast to 'char *' from smaller integer type 'int'}}
|
||||
clang_analyzer_eval(((char*)(n33.s1))[1] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{cast to 'char *' from smaller integer type 'int'}}
|
||||
clang_analyzer_eval(((char*)(n33.s1))[2] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{cast to 'char *' from smaller integer type 'int'}}
|
||||
clang_analyzer_eval(((char*)(n33.s1))[3] == 1); // expected-warning{{UNKNOWN}}\
|
||||
expected-warning{{cast to 'char *' from smaller integer type 'int'}}
|
||||
clang_analyzer_eval(n33.s2 == 0); //expected-warning{{UNKNOWN}}
|
||||
return 0; // expected-warning{{Potential leak of memory pointed to by 'n33.s2'}}
|
||||
}
|
Loading…
Reference in New Issue