clang: lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

28

29using namespace clang;

32

33

34

36

37namespace {

38

39class UninitializedObjectChecker

40 : public Checker<check::EndFunction, check::DeadSymbols> {

41 const BugType BT_uninitField{this, "Uninitialized fields"};

42

43public:

44

45 UninitObjCheckerOptions Opts;

46

47 void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;

48 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;

49};

50

51

52

53class RegularField final : public FieldNode {

54public:

55 RegularField(const FieldRegion *FR) : FieldNode(FR) {}

56

57 void printNoteMsg(llvm::raw_ostream &Out) const override {

58 Out << "uninitialized field ";

59 }

60

61 void printPrefix(llvm::raw_ostream &Out) const override {}

62

63 void printNode(llvm::raw_ostream &Out) const override {

65 }

66

67 void printSeparator(llvm::raw_ostream &Out) const override { Out << '.'; }

68};

69

70

71

72

73

74class BaseClass final : public FieldNode {

75 const QualType BaseClassT;

76

77public:

78 BaseClass(const QualType &T) : FieldNode(nullptr), BaseClassT(T) {

79 assert(T.isNull());

81 }

82

83 void printNoteMsg(llvm::raw_ostream &Out) const override {

84 llvm_unreachable("This node can never be the final node in the "

85 "fieldchain!");

86 }

87

88 void printPrefix(llvm::raw_ostream &Out) const override {}

89

90 void printNode(llvm::raw_ostream &Out) const override {

91 Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";

92 }

93

94 void printSeparator(llvm::raw_ostream &Out) const override {}

95

96 bool isBase() const override { return true; }

97};

98

99}

100

101

102

103

104

108

109

110

111

114

115

116

118

119

120

121

122

123

124

125

126

128

129

130

131

132

133void UninitializedObjectChecker::checkEndFunction(

135

136 const auto *CtorDecl = dyn_cast_or_null(

137 Context.getLocationContext()->getDecl());

138 if (!CtorDecl)

139 return;

140

141 if (!CtorDecl->isUserProvided())

142 return;

143

144 if (CtorDecl->getParent()->isUnion())

145 return;

146

147

149 return;

150

152 if (!R)

153 return;

154

155 FindUninitializedFields F(Context.getState(), R, Opts);

156

157 std::pair<ProgramStateRef, const UninitFieldMap &> UninitInfo =

158 F.getResults();

159

161 const UninitFieldMap &UninitFields = UninitInfo.second;

162

163 if (UninitFields.empty()) {

164 Context.addTransition(UpdatedState);

165 return;

166 }

167

168

169

170 ExplodedNode *Node = Context.generateNonFatalErrorNode(UpdatedState);

171 if (!Node)

172 return;

173

174 PathDiagnosticLocation LocUsedForUniqueing;

175 const Stmt *CallSite = Context.getStackFrame()->getCallSite();

176 if (CallSite)

179

180

181

183 for (const auto &Pair : UninitFields) {

184

185 auto Report = std::make_unique(

186 BT_uninitField, Pair.second, Node, LocUsedForUniqueing,

188 Context.emitReport(std::move(Report));

189 }

190 return;

191 }

192

193 SmallString<100> WarningBuf;

194 llvm::raw_svector_ostream WarningOS(WarningBuf);

195 WarningOS << UninitFields.size() << " uninitialized field"

196 << (UninitFields.size() == 1 ? "" : "s")

197 << " at the end of the constructor call";

198

199 auto Report = std::make_unique(

200 BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,

202

203 for (const auto &Pair : UninitFields) {

204 Report->addNote(Pair.second,

207 }

208 Context.emitReport(std::move(Report));

209}

210

211void UninitializedObjectChecker::checkDeadSymbols(SymbolReaper &SR,

212 CheckerContext &C) const {

214 for (const MemRegion *R : State->get()) {

216 State = State->remove(R);

217 }

218}

219

220

221

222

223

227 : State(State), ObjectR(R), Opts(Opts) {

228

229 isNonUnionUninit(ObjectR, FieldChainInfo(ChainFactory));

230

231

232

234 UninitFields.clear();

235}

236

237bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain,

240

242 "One must also pass the pointee region as a parameter for "

243 "dereferenceable fields!");

244

245 if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(

247 return false;

248

250 return false;

251

252 if (State->contains(FR))

253 return false;

254

255 if (PointeeR) {

256 if (State->contains(PointeeR)) {

257 return false;

258 }

259 State = State->add(PointeeR);

260 }

261

262 State = State->add(FR);

263

264 UninitFieldMap::mapped_type NoteMsgBuf;

265 llvm::raw_svector_ostream OS(NoteMsgBuf);

267

268 return UninitFields.insert({FR, std::move(NoteMsgBuf)}).second;

269}

270

271bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,

275 "This method only checks non-union record objects!");

276

278

279 if (!RD) {

280 IsAnyFieldInitialized = true;

281 return true;

282 }

283

284 if (!Opts.IgnoredRecordsWithFieldPattern.empty() &&

286 IsAnyFieldInitialized = true;

287 return false;

288 }

289

290 bool ContainsUninitField = false;

291

292

293 for (const FieldDecl *I : RD->fields()) {

294 if (I->isUnnamedBitField()) {

295 continue;

296 }

297 const auto FieldVal =

298 State->getLValue(I, loc::MemRegionVal(R)).castAsloc::MemRegionVal();

299 const auto *FR = FieldVal.getRegionAs();

300 QualType T = I->getType();

301

302

303

304

306 return false;

307

309 if (isNonUnionUninit(FR, LocalChain.add(RegularField(FR))))

310 ContainsUninitField = true;

311 continue;

312 }

313

315 if (isUnionUninit(FR)) {

316 if (addFieldToUninits(LocalChain.add(RegularField(FR))))

317 ContainsUninitField = true;

318 } else

319 IsAnyFieldInitialized = true;

320 continue;

321 }

322

324 IsAnyFieldInitialized = true;

325 continue;

326 }

327

328 SVal V = State->getSVal(FieldVal);

329

331 if (isDereferencableUninit(FR, LocalChain))

332 ContainsUninitField = true;

333 continue;

334 }

335

337 if (isPrimitiveUninit(V)) {

338 if (addFieldToUninits(LocalChain.add(RegularField(FR))))

339 ContainsUninitField = true;

340 }

341 continue;

342 }

343

344 llvm_unreachable("All cases are handled!");

345 }

346

347

348

349 const auto *CXXRD = dyn_cast(RD);

350 if (!CXXRD)

351 return ContainsUninitField;

352

353 for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {

354 const auto *BaseRegion = State->getLValue(BaseSpec, R)

355 .castAsloc::MemRegionVal()

356 .getRegionAs();

357

358

359

361 if (isNonUnionUninit(BaseRegion, LocalChain.replaceHead(

362 BaseClass(BaseSpec.getType()))))

363 ContainsUninitField = true;

364 } else {

365 if (isNonUnionUninit(BaseRegion,

366 LocalChain.add(BaseClass(BaseSpec.getType()))))

367 ContainsUninitField = true;

368 }

369 }

370

371 return ContainsUninitField;

372}

373

374bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {

376 "This method only checks union objects!");

377

378 return false;

379}

380

381bool FindUninitializedFields::isPrimitiveUninit(SVal V) {

382 if (V.isUndef())

383 return true;

384

385 IsAnyFieldInitialized = true;

386 return false;

387}

388

389

390

391

392

394 for (const FieldNode &Node : Chain) {

395 if (Node.isSameRegion(FR))

396 return true;

397 }

398 return false;

399}

400

401

402

403

404

405static void printTail(llvm::raw_ostream &Out,

407

408

409

410

411

412

413

414

415

416

417

418

419

420

422 if (Chain.isEmpty())

423 return;

424

426

428 Out << '\'';

429

430 for (const FieldNode &Node : Chain)

431 Node.printPrefix(Out);

432

433 Out << "this->";

436 Out << '\'';

437}

438

441 if (L.isEmpty())

442 return;

443

445

446 L.getHead().printNode(Out);

447 L.getHead().printSeparator(Out);

448}

449

450

451

452

453

457

458 Loc ThisLoc =

459 Context.getSValBuilder().getCXXThis(CtorDecl, Context.getStackFrame());

460

461 SVal ObjectV = Context.getState()->getSVal(ThisLoc);

462

465 return nullptr;

466

467 return R;

468}

469

472

474 if (!CurrRegion)

475 return false;

476

477 const LocationContext *LC = Context.getLocationContext();

479

480

481 const auto *OtherCtor = dyn_cast(LC->getDecl());

482 if (!OtherCtor)

483 continue;

484

487 if (!OtherRegion)

488 continue;

489

490

491

493 return true;

494 }

495

496 return false;

497}

498

500 llvm::Regex R(Pattern);

501

503 if (R.match(FD->getType().getAsString()))

504 return true;

505 if (R.match(FD->getName()))

506 return true;

507 }

508

509 return false;

510}

511

514 return nullptr;

515

517 return nullptr;

518

520}

521

523

525 return true;

526

527 const auto *Parent = dyn_cast(FD->getParent());

528

529 if (!Parent)

530 return true;

531

532 Parent = Parent->getDefinition();

533 assert(Parent && "The record's definition must be avaible if an uninitialized"

534 " field of it was found!");

535

536 ASTContext &AC = State->getStateManager().getContext();

537

539

541 hasAnyName("exit", "panic", "error", "Assert", "assert", "ziperr",

542 "assfail", "db_error", "__assert", "__assert2", "_wassert",

543 "__assert_rtn", "__assert_fail", "dtrace_assfail",

544 "yy_fatal_error", "_XCAssertionFailureHandler",

545 "_DTAssertionFailureHandler", "_TSAssertionFailureHandler"))));

546

548

549 auto GuardM =

551 NoReturnFuncM))

552 .bind("guard");

553

554 for (const CXXMethodDecl *M : Parent->methods()) {

556 if (!MethodBody)

557 continue;

558

560 if (Accesses.empty())

561 continue;

562 const auto *FirstAccess = Accesses[0].getNodeAs<MemberExpr>("access");

563 assert(FirstAccess);

564

566 if (Guards.empty())

567 return true;

568 const auto *FirstGuard = Guards[0].getNodeAs<Stmt>("guard");

569 assert(FirstGuard);

570

571 if (FirstAccess->getBeginLoc() < FirstGuard->getBeginLoc())

572 return true;

573 }

574

575 return false;

576}

577

579

580

581

582 const auto *CXXParent = dyn_cast(Field->getParent());

583

584 if (CXXParent && CXXParent->isLambda()) {

585 assert(CXXParent->captures_begin());

586 auto It = CXXParent->captures_begin() + Field->getFieldIndex();

587

588 if (It->capturesVariable())

589 return llvm::Twine("/*captured variable*/" +

590 It->getCapturedVar()->getName())

591 .str();

592

593 if (It->capturesThis())

594 return "/*'this' capture*/";

595

596 llvm_unreachable("No other capture type is expected!");

597 }

598

599 return std::string(Field->getName());

600}

601

602void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {

603 auto Chk = Mgr.registerChecker();

604

607

608 ChOpts.IsPedantic = AnOpts.getCheckerBooleanOption(Chk, "Pedantic");

610 Chk, "NotesAsWarnings");

612 Chk, "CheckPointeeInitialization");

614 std::string(AnOpts.getCheckerStringOption(Chk, "IgnoreRecordsWithField"));

616 AnOpts.getCheckerBooleanOption(Chk, "IgnoreGuardedFields");

617

618 std::string ErrorMsg;

621 "a valid regex, building failed with error message "

622 "\"" + ErrorMsg + "\"");

623}

624

625bool ento::shouldRegisterUninitializedObjectChecker(const CheckerManager &mgr) {

626 return true;

627}

#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)

Declares an immutable set of type NameTy, suitable for placement into the ProgramState.

static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match, std::string *Result)

static const Stmt * getMethodBody(const CXXMethodDecl *M)

Definition UninitializedObjectChecker.cpp:512

static const TypedValueRegion * getConstructedRegion(const CXXConstructorDecl *CtorDecl, CheckerContext &Context)

Returns the region that was constructed by CtorDecl, or nullptr if that isn't possible.

Definition UninitializedObjectChecker.cpp:455

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...

Definition UninitializedObjectChecker.cpp:522

static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, CheckerContext &Context)

Checks whether the object constructed by Ctor will be analyzed later (e.g.

Definition UninitializedObjectChecker.cpp:470

static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern)

Checks whether RD contains a field with a name or type name that matches Pattern.

Definition UninitializedObjectChecker.cpp:499

static void printTail(llvm::raw_ostream &Out, const FieldChainInfo::FieldChain L)

Prints every element except the last to Out.

Definition UninitializedObjectChecker.cpp:439

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

SourceManager & getSourceManager()

Stores options for the analyzer from the command line.

Represents a C++ constructor within a class.

Represents a static or instance method of a struct/union/class.

SourceLocation getLocation() const

AccessSpecifier getAccess() const

Represents a member of a struct/union/class.

const RecordDecl * getParent() const

Returns the parent of this field declaration, which is the struct in which this field is defined.

Stmt * getBody(const FunctionDecl *&Definition) const

Retrieve the body (definition) of the function.

FunctionDecl * getDefinition()

Get the definition for this declaration.

bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const

Returns true if the function has a definition that does not need to be instantiated.

It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...

const Decl * getDecl() const

const LocationContext * getParent() const

It might return null.

MemberExpr - [C99 6.5.2.3] Structure and Union Members.

Represents a struct/union/class.

field_range fields() const

RecordDecl * getDefinition() const

Returns the RecordDecl that actually defines this struct/union/class.

ReturnStmt - This represents a return, optionally of an expression: return; return 4;.

Stmt - This represents one statement.

CXXRecordDecl * getAsCXXRecordDecl() const

Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...

RecordDecl * getAsRecordDecl() const

Retrieves the RecordDecl this type refers to.

bool isStructureOrClassType() const

bool isRecordType() const

const AnalyzerOptions & getAnalyzerOptions() const

CHECKER * registerChecker(AT &&...Args)

Register a single-part checker (derived from Checker): construct its singleton instance,...

void reportInvalidCheckerOptionValue(const CheckerFrontend *Checker, StringRef OptionName, StringRef ExpectedValueDesc) const

Emits an error through a DiagnosticsEngine about an invalid user supplied checker option value.

Simple checker classes that implement one frontend (i.e.

const LocationContext * getLocationContext() const

Represents a field chain.

bool contains(const FieldRegion *FR) const

Definition UninitializedObjectChecker.cpp:393

llvm::ImmutableList< const FieldNode & > FieldChain

const FieldNode & getHead() const

const FieldRegion * getUninitRegion() const

FieldChainInfo replaceHead(const FieldNodeT &FN)

Constructs a new FieldChainInfo object with FN as the new head of the list.

FieldChainInfo add(const FieldNodeT &FN)

Constructs a new FieldChainInfo object with FN appended.

void printNoteMsg(llvm::raw_ostream &Out) const

Definition UninitializedObjectChecker.cpp:421

A lightweight polymorphic wrapper around FieldRegion *.

virtual bool isBase() 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...

virtual void printNode(llvm::raw_ostream &Out) const =0

Print the node. Should contain the name of the field stored in FR.

LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override

FindUninitializedFields(ProgramStateRef State, const TypedValueRegion *const R, const UninitObjCheckerOptions &Opts)

Constructs the FindUninitializedField object, searches for and stores uninitialized fields in R.

Definition UninitializedObjectChecker.cpp:224

bool isAnyFieldInitialized()

Returns whether the analyzed region contains at least one initialized field.

MemRegion - The root abstract class for all memory regions.

const RegionTy * getAs() const

static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)

Create a location for the beginning of the declaration.

static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)

Create a location corresponding to the given declaration.

SVal - This represents a symbolic expression, which can be either an L-value or an R-value.

const MemRegion * getAsRegion() const

bool isSubRegionOf(const MemRegion *R) const override

Check if the region is a subregion of the given region.

bool isLiveRegion(const MemRegion *region)

TypedValueRegion - An abstract class representing regions having a typed value.

virtual QualType getValueType() const =0

const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant

Matches AST nodes that have descendant AST nodes that match the provided matcher.

const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr

Matches call expressions.

SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)

Returns the results of matching Matcher on Node.

const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName

Matches NamedDecl nodes that have any of the specified names.

const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl

Matches function declarations.

const internal::VariadicDynCastAllOfMatcher< Stmt, SwitchStmt > switchStmt

Matches switch statements.

const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr

Matches member expressions.

internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)

Matches a node if the declaration associated with that node matches the given matcher.

const internal::VariadicAllOfMatcher< Stmt > stmt

Matches statements.

const internal::VariadicDynCastAllOfMatcher< Stmt, ConditionalOperator > conditionalOperator

Matches conditional operator expressions.

const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf

Matches if any of the given matchers matches.

const internal::VariadicDynCastAllOfMatcher< Stmt, IfStmt > ifStmt

Matches if statements.

std::string getVariableName(const FieldDecl *Field)

Returns with Field's name.

Definition UninitializedObjectChecker.cpp:578

std::map< const FieldRegion *, llvm::SmallString< 50 > > UninitFieldMap

bool isPrimitiveType(const QualType &T)

Returns true if T is a primitive type.

IntrusiveRefCntPtr< const ProgramState > ProgramStateRef

@ OS

Indicates that the tracking object is a descendant of a referenced-counted OSObject,...

bool isDereferencableType(const QualType &T)

The JSON file list parser is used to communicate input to InstallAPI.

bool isa(CodeGen::Address addr)

nullptr

This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...

const FunctionProtoType * T

bool ShouldConvertNotesToWarnings

std::string IgnoredRecordsWithFieldPattern

bool CheckPointeeInitialization