29 using namespace clang;
39 class UninitializedObjectChecker
40 :
public Checker<check::EndFunction, check::DeadSymbols> {
41 std::unique_ptr<BuiltinBug> BT_uninitField;
47 UninitializedObjectChecker()
48 : BT_uninitField(new
BuiltinBug(this,
"Uninitialized fields")) {}
56 class RegularField final :
public FieldNode {
60 virtual void printNoteMsg(llvm::raw_ostream &Out)
const override {
61 Out <<
"uninitialized field ";
64 virtual void printPrefix(llvm::raw_ostream &Out)
const override {}
66 virtual void printNode(llvm::raw_ostream &Out)
const override {
70 virtual void printSeparator(llvm::raw_ostream &Out)
const override {
79 class BaseClass final :
public FieldNode {
88 virtual void printNoteMsg(llvm::raw_ostream &Out)
const override {
89 llvm_unreachable(
"This node can never be the final node in the " 93 virtual void printPrefix(llvm::raw_ostream &Out)
const override {}
95 virtual void printNode(llvm::raw_ostream &Out)
const override {
96 Out << BaseClassT->getAsCXXRecordDecl()->getName() <<
"::";
99 virtual void printSeparator(llvm::raw_ostream &Out)
const override {}
101 virtual bool isBase()
const override {
return true; }
138 void UninitializedObjectChecker::checkEndFunction(
141 const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
146 if (!CtorDecl->isUserProvided())
149 if (CtorDecl->getParent()->isUnion())
162 std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =
168 if (UninitFields.empty()) {
187 if (Opts.ShouldConvertNotesToWarnings) {
188 for (
const auto &Pair : UninitFields) {
190 auto Report = llvm::make_unique<BugReport>(
191 *BT_uninitField, Pair.second,
Node, LocUsedForUniqueing,
199 llvm::raw_svector_ostream WarningOS(WarningBuf);
200 WarningOS << UninitFields.size() <<
" uninitialized field" 201 << (UninitFields.size() == 1 ?
"" :
"s")
202 <<
" at the end of the constructor call";
204 auto Report = llvm::make_unique<BugReport>(
205 *BT_uninitField, WarningOS.str(),
Node, LocUsedForUniqueing,
208 for (
const auto &Pair : UninitFields) {
209 Report->addNote(Pair.second,
216 void UninitializedObjectChecker::checkDeadSymbols(
SymbolReaper &SR,
219 for (
const MemRegion *R : State->get<AnalyzedRegions>()) {
221 State = State->remove<AnalyzedRegions>(R);
232 : State(State), ObjectR(R), Opts(Opts) {
239 UninitFields.clear();
242 bool FindUninitializedFields::addFieldToUninits(
FieldChainInfo Chain,
247 "One must also pass the pointee region as a parameter for " 248 "dereferenceable fields!");
250 if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
257 if (State->contains<AnalyzedRegions>(FR))
261 if (State->contains<AnalyzedRegions>(PointeeR)) {
264 State = State->add<AnalyzedRegions>(PointeeR);
267 State = State->add<AnalyzedRegions>(FR);
269 UninitFieldMap::mapped_type NoteMsgBuf;
270 llvm::raw_svector_ostream
OS(NoteMsgBuf);
273 return UninitFields.insert({FR, std::move(NoteMsgBuf)}).second;
280 "This method only checks non-union record objects!");
285 IsAnyFieldInitialized =
true;
291 IsAnyFieldInitialized =
true;
295 bool ContainsUninitField =
false;
298 for (
const FieldDecl *I : RD->fields()) {
300 const auto FieldVal =
311 if (T->isStructureOrClassType()) {
312 if (isNonUnionUninit(FR, LocalChain.
add(RegularField(FR))))
313 ContainsUninitField =
true;
317 if (T->isUnionType()) {
318 if (isUnionUninit(FR)) {
319 if (addFieldToUninits(LocalChain.
add(RegularField(FR))))
320 ContainsUninitField =
true;
322 IsAnyFieldInitialized =
true;
326 if (T->isArrayType()) {
327 IsAnyFieldInitialized =
true;
331 SVal V = State->getSVal(FieldVal);
334 if (isDereferencableUninit(FR, LocalChain))
335 ContainsUninitField =
true;
340 if (isPrimitiveUninit(V)) {
341 if (addFieldToUninits(LocalChain.
add(RegularField(FR))))
342 ContainsUninitField =
true;
347 llvm_unreachable(
"All cases are handled!");
354 return ContainsUninitField;
357 const auto *BaseRegion = State->getLValue(BaseSpec, R)
359 .getRegionAs<TypedValueRegion>();
364 if (isNonUnionUninit(BaseRegion, LocalChain.
replaceHead(
365 BaseClass(BaseSpec.getType()))))
366 ContainsUninitField =
true;
368 if (isNonUnionUninit(BaseRegion,
369 LocalChain.
add(BaseClass(BaseSpec.getType()))))
370 ContainsUninitField =
true;
374 return ContainsUninitField;
379 "This method only checks union objects!");
384 bool FindUninitializedFields::isPrimitiveUninit(
const SVal &
V) {
388 IsAnyFieldInitialized =
true;
398 if (Node.isSameRegion(FR))
408 static void printTail(llvm::raw_ostream &Out,
434 Node.printPrefix(Out);
449 L.getHead().printNode(Out);
450 L.getHead().printSeparator(Out);
503 llvm::Regex R(Pattern);
506 if (R.match(FD->getType().getAsString()))
508 if (R.match(FD->getName()))
516 if (isa<CXXConstructorDecl>(M))
536 assert(
Parent &&
"The record's definition must be avaible if an uninitialized" 537 " field of it was found!");
539 ASTContext &AC = State->getStateManager().getContext();
550 hasName(
"_DTAssertionFailureHandler"),
551 hasName(
"_TSAssertionFailureHandler")))));
566 if (Accesses.empty())
568 const auto *FirstAccess = Accesses[0].getNodeAs<
MemberExpr>(
"access");
574 const auto *FirstGuard = Guards[0].getNodeAs<
Stmt>(
"guard");
577 if (FirstAccess->getBeginLoc() < FirstGuard->getBeginLoc())
590 if (CXXParent && CXXParent->isLambda()) {
591 assert(CXXParent->captures_begin());
594 if (It->capturesVariable())
595 return llvm::Twine(
"/*captured variable*/" +
596 It->getCapturedVar()->getName())
599 if (It->capturesThis())
600 return "/*'this' capture*/";
602 llvm_unreachable(
"No other capture type is expected!");
608 void ento::registerUninitializedObjectChecker(
CheckerManager &Mgr) {
614 ChOpts.
IsPedantic = AnOpts.getCheckerBooleanOption(Chk,
"Pedantic");
616 Chk,
"NotesAsWarnings");
618 Chk,
"CheckPointeeInitialization");
620 AnOpts.getCheckerStringOption(Chk,
"IgnoreRecordsWithField");
622 AnOpts.getCheckerBooleanOption(Chk,
"IgnoreGuardedFields");
624 std::string ErrorMsg;
627 "a valid regex, building failed with error message " 628 "\"" + ErrorMsg +
"\"");
631 bool ento::shouldRegisterUninitializedObjectChecker(
const LangOptions &LO) {
FunctionDecl * getDefinition()
Get the definition for this declaration.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
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.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
bool ShouldConvertNotesToWarnings
const FieldRegion * getUninitRegion() const
Stmt - This represents one statement.
internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher, internal::Matcher< Decl >, void(internal::HasDeclarationSupportedTypes)> hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const REGION * getRegionAs() const
bool isRecordType() const
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
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 internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher. ...
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined...
bool isDefined(const FunctionDecl *&Definition) const
Returns true if the function has a definition that does not need to be instantiated.
Represents a C++ constructor within a class.
bool isAnyFieldInitialized()
Returns whether the analyzed region contains at least one initialized field.
static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State)
Checks syntactically whether it is possible to access FD from the record that contains it without a p...
loc::MemRegionVal getCXXThis(const CXXMethodDecl *D, const StackFrameContext *SFC)
Return a memory region for the 'this' object reference.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
Represents a struct/union/class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
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.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
FindUninitializedFields(ProgramStateRef State, const TypedValueRegion *const R, const UninitObjCheckerOptions &Opts)
Constructs the FindUninitializedField object, searches for and stores uninitialized fields in R...
const internal::VariadicDynCastAllOfMatcher< Stmt, IfStmt > ifStmt
Matches if statements.
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)
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
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...
const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr
Matches member expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, SwitchStmt > switchStmt
Matches switch statements.
std::string getVariableName(const FieldDecl *Field)
Returns with Field's name.
Searches for and stores uninitialized fields in a non-union object.
void reportInvalidCheckerOptionValue(const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc)
Emits an error through a DiagnosticsEngine about an invalid user supplied checker option value...
const internal::VariadicDynCastAllOfMatcher< Stmt, ConditionalOperator > conditionalOperator
Matches conditional operator expressions.
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.
Represents a static or instance method of a struct/union/class.
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.
AccessSpecifier getAccess() const
static const Stmt * getMethodBody(const CXXMethodDecl *M)
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 *.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
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()
internal::Matcher< NamedDecl > hasName(const std::string &Name)
Matches NamedDecl nodes that have the specified name.
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