forked from OSchip/llvm-project
[analyzer][UninitializedObjectChecker] Refactoring p6.: Move dereferencing to a function
Now that it has it's own file, it makes little sense for isPointerOrReferenceUninit to be this large, so I moved dereferencing to a separate function. Differential Revision: https://reviews.llvm.org/D50509 llvm-svn: 340265
This commit is contained in:
parent
8e15b43092
commit
646019655c
|
@ -265,7 +265,8 @@ bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T->isAnyPointerType() || T->isReferenceType() || T->isBlockPointerType()) {
|
if (T->isAnyPointerType() || T->isReferenceType() ||
|
||||||
|
T->isBlockPointerType()) {
|
||||||
if (isPointerOrReferenceUninit(FR, LocalChain))
|
if (isPointerOrReferenceUninit(FR, LocalChain))
|
||||||
ContainsUninitField = true;
|
ContainsUninitField = true;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -95,6 +95,12 @@ public:
|
||||||
/// known, and thus FD can not be analyzed.
|
/// known, and thus FD can not be analyzed.
|
||||||
static bool isVoidPointer(QualType T);
|
static bool isVoidPointer(QualType T);
|
||||||
|
|
||||||
|
/// Dereferences \p V and returns the value and dynamic type of the pointee, as
|
||||||
|
/// well as wether \p FR needs to be casted back to that type. If for whatever
|
||||||
|
/// reason dereferencing fails, returns with None.
|
||||||
|
static llvm::Optional<std::tuple<SVal, QualType, bool>>
|
||||||
|
dereference(ProgramStateRef State, const FieldRegion *FR);
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Methods for FindUninitializedFields.
|
// Methods for FindUninitializedFields.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -126,67 +132,22 @@ bool FindUninitializedFields::isPointerOrReferenceUninit(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(V.getAs<loc::MemRegionVal>() &&
|
|
||||||
"At this point V must be loc::MemRegionVal!");
|
|
||||||
auto L = V.castAs<loc::MemRegionVal>();
|
|
||||||
|
|
||||||
// We can't reason about symbolic regions, assume its initialized.
|
|
||||||
// Note that this also avoids a potential infinite recursion, because
|
|
||||||
// constructors for list-like classes are checked without being called, and
|
|
||||||
// the Static Analyzer will construct a symbolic region for Node *next; or
|
|
||||||
// similar code snippets.
|
|
||||||
if (L.getRegion()->getSymbolicBase()) {
|
|
||||||
IsAnyFieldInitialized = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicTypeInfo DynTInfo = getDynamicTypeInfo(State, L.getRegion());
|
|
||||||
if (!DynTInfo.isValid()) {
|
|
||||||
IsAnyFieldInitialized = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QualType DynT = DynTInfo.getType();
|
|
||||||
|
|
||||||
// If the static type of the field is a void pointer, we need to cast it back
|
|
||||||
// to the dynamic type before dereferencing.
|
|
||||||
bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
|
|
||||||
|
|
||||||
if (isVoidPointer(DynT)) {
|
|
||||||
IsAnyFieldInitialized = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point the pointer itself is initialized and points to a valid
|
// At this point the pointer itself is initialized and points to a valid
|
||||||
// location, we'll now check the pointee.
|
// location, we'll now check the pointee.
|
||||||
SVal DerefdV = State->getSVal(V.castAs<Loc>(), DynT);
|
llvm::Optional<std::tuple<SVal, QualType, bool>> DerefInfo =
|
||||||
|
dereference(State, FR);
|
||||||
// If DerefdV is still a pointer value, we'll dereference it again (e.g.:
|
if (!DerefInfo) {
|
||||||
// int** -> int*).
|
IsAnyFieldInitialized = true;
|
||||||
while (auto Tmp = DerefdV.getAs<loc::MemRegionVal>()) {
|
return false;
|
||||||
if (Tmp->getRegion()->getSymbolicBase()) {
|
|
||||||
IsAnyFieldInitialized = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
|
|
||||||
if (!DynTInfo.isValid()) {
|
|
||||||
IsAnyFieldInitialized = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynT = DynTInfo.getType();
|
|
||||||
if (isVoidPointer(DynT)) {
|
|
||||||
IsAnyFieldInitialized = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DerefdV = State->getSVal(*Tmp, DynT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V = std::get<0>(*DerefInfo);
|
||||||
|
QualType DynT = std::get<1>(*DerefInfo);
|
||||||
|
bool NeedsCastBack = std::get<2>(*DerefInfo);
|
||||||
|
|
||||||
// If FR is a pointer pointing to a non-primitive type.
|
// If FR is a pointer pointing to a non-primitive type.
|
||||||
if (Optional<nonloc::LazyCompoundVal> RecordV =
|
if (Optional<nonloc::LazyCompoundVal> RecordV =
|
||||||
DerefdV.getAs<nonloc::LazyCompoundVal>()) {
|
V.getAs<nonloc::LazyCompoundVal>()) {
|
||||||
|
|
||||||
const TypedValueRegion *R = RecordV->getRegion();
|
const TypedValueRegion *R = RecordV->getRegion();
|
||||||
|
|
||||||
|
@ -220,7 +181,7 @@ bool FindUninitializedFields::isPointerOrReferenceUninit(
|
||||||
"At this point FR must either have a primitive dynamic type, or it "
|
"At this point FR must either have a primitive dynamic type, or it "
|
||||||
"must be a null, undefined, unknown or concrete pointer!");
|
"must be a null, undefined, unknown or concrete pointer!");
|
||||||
|
|
||||||
if (isPrimitiveUninit(DerefdV)) {
|
if (isPrimitiveUninit(V)) {
|
||||||
if (NeedsCastBack)
|
if (NeedsCastBack)
|
||||||
return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
|
return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)));
|
||||||
return addFieldToUninits(LocalChain.add(LocField(FR)));
|
return addFieldToUninits(LocalChain.add(LocField(FR)));
|
||||||
|
@ -242,3 +203,48 @@ static bool isVoidPointer(QualType T) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static llvm::Optional<std::tuple<SVal, QualType, bool>>
|
||||||
|
dereference(ProgramStateRef State, const FieldRegion *FR) {
|
||||||
|
|
||||||
|
DynamicTypeInfo DynTInfo;
|
||||||
|
QualType DynT;
|
||||||
|
|
||||||
|
// If the static type of the field is a void pointer, we need to cast it back
|
||||||
|
// to the dynamic type before dereferencing.
|
||||||
|
bool NeedsCastBack = isVoidPointer(FR->getDecl()->getType());
|
||||||
|
|
||||||
|
SVal V = State->getSVal(FR);
|
||||||
|
assert(V.getAs<loc::MemRegionVal>() && "V must be loc::MemRegionVal!");
|
||||||
|
|
||||||
|
// If V is multiple pointer value, we'll dereference it again (e.g.: int** ->
|
||||||
|
// int*).
|
||||||
|
// TODO: Dereference according to the dynamic type to avoid infinite loop for
|
||||||
|
// these kind of fields:
|
||||||
|
// int **ptr = reinterpret_cast<int **>(&ptr);
|
||||||
|
while (auto Tmp = V.getAs<loc::MemRegionVal>()) {
|
||||||
|
// We can't reason about symbolic regions, assume its initialized.
|
||||||
|
// Note that this also avoids a potential infinite recursion, because
|
||||||
|
// constructors for list-like classes are checked without being called, and
|
||||||
|
// the Static Analyzer will construct a symbolic region for Node *next; or
|
||||||
|
// similar code snippets.
|
||||||
|
if (Tmp->getRegion()->getSymbolicBase()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynTInfo = getDynamicTypeInfo(State, Tmp->getRegion());
|
||||||
|
if (!DynTInfo.isValid()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynT = DynTInfo.getType();
|
||||||
|
|
||||||
|
if (isVoidPointer(DynT)) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
V = State->getSVal(*Tmp, DynT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_tuple(V, DynT, NeedsCastBack);
|
||||||
|
}
|
||||||
|
|
|
@ -194,15 +194,28 @@ void fCharPointerTest() {
|
||||||
CharPointerTest();
|
CharPointerTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CyclicPointerTest {
|
struct CyclicPointerTest1 {
|
||||||
int *ptr;
|
int *ptr;
|
||||||
CyclicPointerTest() : ptr(reinterpret_cast<int *>(&ptr)) {}
|
CyclicPointerTest1() : ptr(reinterpret_cast<int *>(&ptr)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void fCyclicPointerTest() {
|
void fCyclicPointerTest1() {
|
||||||
CyclicPointerTest();
|
CyclicPointerTest1();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Currently, the checker ends up in an infinite loop for the following
|
||||||
|
// test case.
|
||||||
|
/*
|
||||||
|
struct CyclicPointerTest2 {
|
||||||
|
int **pptr;
|
||||||
|
CyclicPointerTest2() : pptr(reinterpret_cast<int **>(&pptr)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void fCyclicPointerTest2() {
|
||||||
|
CyclicPointerTest2();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Void pointer tests.
|
// Void pointer tests.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
Loading…
Reference in New Issue