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
//===-- DataflowEnvironment.h -----------------------------------*- 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 an Environment class that is used by dataflow analyses
10
//  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
11
//  program at given program points.
12
//
13
//===----------------------------------------------------------------------===//
14
 
15
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
16
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
17
 
18
#include "clang/AST/Decl.h"
19
#include "clang/AST/DeclBase.h"
20
#include "clang/AST/Expr.h"
21
#include "clang/AST/Type.h"
22
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
23
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
24
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
25
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
26
#include "clang/Analysis/FlowSensitive/Value.h"
27
#include "llvm/ADT/DenseMap.h"
28
#include "llvm/ADT/DenseSet.h"
29
#include "llvm/Support/ErrorHandling.h"
30
#include <memory>
31
#include <type_traits>
32
#include <utility>
33
 
34
namespace clang {
35
namespace dataflow {
36
 
37
/// Indicates what kind of indirections should be skipped past when retrieving
38
/// storage locations or values.
39
///
40
/// FIXME: Consider renaming this or replacing it with a more appropriate model.
41
/// See the discussion in https://reviews.llvm.org/D116596 for context.
42
enum class SkipPast {
43
  /// No indirections should be skipped past.
44
  None,
45
  /// An optional reference should be skipped past.
46
  Reference,
47
  /// An optional reference should be skipped past, then an optional pointer
48
  /// should be skipped past.
49
  ReferenceThenPointer,
50
};
51
 
52
/// Indicates the result of a tentative comparison.
53
enum class ComparisonResult {
54
  Same,
55
  Different,
56
  Unknown,
57
};
58
 
59
/// Holds the state of the program (store and heap) at a given program point.
60
///
61
/// WARNING: Symbolic values that are created by the environment for static
62
/// local and global variables are not currently invalidated on function calls.
63
/// This is unsound and should be taken into account when designing dataflow
64
/// analyses.
65
class Environment {
66
public:
67
  /// Supplements `Environment` with non-standard comparison and join
68
  /// operations.
69
  class ValueModel {
70
  public:
71
    virtual ~ValueModel() = default;
72
 
73
    /// Returns:
74
    ///   `Same`: `Val1` is equivalent to `Val2`, according to the model.
75
    ///   `Different`: `Val1` is distinct from `Val2`, according to the model.
76
    ///   `Unknown`: The model can't determine a relationship between `Val1` and
77
    ///    `Val2`.
78
    ///
79
    /// Requirements:
80
    ///
81
    ///  `Val1` and `Val2` must be distinct.
82
    ///
83
    ///  `Val1` and `Val2` must model values of type `Type`.
84
    ///
85
    ///  `Val1` and `Val2` must be assigned to the same storage location in
86
    ///  `Env1` and `Env2` respectively.
87
    virtual ComparisonResult compare(QualType Type, const Value &Val1,
88
                                     const Environment &Env1, const Value &Val2,
89
                                     const Environment &Env2) {
90
      // FIXME: Consider adding QualType to StructValue and removing the Type
91
      // argument here.
92
      return ComparisonResult::Unknown;
93
    }
94
 
95
    /// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could
96
    /// be a strict lattice join or a more general widening operation.
97
    ///
98
    /// If this function returns true, `MergedVal` will be assigned to a storage
99
    /// location of type `Type` in `MergedEnv`.
100
    ///
101
    /// `Env1` and `Env2` can be used to query child values and path condition
102
    /// implications of `Val1` and `Val2` respectively.
103
    ///
104
    /// Requirements:
105
    ///
106
    ///  `Val1` and `Val2` must be distinct.
107
    ///
108
    ///  `Val1`, `Val2`, and `MergedVal` must model values of type `Type`.
109
    ///
110
    ///  `Val1` and `Val2` must be assigned to the same storage location in
111
    ///  `Env1` and `Env2` respectively.
112
    virtual bool merge(QualType Type, const Value &Val1,
113
                       const Environment &Env1, const Value &Val2,
114
                       const Environment &Env2, Value &MergedVal,
115
                       Environment &MergedEnv) {
116
      return true;
117
    }
118
 
119
    /// This function may widen the current value -- replace it with an
120
    /// approximation that can reach a fixed point more quickly than iterated
121
    /// application of the transfer function alone. The previous value is
122
    /// provided to inform the choice of widened value. The function must also
123
    /// serve as a comparison operation, by indicating whether the widened value
124
    /// is equivalent to the previous value.
125
    ///
126
    /// Returns either:
127
    ///
128
    ///   `nullptr`, if this value is not of interest to the model, or
129
    ///
130
    ///   `&Prev`, if the widened value is equivalent to `Prev`, or
131
    ///
132
    ///   A non-null value that approximates `Current`. `Prev` is available to
133
    ///   inform the chosen approximation.
134
    ///
135
    /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
136
    /// condition implications of `Prev` and `Current`, respectively.
137
    ///
138
    /// Requirements:
139
    ///
140
    ///  `Prev` and `Current` must model values of type `Type`.
141
    ///
142
    ///  `Prev` and `Current` must be assigned to the same storage location in
143
    ///  `PrevEnv` and `CurrentEnv`, respectively.
144
    virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv,
145
                         Value &Current, Environment &CurrentEnv) {
146
      // The default implementation reduces to just comparison, since comparison
147
      // is required by the API, even if no widening is performed.
148
      switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
149
        case ComparisonResult::Same:
150
          return &Prev;
151
        case ComparisonResult::Different:
152
          return &Current;
153
        case ComparisonResult::Unknown:
154
          return nullptr;
155
      }
156
      llvm_unreachable("all cases in switch covered");
157
    }
158
  };
159
 
160
  /// Creates an environment that uses `DACtx` to store objects that encompass
161
  /// the state of a program.
162
  explicit Environment(DataflowAnalysisContext &DACtx);
163
 
164
  Environment(const Environment &Other);
165
  Environment &operator=(const Environment &Other);
166
 
167
  Environment(Environment &&Other) = default;
168
  Environment &operator=(Environment &&Other) = default;
169
 
170
  /// Creates an environment that uses `DACtx` to store objects that encompass
171
  /// the state of a program.
172
  ///
173
  /// If `DeclCtx` is a function, initializes the environment with symbolic
174
  /// representations of the function parameters.
175
  ///
176
  /// If `DeclCtx` is a non-static member function, initializes the environment
177
  /// with a symbolic representation of the `this` pointee.
178
  Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
179
 
180
  const DataflowAnalysisContext::Options &getAnalysisOptions() {
181
    return DACtx->getOptions();
182
  }
183
 
184
  /// Creates and returns an environment to use for an inline analysis  of the
185
  /// callee. Uses the storage location from each argument in the `Call` as the
186
  /// storage location for the corresponding parameter in the callee.
187
  ///
188
  /// Requirements:
189
  ///
190
  ///  The callee of `Call` must be a `FunctionDecl`.
191
  ///
192
  ///  The body of the callee must not reference globals.
193
  ///
194
  ///  The arguments of `Call` must map 1:1 to the callee's parameters.
195
  Environment pushCall(const CallExpr *Call) const;
196
  Environment pushCall(const CXXConstructExpr *Call) const;
197
 
198
  /// Moves gathered information back into `this` from a `CalleeEnv` created via
199
  /// `pushCall`.
200
  void popCall(const Environment &CalleeEnv);
201
 
202
  /// Returns true if and only if the environment is equivalent to `Other`, i.e
203
  /// the two environments:
204
  ///  - have the same mappings from declarations to storage locations,
205
  ///  - have the same mappings from expressions to storage locations,
206
  ///  - have the same or equivalent (according to `Model`) values assigned to
207
  ///    the same storage locations.
208
  ///
209
  /// Requirements:
210
  ///
211
  ///  `Other` and `this` must use the same `DataflowAnalysisContext`.
212
  bool equivalentTo(const Environment &Other,
213
                    Environment::ValueModel &Model) const;
214
 
215
  /// Joins the environment with `Other` by taking the intersection of storage
216
  /// locations and values that are stored in them. Distinct values that are
217
  /// assigned to the same storage locations in the environment and `Other` are
218
  /// merged using `Model`.
219
  ///
220
  /// Requirements:
221
  ///
222
  ///  `Other` and `this` must use the same `DataflowAnalysisContext`.
223
  LatticeJoinEffect join(const Environment &Other,
224
                         Environment::ValueModel &Model);
225
 
226
 
227
  /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
228
  /// approximation.
229
  ///
230
  /// Requirements:
231
  ///
232
  ///  `PrevEnv` must be the immediate previous version of the environment.
233
  ///  `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
234
  LatticeJoinEffect widen(const Environment &PrevEnv,
235
                          Environment::ValueModel &Model);
236
 
237
  // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
238
  // `getStableStorageLocation`, or something more appropriate.
239
 
240
  /// Creates a storage location appropriate for `Type`. Does not assign a value
241
  /// to the returned storage location in the environment.
242
  ///
243
  /// Requirements:
244
  ///
245
  ///  `Type` must not be null.
246
  StorageLocation &createStorageLocation(QualType Type);
247
 
248
  /// Creates a storage location for `D`. Does not assign the returned storage
249
  /// location to `D` in the environment. Does not assign a value to the
250
  /// returned storage location in the environment.
251
  StorageLocation &createStorageLocation(const VarDecl &D);
252
 
253
  /// Creates a storage location for `E`. Does not assign the returned storage
254
  /// location to `E` in the environment. Does not assign a value to the
255
  /// returned storage location in the environment.
256
  StorageLocation &createStorageLocation(const Expr &E);
257
 
258
  /// Assigns `Loc` as the storage location of `D` in the environment.
259
  ///
260
  /// Requirements:
261
  ///
262
  ///  `D` must not be assigned a storage location in the environment.
263
  void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
264
 
265
  /// Returns the storage location assigned to `D` in the environment, applying
266
  /// the `SP` policy for skipping past indirections, or null if `D` isn't
267
  /// assigned a storage location in the environment.
268
  StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const;
269
 
270
  /// Assigns `Loc` as the storage location of `E` in the environment.
271
  ///
272
  /// Requirements:
273
  ///
274
  ///  `E` must not be assigned a storage location in the environment.
275
  void setStorageLocation(const Expr &E, StorageLocation &Loc);
276
 
277
  /// Returns the storage location assigned to `E` in the environment, applying
278
  /// the `SP` policy for skipping past indirections, or null if `E` isn't
279
  /// assigned a storage location in the environment.
280
  StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const;
281
 
282
  /// Returns the storage location assigned to the `this` pointee in the
283
  /// environment or null if the `this` pointee has no assigned storage location
284
  /// in the environment.
285
  StorageLocation *getThisPointeeStorageLocation() const;
286
 
287
  /// Returns the storage location of the return value or null, if unset.
288
  StorageLocation *getReturnStorageLocation() const;
289
 
290
  /// Returns a pointer value that represents a null pointer. Calls with
291
  /// `PointeeType` that are canonically equivalent will return the same result.
292
  PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
293
 
294
  /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
295
  /// return null. If `Type` is a pointer or reference type, creates all the
296
  /// necessary storage locations and values for indirections until it finds a
297
  /// non-pointer/non-reference type.
298
  ///
299
  /// Requirements:
300
  ///
301
  ///  `Type` must not be null.
302
  Value *createValue(QualType Type);
303
 
304
  /// Assigns `Val` as the value of `Loc` in the environment.
305
  void setValue(const StorageLocation &Loc, Value &Val);
306
 
307
  /// Returns the value assigned to `Loc` in the environment or null if `Loc`
308
  /// isn't assigned a value in the environment.
309
  Value *getValue(const StorageLocation &Loc) const;
310
 
311
  /// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D`
312
  /// is assigned a storage location in the environment, otherwise returns null.
313
  Value *getValue(const ValueDecl &D, SkipPast SP) const;
314
 
315
  /// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E`
316
  /// is assigned a storage location in the environment, otherwise returns null.
317
  Value *getValue(const Expr &E, SkipPast SP) const;
318
 
319
  /// Transfers ownership of `Loc` to the analysis context and returns a
320
  /// reference to it.
321
  ///
322
  /// Requirements:
323
  ///
324
  ///  `Loc` must not be null.
325
  template <typename T>
326
  std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
327
  takeOwnership(std::unique_ptr<T> Loc) {
328
    return DACtx->takeOwnership(std::move(Loc));
329
  }
330
 
331
  /// Transfers ownership of `Val` to the analysis context and returns a
332
  /// reference to it.
333
  ///
334
  /// Requirements:
335
  ///
336
  ///  `Val` must not be null.
337
  template <typename T>
338
  std::enable_if_t<std::is_base_of<Value, T>::value, T &>
339
  takeOwnership(std::unique_ptr<T> Val) {
340
    return DACtx->takeOwnership(std::move(Val));
341
  }
342
 
343
  /// Returns a symbolic boolean value that models a boolean literal equal to
344
  /// `Value`
345
  AtomicBoolValue &getBoolLiteralValue(bool Value) const {
346
    return DACtx->getBoolLiteralValue(Value);
347
  }
348
 
349
  /// Returns an atomic boolean value.
350
  BoolValue &makeAtomicBoolValue() const {
351
    return DACtx->createAtomicBoolValue();
352
  }
353
 
354
  /// Returns a unique instance of boolean Top.
355
  BoolValue &makeTopBoolValue() const {
356
    return DACtx->createTopBoolValue();
357
  }
358
 
359
  /// Returns a boolean value that represents the conjunction of `LHS` and
360
  /// `RHS`. Subsequent calls with the same arguments, regardless of their
361
  /// order, will return the same result. If the given boolean values represent
362
  /// the same value, the result will be the value itself.
363
  BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const {
364
    return DACtx->getOrCreateConjunction(LHS, RHS);
365
  }
366
 
367
  /// Returns a boolean value that represents the disjunction of `LHS` and
368
  /// `RHS`. Subsequent calls with the same arguments, regardless of their
369
  /// order, will return the same result. If the given boolean values represent
370
  /// the same value, the result will be the value itself.
371
  BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
372
    return DACtx->getOrCreateDisjunction(LHS, RHS);
373
  }
374
 
375
  /// Returns a boolean value that represents the negation of `Val`. Subsequent
376
  /// calls with the same argument will return the same result.
377
  BoolValue &makeNot(BoolValue &Val) const {
378
    return DACtx->getOrCreateNegation(Val);
379
  }
380
 
381
  /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
382
  /// the same arguments, will return the same result. If the given boolean
383
  /// values represent the same value, the result will be a value that
384
  /// represents the true boolean literal.
385
  BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const {
386
    return DACtx->getOrCreateImplication(LHS, RHS);
387
  }
388
 
389
  /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
390
  /// the same arguments, regardless of their order, will return the same
391
  /// result. If the given boolean values represent the same value, the result
392
  /// will be a value that represents the true boolean literal.
393
  BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const {
394
    return DACtx->getOrCreateIff(LHS, RHS);
395
  }
396
 
397
  /// Returns the token that identifies the flow condition of the environment.
398
  AtomicBoolValue &getFlowConditionToken() const { return *FlowConditionToken; }
399
 
400
  /// Builds and returns the logical formula defining the flow condition
401
  /// identified by `Token`. If a value in the formula is present as a key in
402
  /// `Substitutions`, it will be substituted with the value it maps to.
403
  BoolValue &buildAndSubstituteFlowCondition(
404
      AtomicBoolValue &Token,
405
      llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) {
406
    return DACtx->buildAndSubstituteFlowCondition(Token,
407
                                                  std::move(Substitutions));
408
  }
409
 
410
  /// Adds `Val` to the set of clauses that constitute the flow condition.
411
  void addToFlowCondition(BoolValue &Val);
412
 
413
  /// Returns true if and only if the clauses that constitute the flow condition
414
  /// imply that `Val` is true.
415
  bool flowConditionImplies(BoolValue &Val) const;
416
 
417
  /// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
418
  /// returns null.
419
  const DeclContext *getDeclCtx() const { return CallStack.back(); }
420
 
421
  /// Returns whether this `Environment` can be extended to analyze the given
422
  /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
423
  /// given `MaxDepth`.
424
  bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
425
 
426
  /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
427
  /// returns null.
428
  const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) {
429
    return DACtx->getControlFlowContext(F);
430
  }
431
 
432
  LLVM_DUMP_METHOD void dump() const;
433
  LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
434
 
435
private:
436
  /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
437
  /// return null.
438
  ///
439
  /// Recursively initializes storage locations and values until it sees a
440
  /// self-referential pointer or reference type. `Visited` is used to track
441
  /// which types appeared in the reference/pointer chain in order to avoid
442
  /// creating a cyclic dependency with self-referential pointers/references.
443
  ///
444
  /// Requirements:
445
  ///
446
  ///  `Type` must not be null.
447
  Value *createValueUnlessSelfReferential(QualType Type,
448
                                          llvm::DenseSet<QualType> &Visited,
449
                                          int Depth, int &CreatedValuesCount);
450
 
451
  StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const;
452
  const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const;
453
 
454
  /// Shared implementation of `pushCall` overloads. Note that unlike
455
  /// `pushCall`, this member is invoked on the environment of the callee, not
456
  /// of the caller.
457
  void pushCallInternal(const FunctionDecl *FuncDecl,
458
                        ArrayRef<const Expr *> Args);
459
 
460
  /// Assigns storage locations and values to all variables in `Vars`.
461
  void initVars(llvm::DenseSet<const VarDecl *> Vars);
462
 
463
  // `DACtx` is not null and not owned by this object.
464
  DataflowAnalysisContext *DACtx;
465
 
466
 
467
  // FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into a
468
  // separate call-context object, shared between environments in the same call.
469
  // https://github.com/llvm/llvm-project/issues/59005
470
 
471
  // `DeclContext` of the block being analysed if provided.
472
  std::vector<const DeclContext *> CallStack;
473
 
474
  // In a properly initialized `Environment`, `ReturnLoc` should only be null if
475
  // its `DeclContext` could not be cast to a `FunctionDecl`.
476
  StorageLocation *ReturnLoc = nullptr;
477
  // The storage location of the `this` pointee. Should only be null if the
478
  // function being analyzed is only a function and not a method.
479
  StorageLocation *ThisPointeeLoc = nullptr;
480
 
481
  // Maps from program declarations and statements to storage locations that are
482
  // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
483
  // include only storage locations that are in scope for a particular basic
484
  // block.
485
  llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
486
  llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
487
 
488
  llvm::DenseMap<const StorageLocation *, Value *> LocToVal;
489
 
490
  // Maps locations of struct members to symbolic values of the structs that own
491
  // them and the decls of the struct members.
492
  llvm::DenseMap<const StorageLocation *,
493
                 std::pair<StructValue *, const ValueDecl *>>
494
      MemberLocToStruct;
495
 
496
  AtomicBoolValue *FlowConditionToken;
497
};
498
 
499
} // namespace dataflow
500
} // namespace clang
501
 
502
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H