#include "UninitializedObject.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
using namespace clang;
using namespace clang::ento;
namespace {
class LocField final : public FieldNode {
const bool IsDereferenced;
public:
LocField(const FieldRegion *FR, const bool IsDereferenced = true)
: FieldNode(FR), IsDereferenced(IsDereferenced) {}
void printNoteMsg(llvm::raw_ostream &Out) const override {
if (IsDereferenced)
Out << "uninitialized pointee ";
else
Out << "uninitialized pointer ";
}
void printPrefix(llvm::raw_ostream &Out) const override {}
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
void printSeparator(llvm::raw_ostream &Out) const override {
if (getDecl()->getType()->isPointerType())
Out << "->";
else
Out << '.';
}
};
class NeedsCastLocField final : public FieldNode {
QualType CastBackType;
public:
NeedsCastLocField(const FieldRegion *FR, const QualType &T)
: FieldNode(FR), CastBackType(T) {}
void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "uninitialized pointee ";
}
void printPrefix(llvm::raw_ostream &Out) const override {
if (getDecl()->getType()->isIntegerType())
Out << "reinterpret_cast";
else
Out << "static_cast";
Out << '<' << CastBackType.getAsString() << ">(";
}
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl()) << ')';
}
void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }
};
class CyclicLocField final : public FieldNode {
public:
CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "object references itself ";
}
void printPrefix(llvm::raw_ostream &Out) const override {}
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
void printSeparator(llvm::raw_ostream &Out) const override {
llvm_unreachable("CyclicLocField objects must be the last node of the "
"fieldchain!");
}
};
}
struct DereferenceInfo {
const TypedValueRegion *R;
const bool NeedsCastBack;
const bool IsCyclic;
DereferenceInfo(const TypedValueRegion *R, bool NCB, bool IC)
: R(R), NeedsCastBack(NCB), IsCyclic(IC) {}
};
static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
const FieldRegion *FR);
static bool isVoidPointer(QualType T);
bool FindUninitializedFields::isDereferencableUninit(
const FieldRegion *FR, FieldChainInfo LocalChain) {
SVal V = State->getSVal(FR);
assert((isDereferencableType(FR->getDecl()->getType()) ||
isa<nonloc::LocAsInteger>(V)) &&
"This method only checks dereferenceable objects!");
if (V.isUnknown() || isa<loc::ConcreteInt>(V)) {
IsAnyFieldInitialized = true;
return false;
}
if (V.isUndef()) {
return addFieldToUninits(
LocalChain.add(LocField(FR, false)), FR);
}
if (!Opts.CheckPointeeInitialization) {
IsAnyFieldInitialized = true;
return false;
}
llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
if (!DerefInfo) {
IsAnyFieldInitialized = true;
return false;
}
if (DerefInfo->IsCyclic)
return addFieldToUninits(LocalChain.add(CyclicLocField(FR)), FR);
const TypedValueRegion *R = DerefInfo->R;
const bool NeedsCastBack = DerefInfo->NeedsCastBack;
QualType DynT = R->getLocationType();
QualType PointeeT = DynT->getPointeeType();
if (PointeeT->isStructureOrClassType()) {
if (NeedsCastBack)
return isNonUnionUninit(R, LocalChain.add(NeedsCastLocField(FR, DynT)));
return isNonUnionUninit(R, LocalChain.add(LocField(FR)));
}
if (PointeeT->isUnionType()) {
if (isUnionUninit(R)) {
if (NeedsCastBack)
return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)),
R);
return addFieldToUninits(LocalChain.add(LocField(FR)), R);
} else {
IsAnyFieldInitialized = true;
return false;
}
}
if (PointeeT->isArrayType()) {
IsAnyFieldInitialized = true;
return false;
}
assert((isPrimitiveType(PointeeT) || isDereferencableType(PointeeT)) &&
"At this point FR must either have a primitive dynamic type, or it "
"must be a null, undefined, unknown or concrete pointer!");
SVal PointeeV = State->getSVal(R);
if (isPrimitiveUninit(PointeeV)) {
if (NeedsCastBack)
return addFieldToUninits(LocalChain.add(NeedsCastLocField(FR, DynT)), R);
return addFieldToUninits(LocalChain.add(LocField(FR)), R);
}
IsAnyFieldInitialized = true;
return false;
}
static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
const FieldRegion *FR) {
llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
SVal V = State->getSVal(FR);
assert(V.getAsRegion() && "V must have an underlying region!");
bool NeedsCastBack =
isVoidPointer(FR->getDecl()->getType()) || isa<nonloc::LocAsInteger>(V);
const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
if (!R)
return None;
VisitedRegions.insert(R);
QualType DynT = R->getLocationType();
while (const MemRegion *Tmp = State->getSVal(R, DynT).getAsRegion()) {
R = Tmp->getAs<TypedValueRegion>();
if (!R)
return None;
if (!VisitedRegions.insert(R).second)
return DereferenceInfo{R, NeedsCastBack, true};
DynT = R->getLocationType();
if (isDereferencableType(DynT->getPointeeType()))
break;
}
while (isa<CXXBaseObjectRegion>(R)) {
NeedsCastBack = true;
const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
if (!SuperR)
break;
R = SuperR;
}
return DereferenceInfo{R, NeedsCastBack, false};
}
static bool isVoidPointer(QualType T) {
while (!T.isNull()) {
if (T->isVoidPointerType())
return true;
T = T->getPointeeType();
}
return false;
}