clang: lib/StaticAnalyzer/Core/ExplodedGraph.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

26#include "llvm/ADT/DenseSet.h"

27#include "llvm/ADT/FoldingSet.h"

28#include "llvm/ADT/PointerUnion.h"

29#include "llvm/ADT/SmallVector.h"

30#include "llvm/Support/Casting.h"

31#include

32#include

33#include

34

35using namespace clang;

36using namespace ento;

37

38

39

40

41

43

45

46

47

48

49

52 return false;

53 return isa<DeclRefExpr, MemberExpr, ObjCIvarRefExpr, ArraySubscriptExpr>(Ex);

54}

55

56bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88 if (node->pred_size() != 1 || node->succ_size() != 1)

89 return false;

90

91 const ExplodedNode *pred = *(node->pred_begin());

93 return false;

94

95 const ExplodedNode *succ = *(node->succ_begin());

97 return false;

98

99

100

101 ProgramPoint progPoint = node->getLocation();

103 return !progPoint.getTag();

104

105

107 return false;

108

109

110 if (progPoint.getTag())

111 return false;

112

113

116 if (state->store != pred_state->store || state->GDM != pred_state->GDM ||

118 return false;

119

120

121

123 if (!Ex)

124 return false;

125

126

127

128

130 return false;

131

132

133

134

135

138 return false;

139

140

142 if (std::optional SP = SuccLoc.getAs<StmtPoint>())

144 return false;

145

146

148 return false;

149

150 return true;

151}

152

153void ExplodedGraph::collectNode(ExplodedNode *node) {

154

155

156

157

158 assert(node->pred_size() == 1 || node->succ_size() == 1);

161 pred->replaceSuccessor(succ);

162 succ->replacePredecessor(pred);

164 Nodes.RemoveNode(node);

166 node->~ExplodedNode();

167}

168

171 return;

172

173

174

175

178 return;

180

182 if (shouldCollect(node))

183 collectNode(node);

185}

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

202using GroupStorage = llvm::PointerUnion<ExplodedNode *, ExplodedNodeVector *>;

203

205 assert(V->isSink());

206 Preds.addNode(V, G);

207 V->Succs.addNode(this, G);

208}

209

210void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {

211 assert(!getFlag());

212

214 assert(isa<ExplodedNode *>(Storage));

215 Storage = node;

216 assert(isa<ExplodedNode *>(Storage));

217}

218

220 assert(!getFlag());

221

223 if (Storage.isNull()) {

224 Storage = N;

225 assert(isa<ExplodedNode *>(Storage));

226 return;

227 }

228

230

231 if (V) {

232

233 auto *Old = cast<ExplodedNode *>(Storage);

234

237 V->push_back(Old, Ctx);

238

239 Storage = V;

240 assert(!getFlag());

241 assert(isa<ExplodedNodeVector *>(Storage));

242 }

243

245}

246

247unsigned ExplodedNode::NodeGroup::size() const {

248 if (getFlag())

249 return 0;

250

253 return 0;

255 return V->size();

256 return 1;

257}

258

259ExplodedNode * const *ExplodedNode::NodeGroup::begin() const {

260 if (getFlag())

261 return nullptr;

262

265 return nullptr;

267 return V->begin();

268 return Storage.getAddrOfPtr1();

269}

270

271ExplodedNode * const *ExplodedNode::NodeGroup::end() const {

272 if (getFlag())

273 return nullptr;

274

277 return nullptr;

279 return V->end();

280 return Storage.getAddrOfPtr1() + 1;

281}

282

287}

288

292 return BEP->getBlock();

293

294

295

296

302

303 return nullptr;

304}

305

310 assert(ParentLC && "We don't start analysis from autosynthesized code");

312 LC = ParentLC;

314 assert(ParentLC && "We don't start analysis from autosynthesized code");

315 }

316 return LC;

317}

318

320

321

322

325

327 ->getCallSite();

328 }

329

330

333 return SP->getStmt();

335 return BE->getSrc()->getTerminatorStmt();

337 return CE->getCallExpr();

339 return CEE->getCalleeContext()->getCallSite();

341 return PIPP->getInitializer()->getInit();

343 return CEB->getReturnStmt();

345 return FEP->getStmt();

346

347 return nullptr;

348}

349

353 continue;

355

356

357 switch (S->getStmtClass()) {

358 case Stmt::ChooseExprClass:

359 case Stmt::BinaryConditionalOperatorClass:

360 case Stmt::ConditionalOperatorClass:

361 continue;

362 case Stmt::BinaryOperatorClass: {

364 if (Op == BO_LAnd || Op == BO_LOr)

365 continue;

366 break;

367 }

368 default:

369 break;

370 }

371

372 return S;

373 }

374 }

375

376 return nullptr;

377}

378

382 return S;

383

384 return nullptr;

385}

386

389 return S;

390

392}

393

396 bool IsSink,

397 bool* IsNew) {

398

399 llvm::FoldingSetNodeID profile;

400 void *InsertPos = nullptr;

401

403 NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);

404

405 if (V) {

409 }

410 else {

411

413 }

414

417

420

421

422 Nodes.InsertNode(V, InsertPos);

423

424 if (IsNew) *IsNew = true;

425 }

426 else

427 if (IsNew) *IsNew = false;

428

429 return V;

430}

431

434 int64_t Id,

435 bool IsSink) {

437 new (V) NodeTy(L, State, Id, IsSink);

438 return V;

439}

440

441std::unique_ptr

445 if (Nodes.empty())

446 return nullptr;

447

448 using Pass1Ty = llvm::DenseSet<const ExplodedNode *>;

449 Pass1Ty Pass1;

450

453 Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch;

454

456

457

458 for (const auto Sink : Sinks)

459 if (Sink)

460 WL1.push_back(Sink);

461

462

463 while (!WL1.empty()) {

465

466

467 if (!Pass1.insert(N).second)

468 continue;

469

470

471 if (N->Preds.empty()) {

472 WL2.push_back(N);

473 continue;

474 }

475

476

477 WL1.append(N->Preds.begin(), N->Preds.end());

478 }

479

480

481 if (WL2.empty())

482 return nullptr;

483

484

486

487

488 while (!WL2.empty()) {

490

491

492 if (Pass2.contains(N))

493 continue;

494

495

496

499 Pass2[N] = NewN;

500

501

502 if (InverseMap) (*InverseMap)[NewN] = N;

503

504

505 if (N->Preds.empty())

506 G->addRoot(NewN);

507

508

509

510

511

512

514 Pass2Ty::iterator PI = Pass2.find(Pred);

515 if (PI == Pass2.end())

516 continue;

517

519 }

520

521

522

523

524

526 Pass2Ty::iterator PI = Pass2.find(Succ);

527 if (PI != Pass2.end()) {

528 const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G);

529 continue;

530 }

531

532

533 if (Pass1.count(Succ))

534 WL2.push_back(Succ);

535 }

536 }

537

538 return G;

539}

llvm::PointerUnion< ExplodedNode *, ExplodedNodeVector * > GroupStorage

BumpVector< ExplodedNode * > ExplodedNodeVector

static const LocationContext * findTopAutosynthesizedParentContext(const LocationContext *LC)

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

CFGStmtMap * getCFGStmtMap()

bool isBodyAutosynthesized() const

Represents a single basic block in a source-level CFG.

CFGBlock * getBlock(Stmt *S)

Returns the CFGBlock the specified Stmt* appears in.

Represents a point when we begin processing an inlined call.

Represents a point when we start the call exit sequence (for inlined call).

Represents a point when we finish the call exit sequence (for inlined call).

This represents one expression.

bool isLValue() const

isLValue - True if this expression is an "l-value" according to the rules of the current language.

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

const ParentMap & getParentMap() const

LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const

const LocationContext * getParent() const

It might return null.

bool isConsumedExpr(Expr *E) const

Represents a program point after a store evaluation.

Represents a program point just before an implicit call event.

Represents a point after we ran remove dead bindings BEFORE processing the given statement.

const ProgramPointTag * getTag() const

bool isPurgeKind()

Is this a program point corresponding to purge/removal of dead symbols and bindings.

T castAs() const

Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.

std::optional< T > getAs() const

Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...

const LocationContext * getLocationContext() const

const Stmt * getStmt() const

Stmt - This represents one statement.

static bool isCallStmt(const Stmt *S)

Returns true if this is a statement is a function or method call of some kind.

std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy * > Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const

Creates a trimmed version of the graph that only contains paths leading to the given nodes.

BumpVectorContext & getNodeAllocator()

unsigned ReclaimCounter

Counter to determine when to reclaim nodes.

NodeVector ChangedNodes

A list of recently allocated nodes that can potentially be recycled.

int64_t NumNodes

NumNodes - The number of nodes in the graph.

unsigned ReclaimNodeInterval

Determines how often nodes are reclaimed.

void reclaimRecentlyAllocatedNodes()

Reclaim "uninteresting" nodes created since the last time this method was called.

static bool isInterestingLValueExpr(const Expr *Ex)

Returns true if nodes for the given expression kind are always kept around.

llvm::BumpPtrAllocator & getAllocator()

std::unique_ptr< ExplodedGraph > MakeEmptyGraph() const

ExplodedNode * getNode(const ProgramPoint &L, ProgramStateRef State, bool IsSink=false, bool *IsNew=nullptr)

Retrieve the node associated with a (Location,State) pair, where the 'Location' is a ProgramPoint in ...

ExplodedNode * createUncachedNode(const ProgramPoint &L, ProgramStateRef State, int64_t Id, bool IsSink=false)

Create a node for a (Location, State) pair, but don't store it for deduplication later.

llvm::FoldingSet< ExplodedNode > Nodes

Nodes - The nodes in the graph.

NodeVector FreeNodes

A list of nodes that can be reused.

const CFGBlock * getCFGBlock() const

const ProgramStateRef & getState() const

const Stmt * getStmtForDiagnostics() const

If the node's program point corresponds to a statement, retrieve that statement.

bool isTrivial() const

The node is trivial if it has only one successor, only one predecessor, it's predecessor has only one...

const Stmt * getPreviousStmtForDiagnostics() const

Find the statement that was executed immediately before this node.

ProgramPoint getLocation() const

getLocation - Returns the edge associated with the given node.

void addPredecessor(ExplodedNode *V, ExplodedGraph &G)

addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...

ExplodedNode * getFirstSucc()

unsigned pred_size() const

static void Profile(llvm::FoldingSetNodeID &ID, const ProgramPoint &Loc, const ProgramStateRef &state, bool IsSink)

const Stmt * getNextStmtForDiagnostics() const

Find the next statement that was executed on this node's execution path.

const LocationContext * getLocationContext() const

const Stmt * getCurrentOrPreviousStmtForDiagnostics() const

Find the statement that was executed at or immediately before this node.

ExplodedNode * getFirstPred()

unsigned succ_size() const

llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap

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