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
//== CheckerContext.h - Context info for path-sensitive checkers--*- 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 CheckerContext that provides contextual info for
10
// path-sensitive checkers.
11
//
12
//===----------------------------------------------------------------------===//
13
 
14
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
15
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CHECKERCONTEXT_H
16
 
17
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
18
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
19
#include <optional>
20
 
21
namespace clang {
22
namespace ento {
23
 
24
class CheckerContext {
25
  ExprEngine &Eng;
26
  /// The current exploded(symbolic execution) graph node.
27
  ExplodedNode *Pred;
28
  /// The flag is true if the (state of the execution) has been modified
29
  /// by the checker using this context. For example, a new transition has been
30
  /// added or a bug report issued.
31
  bool Changed;
32
  /// The tagged location, which is used to generate all new nodes.
33
  const ProgramPoint Location;
34
  NodeBuilder &NB;
35
 
36
public:
37
  /// If we are post visiting a call, this flag will be set if the
38
  /// call was inlined.  In all other cases it will be false.
39
  const bool wasInlined;
40
 
41
  CheckerContext(NodeBuilder &builder,
42
                 ExprEngine &eng,
43
                 ExplodedNode *pred,
44
                 const ProgramPoint &loc,
45
                 bool wasInlined = false)
46
    : Eng(eng),
47
      Pred(pred),
48
      Changed(false),
49
      Location(loc),
50
      NB(builder),
51
      wasInlined(wasInlined) {
52
    assert(Pred->getState() &&
53
           "We should not call the checkers on an empty state.");
54
  }
55
 
56
  AnalysisManager &getAnalysisManager() {
57
    return Eng.getAnalysisManager();
58
  }
59
 
60
  ConstraintManager &getConstraintManager() {
61
    return Eng.getConstraintManager();
62
  }
63
 
64
  StoreManager &getStoreManager() {
65
    return Eng.getStoreManager();
66
  }
67
 
68
  /// Returns the previous node in the exploded graph, which includes
69
  /// the state of the program before the checker ran. Note, checkers should
70
  /// not retain the node in their state since the nodes might get invalidated.
71
  ExplodedNode *getPredecessor() { return Pred; }
72
  const ProgramStateRef &getState() const { return Pred->getState(); }
73
 
74
  /// Check if the checker changed the state of the execution; ex: added
75
  /// a new transition or a bug report.
76
  bool isDifferent() { return Changed; }
77
 
78
  /// Returns the number of times the current block has been visited
79
  /// along the analyzed path.
80
  unsigned blockCount() const {
81
    return NB.getContext().blockCount();
82
  }
83
 
84
  ASTContext &getASTContext() {
85
    return Eng.getContext();
86
  }
87
 
88
  const ASTContext &getASTContext() const { return Eng.getContext(); }
89
 
90
  const LangOptions &getLangOpts() const {
91
    return Eng.getContext().getLangOpts();
92
  }
93
 
94
  const LocationContext *getLocationContext() const {
95
    return Pred->getLocationContext();
96
  }
97
 
98
  const StackFrameContext *getStackFrame() const {
99
    return Pred->getStackFrame();
100
  }
101
 
102
  /// Return true if the current LocationContext has no caller context.
103
  bool inTopFrame() const { return getLocationContext()->inTopFrame();  }
104
 
105
  BugReporter &getBugReporter() {
106
    return Eng.getBugReporter();
107
  }
108
 
109
  const SourceManager &getSourceManager() {
110
    return getBugReporter().getSourceManager();
111
  }
112
 
113
  Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); }
114
 
115
  SValBuilder &getSValBuilder() {
116
    return Eng.getSValBuilder();
117
  }
118
 
119
  SymbolManager &getSymbolManager() {
120
    return getSValBuilder().getSymbolManager();
121
  }
122
 
123
  ProgramStateManager &getStateManager() {
124
    return Eng.getStateManager();
125
  }
126
 
127
  AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
128
    return Pred->getLocationContext()->getAnalysisDeclContext();
129
  }
130
 
131
  /// Get the blockID.
132
  unsigned getBlockID() const {
133
    return NB.getContext().getBlock()->getBlockID();
134
  }
135
 
136
  /// If the given node corresponds to a PostStore program point,
137
  /// retrieve the location region as it was uttered in the code.
138
  ///
139
  /// This utility can be useful for generating extensive diagnostics, for
140
  /// example, for finding variables that the given symbol was assigned to.
141
  static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
142
    ProgramPoint L = N->getLocation();
143
    if (std::optional<PostStore> PSL = L.getAs<PostStore>())
144
      return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
145
    return nullptr;
146
  }
147
 
148
  /// Get the value of arbitrary expressions at this point in the path.
149
  SVal getSVal(const Stmt *S) const {
150
    return Pred->getSVal(S);
151
  }
152
 
153
  /// Returns true if the value of \p E is greater than or equal to \p
154
  /// Val under unsigned comparison
155
  bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
156
 
157
  /// Returns true if the value of \p E is negative.
158
  bool isNegative(const Expr *E);
159
 
160
  /// Generates a new transition in the program state graph
161
  /// (ExplodedGraph). Uses the default CheckerContext predecessor node.
162
  ///
163
  /// @param State The state of the generated node. If not specified, the state
164
  ///        will not be changed, but the new node will have the checker's tag.
165
  /// @param Tag The tag is used to uniquely identify the creation site. If no
166
  ///        tag is specified, a default tag, unique to the given checker,
167
  ///        will be used. Tags are used to prevent states generated at
168
  ///        different sites from caching out.
169
  ExplodedNode *addTransition(ProgramStateRef State = nullptr,
170
                              const ProgramPointTag *Tag = nullptr) {
171
    return addTransitionImpl(State ? State : getState(), false, nullptr, Tag);
172
  }
173
 
174
  /// Generates a new transition with the given predecessor.
175
  /// Allows checkers to generate a chain of nodes.
176
  ///
177
  /// @param State The state of the generated node.
178
  /// @param Pred The transition will be generated from the specified Pred node
179
  ///             to the newly generated node.
180
  /// @param Tag The tag to uniquely identify the creation site.
181
  ExplodedNode *addTransition(ProgramStateRef State, ExplodedNode *Pred,
182
                              const ProgramPointTag *Tag = nullptr) {
183
    return addTransitionImpl(State, false, Pred, Tag);
184
  }
185
 
186
  /// Generate a sink node. Generating a sink stops exploration of the
187
  /// given path. To create a sink node for the purpose of reporting an error,
188
  /// checkers should use generateErrorNode() instead.
189
  ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
190
                             const ProgramPointTag *Tag = nullptr) {
191
    return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
192
  }
193
 
194
  /// Add a sink node to the current path of execution, halting analysis.
195
  void addSink(ProgramStateRef State = nullptr,
196
               const ProgramPointTag *Tag = nullptr) {
197
    if (!State)
198
      State = getState();
199
    addTransition(State, generateSink(State, getPredecessor()));
200
  }
201
 
202
  /// Generate a transition to a node that will be used to report
203
  /// an error. This node will be a sink. That is, it will stop exploration of
204
  /// the given path.
205
  ///
206
  /// @param State The state of the generated node.
207
  /// @param Tag The tag to uniquely identify the creation site. If null,
208
  ///        the default tag for the checker will be used.
209
  ExplodedNode *generateErrorNode(ProgramStateRef State = nullptr,
210
                                  const ProgramPointTag *Tag = nullptr) {
211
    return generateSink(State, Pred,
212
                       (Tag ? Tag : Location.getTag()));
213
  }
214
 
215
  /// Generate a transition to a node that will be used to report
216
  /// an error. This node will be a sink. That is, it will stop exploration of
217
  /// the given path.
218
  ///
219
  /// @param State The state of the generated node.
220
  /// @param Pred The transition will be generated from the specified Pred node
221
  ///             to the newly generated node.
222
  /// @param Tag The tag to uniquely identify the creation site. If null,
223
  ///        the default tag for the checker will be used.
224
  ExplodedNode *generateErrorNode(ProgramStateRef State,
225
                                  ExplodedNode *Pred,
226
                                  const ProgramPointTag *Tag = nullptr) {
227
    return generateSink(State, Pred,
228
                       (Tag ? Tag : Location.getTag()));
229
  }
230
 
231
  /// Generate a transition to a node that will be used to report
232
  /// an error. This node will not be a sink. That is, exploration will
233
  /// continue along this path.
234
  ///
235
  /// @param State The state of the generated node.
236
  /// @param Tag The tag to uniquely identify the creation site. If null,
237
  ///        the default tag for the checker will be used.
238
  ExplodedNode *
239
  generateNonFatalErrorNode(ProgramStateRef State = nullptr,
240
                            const ProgramPointTag *Tag = nullptr) {
241
    return addTransition(State, (Tag ? Tag : Location.getTag()));
242
  }
243
 
244
  /// Generate a transition to a node that will be used to report
245
  /// an error. This node will not be a sink. That is, exploration will
246
  /// continue along this path.
247
  ///
248
  /// @param State The state of the generated node.
249
  /// @param Pred The transition will be generated from the specified Pred node
250
  ///             to the newly generated node.
251
  /// @param Tag The tag to uniquely identify the creation site. If null,
252
  ///        the default tag for the checker will be used.
253
  ExplodedNode *
254
  generateNonFatalErrorNode(ProgramStateRef State,
255
                            ExplodedNode *Pred,
256
                            const ProgramPointTag *Tag = nullptr) {
257
    return addTransition(State, Pred, (Tag ? Tag : Location.getTag()));
258
  }
259
 
260
  /// Emit the diagnostics report.
261
  void emitReport(std::unique_ptr<BugReport> R) {
262
    Changed = true;
263
    Eng.getBugReporter().emitReport(std::move(R));
264
  }
265
 
266
  /// Produce a program point tag that displays an additional path note
267
  /// to the user. This is a lightweight alternative to the
268
  /// BugReporterVisitor mechanism: instead of visiting the bug report
269
  /// node-by-node to restore the sequence of events that led to discovering
270
  /// a bug, you can add notes as you add your transitions.
271
  ///
272
  /// @param Cb Callback with 'BugReporterContext &, BugReport &' parameters.
273
  /// @param IsPrunable Whether the note is prunable. It allows BugReporter
274
  ///        to omit the note from the report if it would make the displayed
275
  ///        bug path significantly shorter.
276
  LLVM_ATTRIBUTE_RETURNS_NONNULL
277
  const NoteTag *getNoteTag(NoteTag::Callback &&Cb, bool IsPrunable = false) {
278
    return Eng.getDataTags().make<NoteTag>(std::move(Cb), IsPrunable);
279
  }
280
 
281
  /// A shorthand version of getNoteTag that doesn't require you to accept
282
  /// the 'BugReporterContext' argument when you don't need it.
283
  ///
284
  /// @param Cb Callback only with 'BugReport &' parameter.
285
  /// @param IsPrunable Whether the note is prunable. It allows BugReporter
286
  ///        to omit the note from the report if it would make the displayed
287
  ///        bug path significantly shorter.
288
  const NoteTag
289
  *getNoteTag(std::function<std::string(PathSensitiveBugReport &)> &&Cb,
290
              bool IsPrunable = false) {
291
    return getNoteTag(
292
        [Cb](BugReporterContext &,
293
             PathSensitiveBugReport &BR) { return Cb(BR); },
294
        IsPrunable);
295
  }
296
 
297
  /// A shorthand version of getNoteTag that doesn't require you to accept
298
  /// the arguments when you don't need it.
299
  ///
300
  /// @param Cb Callback without parameters.
301
  /// @param IsPrunable Whether the note is prunable. It allows BugReporter
302
  ///        to omit the note from the report if it would make the displayed
303
  ///        bug path significantly shorter.
304
  const NoteTag *getNoteTag(std::function<std::string()> &&Cb,
305
                            bool IsPrunable = false) {
306
    return getNoteTag([Cb](BugReporterContext &,
307
                           PathSensitiveBugReport &) { return Cb(); },
308
                      IsPrunable);
309
  }
310
 
311
  /// A shorthand version of getNoteTag that accepts a plain note.
312
  ///
313
  /// @param Note The note.
314
  /// @param IsPrunable Whether the note is prunable. It allows BugReporter
315
  ///        to omit the note from the report if it would make the displayed
316
  ///        bug path significantly shorter.
317
  const NoteTag *getNoteTag(StringRef Note, bool IsPrunable = false) {
318
    return getNoteTag(
319
        [Note](BugReporterContext &,
320
               PathSensitiveBugReport &) { return std::string(Note); },
321
        IsPrunable);
322
  }
323
 
324
  /// A shorthand version of getNoteTag that accepts a lambda with stream for
325
  /// note.
326
  ///
327
  /// @param Cb Callback with 'BugReport &' and 'llvm::raw_ostream &'.
328
  /// @param IsPrunable Whether the note is prunable. It allows BugReporter
329
  ///        to omit the note from the report if it would make the displayed
330
  ///        bug path significantly shorter.
331
  const NoteTag *getNoteTag(
332
      std::function<void(PathSensitiveBugReport &BR, llvm::raw_ostream &OS)> &&Cb,
333
      bool IsPrunable = false) {
334
    return getNoteTag(
335
        [Cb](PathSensitiveBugReport &BR) -> std::string {
336
          llvm::SmallString<128> Str;
337
          llvm::raw_svector_ostream OS(Str);
338
          Cb(BR, OS);
339
          return std::string(OS.str());
340
        },
341
        IsPrunable);
342
  }
343
 
344
  /// Returns the word that should be used to refer to the declaration
345
  /// in the report.
346
  StringRef getDeclDescription(const Decl *D);
347
 
348
  /// Get the declaration of the called function (path-sensitive).
349
  const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
350
 
351
  /// Get the name of the called function (path-sensitive).
352
  StringRef getCalleeName(const FunctionDecl *FunDecl) const;
353
 
354
  /// Get the identifier of the called function (path-sensitive).
355
  const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const {
356
    const FunctionDecl *FunDecl = getCalleeDecl(CE);
357
    if (FunDecl)
358
      return FunDecl->getIdentifier();
359
    else
360
      return nullptr;
361
  }
362
 
363
  /// Get the name of the called function (path-sensitive).
364
  StringRef getCalleeName(const CallExpr *CE) const {
365
    const FunctionDecl *FunDecl = getCalleeDecl(CE);
366
    return getCalleeName(FunDecl);
367
  }
368
 
369
  /// Returns true if the callee is an externally-visible function in the
370
  /// top-level namespace, such as \c malloc.
371
  ///
372
  /// If a name is provided, the function must additionally match the given
373
  /// name.
374
  ///
375
  /// Note that this deliberately excludes C++ library functions in the \c std
376
  /// namespace, but will include C library functions accessed through the
377
  /// \c std namespace. This also does not check if the function is declared
378
  /// as 'extern "C"', or if it uses C++ name mangling.
379
  static bool isCLibraryFunction(const FunctionDecl *FD,
380
                                 StringRef Name = StringRef());
381
 
382
  /// Depending on wither the location corresponds to a macro, return
383
  /// either the macro name or the token spelling.
384
  ///
385
  /// This could be useful when checkers' logic depends on whether a function
386
  /// is called with a given macro argument. For example:
387
  ///   s = socket(AF_INET,..)
388
  /// If AF_INET is a macro, the result should be treated as a source of taint.
389
  ///
390
  /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName().
391
  StringRef getMacroNameOrSpelling(SourceLocation &Loc);
392
 
393
private:
394
  ExplodedNode *addTransitionImpl(ProgramStateRef State,
395
                                 bool MarkAsSink,
396
                                 ExplodedNode *P = nullptr,
397
                                 const ProgramPointTag *Tag = nullptr) {
398
    // The analyzer may stop exploring if it sees a state it has previously
399
    // visited ("cache out"). The early return here is a defensive check to
400
    // prevent accidental caching out by checker API clients. Unless there is a
401
    // tag or the client checker has requested that the generated node be
402
    // marked as a sink, we assume that a client requesting a transition to a
403
    // state that is the same as the predecessor state has made a mistake. We
404
    // return the predecessor rather than cache out.
405
    //
406
    // TODO: We could potentially change the return to an assertion to alert
407
    // clients to their mistake, but several checkers (including
408
    // DereferenceChecker, CallAndMessageChecker, and DynamicTypePropagation)
409
    // rely upon the defensive behavior and would need to be updated.
410
    if (!State || (State == Pred->getState() && !Tag && !MarkAsSink))
411
      return Pred;
412
 
413
    Changed = true;
414
    const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
415
    if (!P)
416
      P = Pred;
417
 
418
    ExplodedNode *node;
419
    if (MarkAsSink)
420
      node = NB.generateSink(LocalLoc, State, P);
421
    else
422
      node = NB.generateNode(LocalLoc, State, P);
423
    return node;
424
  }
425
};
426
 
427
} // end GR namespace
428
 
429
} // end clang namespace
430
 
431
#endif