Detect pass-by-value arguments that are structs that contain

uninitialized data.

llvm-svn: 98796
This commit is contained in:
Ted Kremenek 2010-03-18 02:17:27 +00:00
parent e174fda979
commit 9c05f4ef69
2 changed files with 119 additions and 24 deletions

View File

@ -50,6 +50,12 @@ private:
void HandleNilReceiver(CheckerContext &C, const GRState *state,
const ObjCMessageExpr *ME);
void LazyInit_BT_call_arg() {
if (!BT_call_arg)
BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
" is undefined");
}
};
} // end anonymous namespace
@ -92,11 +98,11 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
if (C.getState()->getSVal(*I).isUndef()) {
const SVal &V = C.getState()->getSVal(*I);
if (V.isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_call_arg)
BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
" is undefined");
LazyInit_BT_call_arg();
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
BT_call_arg->getName(), N);
@ -106,6 +112,89 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
return;
}
}
if (const nonloc::LazyCompoundVal *LV =
dyn_cast<nonloc::LazyCompoundVal>(&V)) {
const LazyCompoundValData *D = LV->getCVData();
class FindUninitializedField {
public:
llvm::SmallVector<const FieldDecl *, 10> FieldChain;
private:
ASTContext &C;
StoreManager &StoreMgr;
MemRegionManager &MrMgr;
Store store;
public:
FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
MemRegionManager &mrMgr, Store s)
: C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
bool Find(const TypedRegion *R) {
QualType T = R->getValueType(C);
if (const RecordType *RT = T->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
assert(RD && "Referred record has no definition");
for (RecordDecl::field_iterator I =
RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
FieldChain.push_back(*I);
T = (*I)->getType();
if (T->getAsStructureType()) {
if (Find(FR))
return true;
}
else {
const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
if (V.isUndef())
return true;
}
FieldChain.pop_back();
}
}
return false;
}
};
FindUninitializedField F(C.getASTContext(),
C.getState()->getStateManager().getStoreManager(),
C.getValueManager().getRegionManager(),
D->getStore());
if (F.Find(D->getRegion())) {
if (ExplodedNode *N = C.GenerateSink()) {
LazyInit_BT_call_arg();
llvm::SmallString<512> Str;
llvm::raw_svector_ostream os(Str);
os << "Passed-by-value struct argument contains uninitialized data";
if (F.FieldChain.size() == 1)
os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() << "')";
else {
os << " (e.g., via the field chain: '";
bool first = true;
for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
if (first)
first = false;
else
os << '.';
os << (*DI)->getNameAsString();
}
os << "')";
}
// Generate a report for this bug.
EnhancedBugReport *R =
new EnhancedBugReport(*BT_call_arg, os.str(), N);
R->addRange((*I)->getSourceRange());
// FIXME: enhance track back for uninitialized value for arbitrary
// memregions
C.EmitReport(R);
}
}
}
}
}

View File

@ -45,3 +45,9 @@ void test_uninit_neg() {
test_unit_aux2(v2.x + v1.y); // no-warning
}
extern void test_uninit_struct_arg_aux(struct TestUninit arg);
void test_uninit_struct_arg() {
struct TestUninit x;
test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
}