@@ -326,6 +326,10 @@ class LocAsInteger : public NonLoc {
326
326
static bool classof (SVal V) { return V.getKind () == LocAsIntegerKind; }
327
327
};
328
328
329
+ // / The simplest example of a concrete compound value is nonloc::CompoundVal,
330
+ // / which represents a concrete r-value of an initializer-list or a string.
331
+ // / Internally, it contains an llvm::ImmutableList of SVal's stored inside the
332
+ // / literal.
329
333
class CompoundVal : public NonLoc {
330
334
friend class ento ::SValBuilder;
331
335
@@ -346,6 +350,36 @@ class CompoundVal : public NonLoc {
346
350
static bool classof (SVal V) { return V.getKind () == CompoundValKind; }
347
351
};
348
352
353
+ // / While nonloc::CompoundVal covers a few simple use cases,
354
+ // / nonloc::LazyCompoundVal is a more performant and flexible way to represent
355
+ // / an rvalue of record type, so it shows up much more frequently during
356
+ // / analysis. This value is an r-value that represents a snapshot of any
357
+ // / structure "as a whole" at a given moment during the analysis. Such value is
358
+ // / already quite far from being referred to as "concrete", as many fields
359
+ // / inside it would be unknown or symbolic. nonloc::LazyCompoundVal operates by
360
+ // / storing two things:
361
+ // / * a reference to the TypedValueRegion being snapshotted (yes, it is always
362
+ // / typed), and also
363
+ // / * a reference to the whole Store object, obtained from the ProgramState in
364
+ // / which the nonloc::LazyCompoundVal was created.
365
+ // /
366
+ // / Note that the old ProgramState and its Store is kept alive during the
367
+ // / analysis because these are immutable functional data structures and each new
368
+ // / Store value is represented as "earlier Store" + "additional binding".
369
+ // /
370
+ // / Essentially, nonloc::LazyCompoundVal is a performance optimization for the
371
+ // / analyzer. Because Store is immutable, creating a nonloc::LazyCompoundVal is
372
+ // / a very cheap operation. Note that the Store contains all region bindings in
373
+ // / the program state, not only related to the region. Later, if necessary, such
374
+ // / value can be unpacked -- eg. when it is assigned to another variable.
375
+ // /
376
+ // / If you ever need to inspect the contents of the LazyCompoundVal, you can use
377
+ // / StoreManager::iterBindings(). It'll iterate through all values in the Store,
378
+ // / but you're only interested in the ones that belong to
379
+ // / LazyCompoundVal::getRegion(); other bindings are immaterial.
380
+ // /
381
+ // / NOTE: LazyCompoundVal::getRegion() itself is also immaterial (see the actual
382
+ // / method docs for details).
349
383
class LazyCompoundVal : public NonLoc {
350
384
friend class ento ::SValBuilder;
351
385
@@ -363,6 +397,18 @@ class LazyCompoundVal : public NonLoc {
363
397
// / It might return null.
364
398
const void *getStore () const ;
365
399
400
+ // / This function itself is immaterial. It is only an implementation detail.
401
+ // / LazyCompoundVal represents only the rvalue, the data (known or unknown)
402
+ // / that *was* stored in that region *at some point in the past*. The region
403
+ // / should not be used for any purpose other than figuring out what part of
404
+ // / the frozen Store you're interested in. The value does not represent the
405
+ // / *current* value of that region. Sometimes it may, but this should not be
406
+ // / relied upon. Instead, if you want to figure out what region it represents,
407
+ // / you typically need to see where you got it from in the first place. The
408
+ // / region is absolutely not analogous to the C++ "this" pointer. It is also
409
+ // / not a valid way to "materialize" the prvalue into a glvalue in C++,
410
+ // / because the region represents the *old* storage (sometimes very old), not
411
+ // / the *future* storage.
366
412
LLVM_ATTRIBUTE_RETURNS_NONNULL
367
413
const TypedValueRegion *getRegion () const ;
368
414
0 commit comments