Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- CoreEngine.h - Path-Sensitive Dataflow Engine ------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file defines a generic engine for intraprocedural, path-sensitive,
10
//  dataflow analysis via graph reachability.
11
//
12
//===----------------------------------------------------------------------===//
13
 
14
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
15
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
16
 
17
#include "clang/AST/Stmt.h"
18
#include "clang/Analysis/AnalysisDeclContext.h"
19
#include "clang/Analysis/CFG.h"
20
#include "clang/Analysis/ProgramPoint.h"
21
#include "clang/Basic/LLVM.h"
22
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
24
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
25
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
27
#include "llvm/ADT/SmallVector.h"
28
#include "llvm/Support/Casting.h"
29
#include <cassert>
30
#include <memory>
31
#include <utility>
32
#include <vector>
33
 
34
namespace clang {
35
 
36
class AnalyzerOptions;
37
class CXXBindTemporaryExpr;
38
class Expr;
39
class LabelDecl;
40
 
41
namespace ento {
42
 
43
class FunctionSummariesTy;
44
class ExprEngine;
45
 
46
//===----------------------------------------------------------------------===//
47
/// CoreEngine - Implements the core logic of the graph-reachability
48
///   analysis. It traverses the CFG and generates the ExplodedGraph.
49
///   Program "states" are treated as opaque void pointers.
50
///   The template class CoreEngine (which subclasses CoreEngine)
51
///   provides the matching component to the engine that knows the actual types
52
///   for states.  Note that this engine only dispatches to transfer functions
53
///   at the statement and block-level.  The analyses themselves must implement
54
///   any transfer function logic and the sub-expression level (if any).
55
class CoreEngine {
56
  friend class CommonNodeBuilder;
57
  friend class EndOfFunctionNodeBuilder;
58
  friend class ExprEngine;
59
  friend class IndirectGotoNodeBuilder;
60
  friend class NodeBuilder;
61
  friend struct NodeBuilderContext;
62
  friend class SwitchNodeBuilder;
63
 
64
public:
65
  using BlocksExhausted =
66
      std::vector<std::pair<BlockEdge, const ExplodedNode *>>;
67
 
68
  using BlocksAborted =
69
      std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>;
70
 
71
private:
72
  ExprEngine &ExprEng;
73
 
74
  /// G - The simulation graph.  Each node is a (location,state) pair.
75
  mutable ExplodedGraph G;
76
 
77
  /// WList - A set of queued nodes that need to be processed by the
78
  ///  worklist algorithm.  It is up to the implementation of WList to decide
79
  ///  the order that nodes are processed.
80
  std::unique_ptr<WorkList> WList;
81
  std::unique_ptr<WorkList> CTUWList;
82
 
83
  /// BCounterFactory - A factory object for created BlockCounter objects.
84
  ///   These are used to record for key nodes in the ExplodedGraph the
85
  ///   number of times different CFGBlocks have been visited along a path.
86
  BlockCounter::Factory BCounterFactory;
87
 
88
  /// The locations where we stopped doing work because we visited a location
89
  ///  too many times.
90
  BlocksExhausted blocksExhausted;
91
 
92
  /// The locations where we stopped because the engine aborted analysis,
93
  /// usually because it could not reason about something.
94
  BlocksAborted blocksAborted;
95
 
96
  /// The information about functions shared by the whole translation unit.
97
  /// (This data is owned by AnalysisConsumer.)
98
  FunctionSummariesTy *FunctionSummaries;
99
 
100
  /// Add path tags with some useful data along the path when we see that
101
  /// something interesting is happening. This field is the allocator for such
102
  /// tags.
103
  DataTag::Factory DataTags;
104
 
105
  void setBlockCounter(BlockCounter C);
106
 
107
  void generateNode(const ProgramPoint &Loc,
108
                    ProgramStateRef State,
109
                    ExplodedNode *Pred);
110
 
111
  void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
112
  void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
113
  void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
114
 
115
  void HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred);
116
 
117
  void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
118
 
119
  void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
120
                    ExplodedNode *Pred);
121
  void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
122
                                    const CFGBlock *B, ExplodedNode *Pred);
123
 
124
  /// Handle conditional logic for running static initializers.
125
  void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
126
                        ExplodedNode *Pred);
127
 
128
  void HandleVirtualBaseBranch(const CFGBlock *B, ExplodedNode *Pred);
129
 
130
private:
131
  ExplodedNode *generateCallExitBeginNode(ExplodedNode *N,
132
                                          const ReturnStmt *RS);
133
 
134
public:
135
  /// Construct a CoreEngine object to analyze the provided CFG.
136
  CoreEngine(ExprEngine &exprengine,
137
             FunctionSummariesTy *FS,
138
             AnalyzerOptions &Opts);
139
 
140
  CoreEngine(const CoreEngine &) = delete;
141
  CoreEngine &operator=(const CoreEngine &) = delete;
142
 
143
  /// getGraph - Returns the exploded graph.
144
  ExplodedGraph &getGraph() { return G; }
145
 
146
  /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
147
  ///  steps.  Returns true if there is still simulation state on the worklist.
148
  bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
149
                       ProgramStateRef InitState);
150
 
151
  /// Returns true if there is still simulation state on the worklist.
152
  bool ExecuteWorkListWithInitialState(const LocationContext *L,
153
                                       unsigned Steps,
154
                                       ProgramStateRef InitState,
155
                                       ExplodedNodeSet &Dst);
156
 
157
  /// Dispatch the work list item based on the given location information.
158
  /// Use Pred parameter as the predecessor state.
159
  void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
160
                        const WorkListUnit& WU);
161
 
162
  // Functions for external checking of whether we have unfinished work
163
  bool wasBlockAborted() const { return !blocksAborted.empty(); }
164
  bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
165
  bool hasWorkRemaining() const { return wasBlocksExhausted() ||
166
                                         WList->hasWork() ||
167
                                         wasBlockAborted(); }
168
 
169
  /// Inform the CoreEngine that a basic block was aborted because
170
  /// it could not be completely analyzed.
171
  void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
172
    blocksAborted.push_back(std::make_pair(block, node));
173
  }
174
 
175
  WorkList *getWorkList() const { return WList.get(); }
176
  WorkList *getCTUWorkList() const { return CTUWList.get(); }
177
 
178
  BlocksExhausted::const_iterator blocks_exhausted_begin() const {
179
    return blocksExhausted.begin();
180
  }
181
 
182
  BlocksExhausted::const_iterator blocks_exhausted_end() const {
183
    return blocksExhausted.end();
184
  }
185
 
186
  BlocksAborted::const_iterator blocks_aborted_begin() const {
187
    return blocksAborted.begin();
188
  }
189
 
190
  BlocksAborted::const_iterator blocks_aborted_end() const {
191
    return blocksAborted.end();
192
  }
193
 
194
  /// Enqueue the given set of nodes onto the work list.
195
  void enqueue(ExplodedNodeSet &Set);
196
 
197
  /// Enqueue nodes that were created as a result of processing
198
  /// a statement onto the work list.
199
  void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx);
200
 
201
  /// enqueue the nodes corresponding to the end of function onto the
202
  /// end of path / work list.
203
  void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS);
204
 
205
  /// Enqueue a single node created as a result of statement processing.
206
  void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
207
 
208
  DataTag::Factory &getDataTags() { return DataTags; }
209
};
210
 
211
// TODO: Turn into a class.
212
struct NodeBuilderContext {
213
  const CoreEngine &Eng;
214
  const CFGBlock *Block;
215
  const LocationContext *LC;
216
 
217
  NodeBuilderContext(const CoreEngine &E, const CFGBlock *B,
218
                     const LocationContext *L)
219
      : Eng(E), Block(B), LC(L) {
220
    assert(B);
221
  }
222
 
223
  NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
224
      : NodeBuilderContext(E, B, N->getLocationContext()) {}
225
 
226
  /// Return the CFGBlock associated with this builder.
227
  const CFGBlock *getBlock() const { return Block; }
228
 
229
  /// Returns the number of times the current basic block has been
230
  /// visited on the exploded graph path.
231
  unsigned blockCount() const {
232
    return Eng.WList->getBlockCounter().getNumVisited(
233
                    LC->getStackFrame(),
234
                    Block->getBlockID());
235
  }
236
};
237
 
238
/// \class NodeBuilder
239
/// This is the simplest builder which generates nodes in the
240
/// ExplodedGraph.
241
///
242
/// The main benefit of the builder is that it automatically tracks the
243
/// frontier nodes (or destination set). This is the set of nodes which should
244
/// be propagated to the next step / builder. They are the nodes which have been
245
/// added to the builder (either as the input node set or as the newly
246
/// constructed nodes) but did not have any outgoing transitions added.
247
class NodeBuilder {
248
  virtual void anchor();
249
 
250
protected:
251
  const NodeBuilderContext &C;
252
 
253
  /// Specifies if the builder results have been finalized. For example, if it
254
  /// is set to false, autotransitions are yet to be generated.
255
  bool Finalized;
256
 
257
  bool HasGeneratedNodes = false;
258
 
259
  /// The frontier set - a set of nodes which need to be propagated after
260
  /// the builder dies.
261
  ExplodedNodeSet &Frontier;
262
 
263
  /// Checks if the results are ready.
264
  virtual bool checkResults() {
265
    return Finalized;
266
  }
267
 
268
  bool hasNoSinksInFrontier() {
269
    for (const auto  I : Frontier)
270
      if (I->isSink())
271
        return false;
272
    return true;
273
  }
274
 
275
  /// Allow subclasses to finalize results before result_begin() is executed.
276
  virtual void finalizeResults() {}
277
 
278
  ExplodedNode *generateNodeImpl(const ProgramPoint &PP,
279
                                 ProgramStateRef State,
280
                                 ExplodedNode *Pred,
281
                                 bool MarkAsSink = false);
282
 
283
public:
284
  NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
285
              const NodeBuilderContext &Ctx, bool F = true)
286
      : C(Ctx), Finalized(F), Frontier(DstSet) {
287
    Frontier.Add(SrcNode);
288
  }
289
 
290
  NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
291
              const NodeBuilderContext &Ctx, bool F = true)
292
      : C(Ctx), Finalized(F), Frontier(DstSet) {
293
    Frontier.insert(SrcSet);
294
    assert(hasNoSinksInFrontier());
295
  }
296
 
297
  virtual ~NodeBuilder() = default;
298
 
299
  /// Generates a node in the ExplodedGraph.
300
  ExplodedNode *generateNode(const ProgramPoint &PP,
301
                             ProgramStateRef State,
302
                             ExplodedNode *Pred) {
303
    return generateNodeImpl(
304
        PP, State, Pred,
305
        /*MarkAsSink=*/State->isPosteriorlyOverconstrained());
306
  }
307
 
308
  /// Generates a sink in the ExplodedGraph.
309
  ///
310
  /// When a node is marked as sink, the exploration from the node is stopped -
311
  /// the node becomes the last node on the path and certain kinds of bugs are
312
  /// suppressed.
313
  ExplodedNode *generateSink(const ProgramPoint &PP,
314
                             ProgramStateRef State,
315
                             ExplodedNode *Pred) {
316
    return generateNodeImpl(PP, State, Pred, true);
317
  }
318
 
319
  const ExplodedNodeSet &getResults() {
320
    finalizeResults();
321
    assert(checkResults());
322
    return Frontier;
323
  }
324
 
325
  using iterator = ExplodedNodeSet::iterator;
326
 
327
  /// Iterators through the results frontier.
328
  iterator begin() {
329
    finalizeResults();
330
    assert(checkResults());
331
    return Frontier.begin();
332
  }
333
 
334
  iterator end() {
335
    finalizeResults();
336
    return Frontier.end();
337
  }
338
 
339
  const NodeBuilderContext &getContext() { return C; }
340
  bool hasGeneratedNodes() { return HasGeneratedNodes; }
341
 
342
  void takeNodes(const ExplodedNodeSet &S) {
343
    for (const auto I : S)
344
      Frontier.erase(I);
345
  }
346
 
347
  void takeNodes(ExplodedNode *N) { Frontier.erase(N); }
348
  void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); }
349
  void addNodes(ExplodedNode *N) { Frontier.Add(N); }
350
};
351
 
352
/// \class NodeBuilderWithSinks
353
/// This node builder keeps track of the generated sink nodes.
354
class NodeBuilderWithSinks: public NodeBuilder {
355
  void anchor() override;
356
 
357
protected:
358
  SmallVector<ExplodedNode*, 2> sinksGenerated;
359
  ProgramPoint &Location;
360
 
361
public:
362
  NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
363
                       const NodeBuilderContext &Ctx, ProgramPoint &L)
364
      : NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
365
 
366
  ExplodedNode *generateNode(ProgramStateRef State,
367
                             ExplodedNode *Pred,
368
                             const ProgramPointTag *Tag = nullptr) {
369
    const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
370
    return NodeBuilder::generateNode(LocalLoc, State, Pred);
371
  }
372
 
373
  ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
374
                             const ProgramPointTag *Tag = nullptr) {
375
    const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
376
    ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred);
377
    if (N && N->isSink())
378
      sinksGenerated.push_back(N);
379
    return N;
380
  }
381
 
382
  const SmallVectorImpl<ExplodedNode*> &getSinks() const {
383
    return sinksGenerated;
384
  }
385
};
386
 
387
/// \class StmtNodeBuilder
388
/// This builder class is useful for generating nodes that resulted from
389
/// visiting a statement. The main difference from its parent NodeBuilder is
390
/// that it creates a statement specific ProgramPoint.
391
class StmtNodeBuilder: public NodeBuilder {
392
  NodeBuilder *EnclosingBldr;
393
 
394
public:
395
  /// Constructs a StmtNodeBuilder. If the builder is going to process
396
  /// nodes currently owned by another builder(with larger scope), use
397
  /// Enclosing builder to transfer ownership.
398
  StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
399
                  const NodeBuilderContext &Ctx,
400
                  NodeBuilder *Enclosing = nullptr)
401
      : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
402
    if (EnclosingBldr)
403
      EnclosingBldr->takeNodes(SrcNode);
404
  }
405
 
406
  StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
407
                  const NodeBuilderContext &Ctx,
408
                  NodeBuilder *Enclosing = nullptr)
409
      : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
410
    if (EnclosingBldr)
411
      for (const auto I : SrcSet)
412
        EnclosingBldr->takeNodes(I);
413
  }
414
 
415
  ~StmtNodeBuilder() override;
416
 
417
  using NodeBuilder::generateNode;
418
  using NodeBuilder::generateSink;
419
 
420
  ExplodedNode *generateNode(const Stmt *S,
421
                             ExplodedNode *Pred,
422
                             ProgramStateRef St,
423
                             const ProgramPointTag *tag = nullptr,
424
                             ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
425
    const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
426
                                  Pred->getLocationContext(), tag);
427
    return NodeBuilder::generateNode(L, St, Pred);
428
  }
429
 
430
  ExplodedNode *generateSink(const Stmt *S,
431
                             ExplodedNode *Pred,
432
                             ProgramStateRef St,
433
                             const ProgramPointTag *tag = nullptr,
434
                             ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
435
    const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
436
                                  Pred->getLocationContext(), tag);
437
    return NodeBuilder::generateSink(L, St, Pred);
438
  }
439
};
440
 
441
/// BranchNodeBuilder is responsible for constructing the nodes
442
/// corresponding to the two branches of the if statement - true and false.
443
class BranchNodeBuilder: public NodeBuilder {
444
  const CFGBlock *DstT;
445
  const CFGBlock *DstF;
446
 
447
  bool InFeasibleTrue;
448
  bool InFeasibleFalse;
449
 
450
  void anchor() override;
451
 
452
public:
453
  BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
454
                    const NodeBuilderContext &C,
455
                    const CFGBlock *dstT, const CFGBlock *dstF)
456
      : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
457
        InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
458
    // The branch node builder does not generate autotransitions.
459
    // If there are no successors it means that both branches are infeasible.
460
    takeNodes(SrcNode);
461
  }
462
 
463
  BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
464
                    const NodeBuilderContext &C,
465
                    const CFGBlock *dstT, const CFGBlock *dstF)
466
      : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
467
        InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
468
    takeNodes(SrcSet);
469
  }
470
 
471
  ExplodedNode *generateNode(ProgramStateRef State, bool branch,
472
                             ExplodedNode *Pred);
473
 
474
  const CFGBlock *getTargetBlock(bool branch) const {
475
    return branch ? DstT : DstF;
476
  }
477
 
478
  void markInfeasible(bool branch) {
479
    if (branch)
480
      InFeasibleTrue = true;
481
    else
482
      InFeasibleFalse = true;
483
  }
484
 
485
  bool isFeasible(bool branch) {
486
    return branch ? !InFeasibleTrue : !InFeasibleFalse;
487
  }
488
};
489
 
490
class IndirectGotoNodeBuilder {
491
  CoreEngine& Eng;
492
  const CFGBlock *Src;
493
  const CFGBlock &DispatchBlock;
494
  const Expr *E;
495
  ExplodedNode *Pred;
496
 
497
public:
498
  IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
499
                    const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
500
      : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
501
 
502
  class iterator {
503
    friend class IndirectGotoNodeBuilder;
504
 
505
    CFGBlock::const_succ_iterator I;
506
 
507
    iterator(CFGBlock::const_succ_iterator i) : I(i) {}
508
 
509
  public:
510
    iterator &operator++() { ++I; return *this; }
511
    bool operator!=(const iterator &X) const { return I != X.I; }
512
 
513
    const LabelDecl *getLabel() const {
514
      return cast<LabelStmt>((*I)->getLabel())->getDecl();
515
    }
516
 
517
    const CFGBlock *getBlock() const {
518
      return *I;
519
    }
520
  };
521
 
522
  iterator begin() { return iterator(DispatchBlock.succ_begin()); }
523
  iterator end() { return iterator(DispatchBlock.succ_end()); }
524
 
525
  ExplodedNode *generateNode(const iterator &I,
526
                             ProgramStateRef State,
527
                             bool isSink = false);
528
 
529
  const Expr *getTarget() const { return E; }
530
 
531
  ProgramStateRef getState() const { return Pred->State; }
532
 
533
  const LocationContext *getLocationContext() const {
534
    return Pred->getLocationContext();
535
  }
536
};
537
 
538
class SwitchNodeBuilder {
539
  CoreEngine& Eng;
540
  const CFGBlock *Src;
541
  const Expr *Condition;
542
  ExplodedNode *Pred;
543
 
544
public:
545
  SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
546
                    const Expr *condition, CoreEngine* eng)
547
      : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
548
 
549
  class iterator {
550
    friend class SwitchNodeBuilder;
551
 
552
    CFGBlock::const_succ_reverse_iterator I;
553
 
554
    iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
555
 
556
  public:
557
    iterator &operator++() { ++I; return *this; }
558
    bool operator!=(const iterator &X) const { return I != X.I; }
559
    bool operator==(const iterator &X) const { return I == X.I; }
560
 
561
    const CaseStmt *getCase() const {
562
      return cast<CaseStmt>((*I)->getLabel());
563
    }
564
 
565
    const CFGBlock *getBlock() const {
566
      return *I;
567
    }
568
  };
569
 
570
  iterator begin() { return iterator(Src->succ_rbegin()+1); }
571
  iterator end() { return iterator(Src->succ_rend()); }
572
 
573
  const SwitchStmt *getSwitch() const {
574
    return cast<SwitchStmt>(Src->getTerminator());
575
  }
576
 
577
  ExplodedNode *generateCaseStmtNode(const iterator &I,
578
                                     ProgramStateRef State);
579
 
580
  ExplodedNode *generateDefaultCaseNode(ProgramStateRef State,
581
                                        bool isSink = false);
582
 
583
  const Expr *getCondition() const { return Condition; }
584
 
585
  ProgramStateRef getState() const { return Pred->State; }
586
 
587
  const LocationContext *getLocationContext() const {
588
    return Pred->getLocationContext();
589
  }
590
};
591
 
592
} // namespace ento
593
 
594
} // namespace clang
595
 
596
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H