28 using namespace clang;
37 class UninitializedObjectChecker
38 :
public Checker<check::EndFunction, check::DeadSymbols> {
39 std::unique_ptr<BuiltinBug> BT_uninitField;
45 UninitializedObjectChecker()
46 : BT_uninitField(new
BuiltinBug(this,
"Uninitialized fields")) {}
54 class RegularField final :
public FieldNode {
58 virtual void printNoteMsg(llvm::raw_ostream &Out)
const override {
59 Out <<
"uninitialized field ";
62 virtual void printPrefix(llvm::raw_ostream &Out)
const override {}
64 virtual void printNode(llvm::raw_ostream &Out)
const override {
68 virtual void printSeparator(llvm::raw_ostream &Out)
const override {
77 class BaseClass final :
public FieldNode {
86 virtual void printNoteMsg(llvm::raw_ostream &Out)
const override {
87 llvm_unreachable(
"This node can never be the final node in the " 91 virtual void printPrefix(llvm::raw_ostream &Out)
const override {}
93 virtual void printNode(llvm::raw_ostream &Out)
const override {
94 Out << BaseClassT->getAsCXXRecordDecl()->getName() <<
"::";
97 virtual void printSeparator(llvm::raw_ostream &Out)
const override {}
99 virtual bool isBase()
const override {
return true; }
126 void UninitializedObjectChecker::checkEndFunction(
129 const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
134 if (!CtorDecl->isUserProvided())
137 if (CtorDecl->getParent()->isUnion())
150 std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =
156 if (UninitFields.empty()) {
175 if (Opts.ShouldConvertNotesToWarnings) {
176 for (
const auto &Pair : UninitFields) {
178 auto Report = llvm::make_unique<BugReport>(
179 *BT_uninitField, Pair.second,
Node, LocUsedForUniqueing,
187 llvm::raw_svector_ostream WarningOS(WarningBuf);
188 WarningOS << UninitFields.size() <<
" uninitialized field" 189 << (UninitFields.size() == 1 ?
"" :
"s")
190 <<
" at the end of the constructor call";
192 auto Report = llvm::make_unique<BugReport>(
193 *BT_uninitField, WarningOS.str(),
Node, LocUsedForUniqueing,
196 for (
const auto &Pair : UninitFields) {
197 Report->addNote(Pair.second,
204 void UninitializedObjectChecker::checkDeadSymbols(
SymbolReaper &SR,
207 for (
const MemRegion *R : State->get<AnalyzedRegions>()) {
209 State = State->remove<AnalyzedRegions>(R);
220 : State(State), ObjectR(R), Opts(Opts) {
227 UninitFields.clear();
230 bool FindUninitializedFields::addFieldToUninits(
FieldChainInfo Chain,
235 "One must also pass the pointee region as a parameter for " 236 "dereferenceable fields!");
238 if (State->contains<AnalyzedRegions>(FR))
242 if (State->contains<AnalyzedRegions>(PointeeR)) {
245 State = State->add<AnalyzedRegions>(PointeeR);
248 State = State->add<AnalyzedRegions>(FR);
250 if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
254 UninitFieldMap::mapped_type NoteMsgBuf;
255 llvm::raw_svector_ostream
OS(NoteMsgBuf);
257 return UninitFields.insert({FR, std::move(NoteMsgBuf)}).second;
264 "This method only checks non-union record objects!");
269 IsAnyFieldInitialized =
true;
275 IsAnyFieldInitialized =
true;
279 bool ContainsUninitField =
false;
282 for (
const FieldDecl *I : RD->fields()) {
284 const auto FieldVal =
295 if (T->isStructureOrClassType()) {
296 if (isNonUnionUninit(FR, LocalChain.
add(RegularField(FR))))
297 ContainsUninitField =
true;
301 if (T->isUnionType()) {
302 if (isUnionUninit(FR)) {
303 if (addFieldToUninits(LocalChain.
add(RegularField(FR))))
304 ContainsUninitField =
true;
306 IsAnyFieldInitialized =
true;
310 if (T->isArrayType()) {
311 IsAnyFieldInitialized =
true;
315 SVal V = State->getSVal(FieldVal);
318 if (isDereferencableUninit(FR, LocalChain))
319 ContainsUninitField =
true;
324 if (isPrimitiveUninit(V)) {
325 if (addFieldToUninits(LocalChain.
add(RegularField(FR))))
326 ContainsUninitField =
true;
331 llvm_unreachable(
"All cases are handled!");
338 return ContainsUninitField;
341 const auto *BaseRegion = State->getLValue(BaseSpec, R)
343 .getRegionAs<TypedValueRegion>();
348 if (isNonUnionUninit(BaseRegion, LocalChain.
replaceHead(
349 BaseClass(BaseSpec.getType()))))
350 ContainsUninitField =
true;
352 if (isNonUnionUninit(BaseRegion,
353 LocalChain.
add(BaseClass(BaseSpec.getType()))))
354 ContainsUninitField =
true;
358 return ContainsUninitField;
363 "This method only checks union objects!");
368 bool FindUninitializedFields::isPrimitiveUninit(
const SVal &V) {
372 IsAnyFieldInitialized =
true;
382 if (Node.isSameRegion(FR))
392 static void printTail(llvm::raw_ostream &Out,
418 Node.printPrefix(Out);
433 L.getHead().printNode(Out);
434 L.getHead().printSeparator(Out);
487 llvm::Regex R(Pattern);
490 if (R.match(FD->getType().getAsString()))
492 if (R.match(FD->getName()))
505 if (CXXParent && CXXParent->isLambda()) {
506 assert(CXXParent->captures_begin());
509 if (It->capturesVariable())
510 return llvm::Twine(
"/*captured variable*/" +
511 It->getCapturedVar()->getName())
514 if (It->capturesThis())
515 return "/*'this' capture*/";
517 llvm_unreachable(
"No other capture type is expected!");
523 void ento::registerUninitializedObjectChecker(
CheckerManager &Mgr) {
530 AnOpts.getCheckerBooleanOption(
"Pedantic",
false, Chk);
532 AnOpts.getCheckerBooleanOption(
"NotesAsWarnings",
false, Chk);
534 "CheckPointeeInitialization",
false, Chk);
536 AnOpts.getCheckerStringOption(
"IgnoreRecordsWithField",
TypedValueRegion - An abstract class representing regions having a typed value.
std::string IgnoredRecordsWithFieldPattern
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
bool ShouldConvertNotesToWarnings
const FieldRegion * getUninitRegion() const
Stmt - This represents one statement.
const REGION * getRegionAs() const
bool isRecordType() const
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
virtual QualType getValueType() const =0
bool contains(const FieldRegion *FR) const
bool isPrimitiveType(const QualType &T)
Returns true if T is a primitive type.
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined...
Represents a C++ constructor within a class.
bool isAnyFieldInitialized()
Returns whether the analyzed region contains at least one initialized field.
loc::MemRegionVal getCXXThis(const CXXMethodDecl *D, const StackFrameContext *SFC)
Return a memory region for the 'this' object reference.
Represents a struct/union/class.
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
FieldChainInfo add(const FieldNodeT &FN)
Constructs a new FieldChainInfo object with FN appended.
field_range fields() const
const FieldDecl * getDecl() const
const FieldNode & getHead() const
Represents a member of a struct/union/class.
static void printTail(llvm::raw_ostream &Out, const FieldChainInfo::FieldChain L)
Prints every element except the last to Out.
FindUninitializedFields(ProgramStateRef State, const TypedValueRegion *const R, const UninitObjCheckerOptions &Opts)
Constructs the FindUninitializedField object, searches for and stores uninitialized fields in R...
bool isLiveRegion(const MemRegion *region)
static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, CheckerContext &Context)
Checks whether the object constructed by Ctor will be analyzed later (e.g.
const LocationContext * getLocationContext() const
const LocationContext * getParent() const
virtual void printNode(llvm::raw_ostream &Out) const =0
Print the node. Should contain the name of the field stored in FR.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
bool isDereferencableType(const QualType &T)
bool CheckPointeeInitialization
static const TypedValueRegion * getConstructedRegion(const CXXConstructorDecl *CtorDecl, CheckerContext &Context)
Returns the region that was constructed by CtorDecl, or nullptr if that isn't possible.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const Stmt * getCallSite() const
const RegionTy * getAs() const
virtual void printNoteMsg(llvm::raw_ostream &Out) const =0
If this is the last element of the fieldchain, this method will print the note message associated wit...
std::string getVariableName(const FieldDecl *Field)
Returns with Field's name.
Searches for and stores uninitialized fields in a non-union object.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const MemRegion * getAsRegion() const
bool isSubRegionOf(const MemRegion *R) const override
Check if the region is a subregion of the given region.
static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern)
Checks whether RD contains a field with a name or type name that matches Pattern. ...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
A class responsible for cleaning up unused symbols.
virtual bool isBase() const
Represents a field chain.
ast_type_traits::DynTypedNode Node
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Dataflow Directional Tag Classes.
AnalyzerOptions & getAnalyzerOptions()
llvm::ImmutableList< const FieldNode & > FieldChain
const Decl * getDecl() const
std::map< const FieldRegion *, llvm::SmallString< 50 > > UninitFieldMap
const StackFrameContext * getStackFrame() const
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
const ProgramStateRef & getState() const
Stores options for the analyzer from the command line.
Represents a base class of a C++ class.
FieldChainInfo replaceHead(const FieldNodeT &FN)
Constructs a new FieldChainInfo object with FN as the new head of the list.
A lightweight polymorphic wrapper around FieldRegion *.
Represents a C++ struct/union/class.
std::pair< ProgramStateRef, const UninitFieldMap & > getResults()
Returns with the modified state and a map of (uninitialized region, note message) pairs...
SourceManager & getSourceManager()
SValBuilder & getSValBuilder()
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
capture_const_iterator captures_begin() const
const LocationContext * getLocationContext() const
SourceLocation getLocation() const
void printNoteMsg(llvm::raw_ostream &Out) const