ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
value_sett Class Reference

#include <value_set.h>

Classes

class  objectt
 Record for an object reference. More...
class  object_map_dt
struct  entryt
 Record for a particular value set: stores the identity of the variable that points at this set of objects, and the objects themselves (with associated offset data). More...

Public Types

typedef std::set< expr2tc > expr_sett
 A type for a set of expressions.
typedef std::unordered_map< unsigned, objectt > object_mapt
 Datatype for a value set: stores a mapping between some integers and additional reference data in an objectt object.
typedef persistent_map< irep_idt, entryt, irep_id_hash > valuest
 Maps each variable to the entryt holding the set of objects it may point at.

Public Member Functions

 value_sett (const namespacet &_ns)
 Primary constructor.
 value_sett (const value_sett &ref)
value_sett & operator= (const value_sett &ref)
unsigned int get_natural_alignment (const expr2tc &e) const
 Get the natural alignment unit of a reference to e.
unsigned int offset2align (const expr2tc &e, const BigInt &m) const
expr2tc to_expr (object_mapt::const_iterator it) const
 Convert an object map element to an expression.
void set (object_mapt &dest, object_mapt::const_iterator it) const
 Insert an object record element into an object map.
bool insert (object_mapt &dest, object_mapt::const_iterator it) const
bool insert (object_mapt &dest, const expr2tc &src, const BigInt &offset) const
bool insert (object_mapt &dest, unsigned n, const objectt &object) const
 Insert an object record into the given object map.
bool insert (object_mapt &dest, const expr2tc &expr, const objectt &object) const
bool erase (const std::string &name)
 Remove the given pointer value set from the map.
void erase_object (const std::string &id, const type2tc &type, const std::string &suffix="")
 Remove the value sets of an object of type named id: its own and those of its members and elements, keyed by id plus a .member or [] suffix.
void get_value_set (const expr2tc &expr, value_setst::valuest &dest) const
 Get the set of things that an expression might point at.
void clear ()
 Clear all value records from this value set.
void add_var (const std::string &id, const std::string &suffix)
 Add a value set for the given variable name and suffix.
void add_var (const entryt &e)
void del_var (const std::string &id, const std::string &suffix)
 Delete the value set for the given variable name and suffix.
void touch_entry (const entryt &e)
 Ensure a record exists for the given entry, without changing an existing one.
bool update_object_map (const entryt &e, const object_mapt &om, bool merge)
 Overwrite (merge=false) or union-into (merge=true) the object map recorded for the given entry.
void add_vars (const std::list< entryt > &vars)
 Add a value set for each variable in the given list.
void output (std::ostream &out) const
 Dump the value set's textual representation to the given iostream.
void dump () const
 Write a textual representation of the value set to stderr.
bool make_union (object_mapt &dest, const object_mapt &src) const
 Join the two given object maps.
bool make_union (const valuest &new_values, bool keepnew=false)
 Given another value set tracking object's storage, read all value set records out and merge them into this object's.
bool make_union (const value_sett &new_values, bool keepnew=false)
void apply_code (const expr2tc &code)
 When using value_sett for static analysis, takes a code statement and sends any assignments contained within to the assign method.
void assign (const expr2tc &lhs, const expr2tc &rhs, bool add_to_sets=false)
 Interpret an assignment, and update value sets to reflect it.
void assign_struct_union (const expr2tc &lhs, const expr2tc &rhs, const type2tc &lhs_type, bool add_to_sets)
 assign()'s struct/union arm, split out to keep assign() one dispatch.
void do_function_call (const symbolt &symbol, const std::vector< expr2tc > &arguments)
 Interpret a function call during static analysis.
void do_end_function (const expr2tc &lhs)
 During static analysis, simulate the return values assignment to the given lhs at the end of the function execution.
void get_reference_set (const expr2tc &expr, value_setst::valuest &dest) const
 Determine the set of variables that expr refers to.
void get_value_set (const expr2tc &expr, object_mapt &dest) const
 "Internal" get_value_set method.
void retire_objectless_operand (object_mapt &op0_set, object_mapt &op1_set, object_mapt &dest) const
 Recursive body of get_value_set.
void get_value_set_rec_cached (const expr2tc &expr, object_mapt &dest, const std::string &suffix, const type2tc &original_type, bool under_deref=true) const
 The entry point for the recursive value-set walk: memoises, then calls get_value_set_rec.

Static Public Member Functions

static irep_idt entry_key (const entryt &e)
 The map key is identifier + suffix.
static std::string concat_key (const std::string &id, const std::string &suffix)
 Compose the identifier + suffix map key into a single pre-sized buffer, avoiding the temporary that id2string(id) + suffix allocates for the (less common) array/struct-member pointer case.

Public Attributes

unsigned location_number
 Location number of the instruction this value set is attached to; used to identify allocation sites for dynamic objects.
valuest values
 Storage for all the value sets for all the variables in the program.
const namespacet & ns
 Namespace for looking up types against.
irep_idt xchg_name
unsigned long xchg_num

Static Public Attributes

static object_numberingt object_numbering
 Object to assign numbers to objects – i.e., the numbers in the map of a object_mapt.
static object_number_numberingt obj_numbering_refset

Protected Member Functions

std::optional< BigInt > constant_pointer_arith_offset (const expr2tc &non_ptr_op, const type2tc &subtype, bool subtracting) const
 The byte offset a constant operand of pointer arithmetic contributes, already signed by subtracting; nullopt when the operand is not a compile-time constant or its element size is not statically known.
void offset_pointer_arith_objects (const object_mapt &pointer_expr_set, const expr2tc &ptr_op, const std::optional< BigInt > &total_offs, object_mapt &dest) const
 Fold total_offs into every object of pointer_expr_set, tracking alignment where the offset or the object's own offset is nondet, and store the results into dest.
bool get_symbol_value_set (const symbol2t &sym, const expr2tc &expr, const std::string &suffix, const type2tc &original_type, object_mapt &dest) const
 What sym points at: the values keyed under the path the read spells, falling back to the paths a union arm it crosses aliases.
void get_constant_value_set (const expr2tc &expr, object_mapt &dest, const std::string &suffix, const type2tc &original_type, bool under_deref) const
 The constant cases of get_value_set_rec: what a value reaches this code as once constant propagation has substituted it.
void get_constant_struct_value_set (const expr2tc &expr, object_mapt &dest, const std::string &suffix, const type2tc &original_type, bool under_deref) const
 The two aggregate literals of get_constant_value_set.
void get_constant_union_value_set (const expr2tc &expr, object_mapt &dest, const std::string &suffix, const type2tc &original_type) const
void get_byte_stitching_value_set (const expr2tc &expr, object_mapt &dest, const std::string &suffix, const type2tc &original_type) const
void get_reference_set (const expr2tc &expr, object_mapt &dest) const
 Internal get_reference_set method.
void get_reference_set_rec (const expr2tc &expr, object_mapt &dest) const
 Recursive implementation of get_reference_set.
void assign_rec (const expr2tc &lhs, const object_mapt &values_rhs, const std::string &suffix, bool add_to_sets)
 Recursive assign method implementation – descends through the left hand side looking for symbols to assign values to.
void do_free (const expr2tc &op)
 Mark dynamic objects as (possibly) deallocated, and thus invalid.
expr2tc make_member (const expr2tc &src, const irep_idt &component_name)
 Attempt to extract the member of an expression statically.

Static Protected Member Functions

static void obj_numbering_ref (unsigned int num)
static void obj_numbering_deref (unsigned int num)

Member Typedef Documentation

◆ expr_sett

typedef std::set<expr2tc> value_sett::expr_sett

A type for a set of expressions.

◆ object_mapt

typedef std::unordered_map<unsigned, objectt> value_sett::object_mapt

Datatype for a value set: stores a mapping between some integers and additional reference data in an objectt object.

The integers are indexes into value_sett::object_numbering, which identifies the l1 variable being referred to.

◆ valuest

Maps each variable to the entryt holding the set of objects it may point at.

Persistent (structurally shared): symex snapshots the whole map at every goto for the later merge, so a std::unordered_map would copy O(N) per branch and make symex quadratic in the tracked-symbol count on branch-heavy inputs. immer's HAMT makes the snapshot O(1) — the same pattern level1 renaming and guard_seq use.

Constructor & Destructor Documentation

◆ value_sett() [1/2]

value_sett::value_sett ( const namespacet & _ns)
inlineexplicit

Primary constructor.

Does approximately nothing non-standard.

◆ value_sett() [2/2]

value_sett::value_sett ( const value_sett & ref)
inline

Member Function Documentation

◆ add_var() [1/2]

void value_sett::add_var ( const entryt & e)
inline

◆ add_var() [2/2]

void value_sett::add_var ( const std::string & id,
const std::string & suffix )
inline

Add a value set for the given variable name and suffix.

No effect if the given record already exists.

◆ add_vars()

void value_sett::add_vars ( const std::list< entryt > & vars)
inline

Add a value set for each variable in the given list.

◆ apply_code()

void value_sett::apply_code ( const expr2tc & code)

When using value_sett for static analysis, takes a code statement and sends any assignments contained within to the assign method.

Parameters
codeThe statement to interpret.

◆ assign()

void value_sett::assign ( const expr2tc & lhs,
const expr2tc & rhs,
bool add_to_sets = false )

Interpret an assignment, and update value sets to reflect it.

Parameters
lhsAssignment target expression.
rhsAssignment expression, to be interpreted, and its pointer records assigned to lhs.
add_to_setsIf true, merge the pointer set from rhs into the pointer set for lhs. Otherwise, overwrite it. Used for the static analysis.

◆ assign_rec()

void value_sett::assign_rec ( const expr2tc & lhs,
const object_mapt & values_rhs,
const std::string & suffix,
bool add_to_sets )
protected

Recursive assign method implementation – descends through the left hand side looking for symbols to assign values to.

Parameters
lhsLeft hand side expression that we're assigning value sets to.
values_rhsThe value set of the right hand side of the assignment, i.e. all the things the rhs points at.
suffixAccumulated suffix of the lhs up to this point. See docs for entryt and @get_value_set_rec_cached.
add_to_setsSee assign.

◆ assign_struct_union()

void value_sett::assign_struct_union ( const expr2tc & lhs,
const expr2tc & rhs,
const type2tc & lhs_type,
bool add_to_sets )

assign()'s struct/union arm, split out to keep assign() one dispatch.

◆ clear()

void value_sett::clear ( )
inline

Clear all value records from this value set.

◆ concat_key()

std::string value_sett::concat_key ( const std::string & id,
const std::string & suffix )
inlinestatic

Compose the identifier + suffix map key into a single pre-sized buffer, avoiding the temporary that id2string(id) + suffix allocates for the (less common) array/struct-member pointer case.

◆ constant_pointer_arith_offset()

std::optional< BigInt > value_sett::constant_pointer_arith_offset ( const expr2tc & non_ptr_op,
const type2tc & subtype,
bool subtracting ) const
protected

The byte offset a constant operand of pointer arithmetic contributes, already signed by subtracting; nullopt when the operand is not a compile-time constant or its element size is not statically known.

◆ del_var()

void value_sett::del_var ( const std::string & id,
const std::string & suffix )
inline

Delete the value set for the given variable name and suffix.

◆ do_end_function()

void value_sett::do_end_function ( const expr2tc & lhs)

During static analysis, simulate the return values assignment to the given lhs at the end of the function execution.

Parameters
lhsVariable to take the (pointer) values of the returned value.

◆ do_free()

void value_sett::do_free ( const expr2tc & op)
protected

Mark dynamic objects as (possibly) deallocated, and thus invalid.

Something to do with the black magic that allows the static analysis to deal with dynamically allocated memory.

Parameters
opOperand evaluating to the pointer to free.

◆ do_function_call()

void value_sett::do_function_call ( const symbolt & symbol,
const std::vector< expr2tc > & arguments )

Interpret a function call during static analysis.

Looks up the given function, and simulates the assignment of all the arguments to the argument variables in the target function (for pointer tracking).

Parameters
functionSymbol of the function to bind arguments into.
argumentsVector of argument expressions, will have their pointer tracking values merged into the corresponding argument variables in the target function.

◆ dump()

void value_sett::dump ( ) const

Write a textual representation of the value set to stderr.

◆ entry_key()

irep_idt value_sett::entry_key ( const entryt & e)
inlinestatic

The map key is identifier + suffix.

The suffix is empty on the overwhelming majority of calls, so avoid building the concatenated temporary in that case and key directly off the identifier.

◆ erase()

bool value_sett::erase ( const std::string & name)
inline

Remove the given pointer value set from the map.

Parameters
nameThe name of the variable, including suffix, to erase.
Returns
True when the erase succeeds, false otherwise.

◆ erase_object()

void value_sett::erase_object ( const std::string & id,
const type2tc & type,
const std::string & suffix = "" )

Remove the value sets of an object of type named id: its own and those of its members and elements, keyed by id plus a .member or [] suffix.

Linear in the type, where scanning the map for id would be linear in every tracked variable.

◆ get_byte_stitching_value_set()

void value_sett::get_byte_stitching_value_set ( const expr2tc & expr,
object_mapt & dest,
const std::string & suffix,
const type2tc & original_type ) const
protected

◆ get_constant_struct_value_set()

void value_sett::get_constant_struct_value_set ( const expr2tc & expr,
object_mapt & dest,
const std::string & suffix,
const type2tc & original_type,
bool under_deref ) const
protected

The two aggregate literals of get_constant_value_set.

Each consumes the one suffix component naming the member it holds, since a literal has no suffixed symbol name for the symbol case to look up.

◆ get_constant_union_value_set()

void value_sett::get_constant_union_value_set ( const expr2tc & expr,
object_mapt & dest,
const std::string & suffix,
const type2tc & original_type ) const
protected

◆ get_constant_value_set()

void value_sett::get_constant_value_set ( const expr2tc & expr,
object_mapt & dest,
const std::string & suffix,
const type2tc & original_type,
bool under_deref ) const
protected

The constant cases of get_value_set_rec: what a value reaches this code as once constant propagation has substituted it.

◆ get_natural_alignment()

unsigned int value_sett::get_natural_alignment ( const expr2tc & e) const
inline

Get the natural alignment unit of a reference to e.

I don't know a more appropriate term, but if we were to have an offset into e, then what is the greatest alignment guarentee that would make sense? i.e., an offset of 404 into an array of integers gives an alignment guarentee of 4 bytes, not 404.

For arrays, this is the element size. For structs, I imagine it's the machine word size (?). Depends on padding. For integers / other things, it's the machine / word size (?).

◆ get_reference_set() [1/2]

void value_sett::get_reference_set ( const expr2tc & expr,
object_mapt & dest ) const
inlineprotected

Internal get_reference_set method.

Just the same as the other get_reference_set method, but collects into an object_mapt instead of a list of exprs.

Parameters
exprThe expression to evaluate the reference set of.
destDestination value set object map to store results into.

◆ get_reference_set() [2/2]

void value_sett::get_reference_set ( const expr2tc & expr,
value_setst::valuest & dest ) const

Determine the set of variables that expr refers to.

The difference between this and get_value_set, is that this accumulates the set of variables /used/ in the expression, not the values they might point at. The primary use is, when one uses the address-of operator, and the operand may be a set of things, determine that set of things. An example: baz = &a->foo.bar[0] What does baz point at? It depends on what a points at, and a series of other expressions that must be interpreted. This method performs said interpretation, storing the results in a value set.

Parameters
exprThe expression to evaluate the reference set for.
destThe expression list to store the results into.

◆ get_reference_set_rec()

void value_sett::get_reference_set_rec ( const expr2tc & expr,
object_mapt & dest ) const
protected

Recursive implementation of get_reference_set.

Parameters
exprThe (portion of the) expression we're evaluating the reference set of.
destDestination value set map to store results into.

◆ get_symbol_value_set()

bool value_sett::get_symbol_value_set ( const symbol2t & sym,
const expr2tc & expr,
const std::string & suffix,
const type2tc & original_type,
object_mapt & dest ) const
protected

What sym points at: the values keyed under the path the read spells, falling back to the paths a union arm it crosses aliases.

Returns whether anything was found.

◆ get_value_set() [1/2]

void value_sett::get_value_set ( const expr2tc & expr,
object_mapt & dest ) const

"Internal" get_value_set method.

Just the same as the other get_value_set method, but collects into an object_mapt instead of a list of exprs.

Parameters
exprThe expression to evaluate the value set of.
destDestination value set object map to store the result into.

◆ get_value_set() [2/2]

void value_sett::get_value_set ( const expr2tc & expr,
value_setst::valuest & dest ) const

Get the set of things that an expression might point at.

Interprets the given expression, making note of all the pointer variables used by it, and create a value set of what this expression points at. For example, the expression: (foo + 2) would return the set of all the things 'foo' points at, with the offset records updated to reflect the offset added by the expression. (Although not for records where the offset is nondeterministic.

To be clear: the value set returned reflects the values that the entire expression may evaluate to. That means if you have ((nondet_bool()) ? foo : bar) then you'll get everything both foo and bar point at.

This method also looks up values through dereferences and addresses-of.

Parameters
exprThe expression to evaluate and determine the set of values it points to.
destA list to store pointed-at object expressions into.

◆ get_value_set_rec_cached()

void value_sett::get_value_set_rec_cached ( const expr2tc & expr,
object_mapt & dest,
const std::string & suffix,
const type2tc & original_type,
bool under_deref = true ) const

The entry point for the recursive value-set walk: memoises, then calls get_value_set_rec.

Call this rather than the recursion itself – a propagated multi-dimensional array reaches here as a DAG, and walking it unmemoised costs paths exponential in the number of stores it carries. The recursion is private so that cannot be bypassed.

◆ insert() [1/4]

bool value_sett::insert ( object_mapt & dest,
const expr2tc & expr,
const objectt & object ) const
inline

◆ insert() [2/4]

bool value_sett::insert ( object_mapt & dest,
const expr2tc & src,
const BigInt & offset ) const
inline

◆ insert() [3/4]

bool value_sett::insert ( object_mapt & dest,
object_mapt::const_iterator it ) const
inline

◆ insert() [4/4]

bool value_sett::insert ( object_mapt & dest,
unsigned n,
const objectt & object ) const
inline

Insert an object record into the given object map.

This method has various overloaded instances, that all descend to this particular method. The essential elements are a) an object map, b) an l1 data object or the index number (in value_sett::object_numbering) that identifies it, and c) the offset data for this record.

Rather than just adding this pointer record to the object map, this method attempts to merge the data in. That is, if the variable might already point at the same object, attempt to merge the two offset records. If that fails, then record the offset as being nondeterministic, and let the SMT solver work it out.

Parameters
destThe object map to insert this record into.
nThe identifier for the object being referrred to, as indexed by the value_set::object_numbering mapping.
objectThe offset data for the pointer record being inserted.

◆ make_member()

expr2tc value_sett::make_member ( const expr2tc & src,
const irep_idt & component_name )
protected

Attempt to extract the member of an expression statically.

If it's a chain of with's, or a constant struct, then pick out the actual expression value of the given struct component. If not, just formulate a member2t expression.

Parameters
srcStructure type'd expr to extract a member from.
component_nameName of the component to extract from src.

◆ make_union() [1/3]

bool value_sett::make_union ( const value_sett & new_values,
bool keepnew = false )
inline

◆ make_union() [2/3]

bool value_sett::make_union ( const valuest & new_values,
bool keepnew = false )

Given another value set tracking object's storage, read all value set records out and merge them into this object's.

Parameters
new_valuesStored set of value sets to merge into this object.
keepnewIf true, add new pointer records in new_values into this object's tracking map; if not, discard them.
Returns
True if a modification occurs.

◆ make_union() [3/3]

bool value_sett::make_union ( object_mapt & dest,
const object_mapt & src ) const

Join the two given object maps.

Takes all the pointer records from src and stores them into the dest object map.

Parameters
destDestination object map to join records into.
srcObject map to merge into dest.
Returns
True when dest has been modified.

◆ obj_numbering_deref()

void value_sett::obj_numbering_deref ( unsigned int num)
staticprotected

◆ obj_numbering_ref()

void value_sett::obj_numbering_ref ( unsigned int num)
staticprotected

◆ offset2align()

unsigned int value_sett::offset2align ( const expr2tc & e,
const BigInt & m ) const
inline

◆ offset_pointer_arith_objects()

void value_sett::offset_pointer_arith_objects ( const object_mapt & pointer_expr_set,
const expr2tc & ptr_op,
const std::optional< BigInt > & total_offs,
object_mapt & dest ) const
protected

Fold total_offs into every object of pointer_expr_set, tracking alignment where the offset or the object's own offset is nondet, and store the results into dest.

◆ operator=()

value_sett & value_sett::operator= ( const value_sett & ref)
inline

◆ output()

void value_sett::output ( std::ostream & out) const

Dump the value set's textual representation to the given iostream.

Parameters
outOutput stream to write the textual representation too.

◆ retire_objectless_operand()

void value_sett::retire_objectless_operand ( object_mapt & op0_set,
object_mapt & op1_set,
object_mapt & dest ) const

Recursive body of get_value_set.

An operand whose set holds nothing but unknown carries no object information, so it must not veto the other operand's.

Parameters
exprExpression to interpret and fetch value set for
destDestination object map to store pointed-at records in.
suffixCumulative suffix to attach to referred-to variables. See the documentation on entryt for what the suffix means. As higher level expressions determine the suffix that a variable name gets, this must be passed down from higher levels (through this parameter).
original_typeType of the top level expression. If any part of the interpreted expression isn't recognized, then an unknown2t expr is put in the value tracking set to represent the fact that interpretation failed, and it might point at something crazy.
under_derefIf true, treat the expression as occuring under a dereference operation. Otherwise treat it at free-standing. This only affects how constants are interpreted: if enabled, the expression 0 becomes a null_object2t reference in the value-set, while other constants are invalid2t/unknown2t; when disabled, constant expressions generate no references, except that a member of a constant aggregate is still selected, since navigating to it inserts nothing by itself. Stop an operand whose set is only unknown from vetoing the other's; the unknown moves into dest. See docs/design/pointer-integer-provenance.md.

Letting it count as non-empty dropped the whole expression to unknown, which is how an address round-tripped through uintptr_t arithmetic lost the object it still pointed at once a multiply had made one side unknown (#6545).

The unknown is carried into dest rather than discarded: the arithmetic may equally land outside every known object, and dropping that alternative would delete the invalid pointer property and hide a wild dereference. See docs/design/pointer-integer-provenance.md.

◆ set()

void value_sett::set ( object_mapt & dest,
object_mapt::const_iterator it ) const
inline

Insert an object record element into an object map.

Parameters
destThe map to insert this record into.
itIterator of existing object record to insert into dest.

◆ to_expr()

expr2tc value_sett::to_expr ( object_mapt::const_iterator it) const

Convert an object map element to an expression.

Formulates either an object_descriptor irep, or unknown / invalid expr's as appropriate.

◆ touch_entry()

void value_sett::touch_entry ( const entryt & e)
inline

Ensure a record exists for the given entry, without changing an existing one.

The persistent map's values are immutable, so a mutation is a read-modify-set via update_object_map().

◆ update_object_map()

bool value_sett::update_object_map ( const entryt & e,
const object_mapt & om,
bool merge )
inline

Overwrite (merge=false) or union-into (merge=true) the object map recorded for the given entry.

Only a genuine change writes the map, so a no-op update never breaks the record's structural sharing.

Member Data Documentation

◆ location_number

unsigned value_sett::location_number

Location number of the instruction this value set is attached to; used to identify allocation sites for dynamic objects.

◆ ns

const namespacet& value_sett::ns

Namespace for looking up types against.

◆ obj_numbering_refset

object_number_numberingt value_sett::obj_numbering_refset
thread_localstatic

◆ object_numbering

object_numberingt value_sett::object_numbering
thread_localstatic

Object to assign numbers to objects – i.e., the numbers in the map of a object_mapt.

thread_local so concurrent symex threads (–k-induction-parallel) don't race on the same hash_numbering. Numbers only need to be consistent within a single goto_symex state's lifetime, and each symex thread owns its own state.

◆ values

valuest value_sett::values

Storage for all the value sets for all the variables in the program.

See entryt for the format of the string used as an index.

◆ xchg_name

irep_idt value_sett::xchg_name

◆ xchg_num

unsigned long value_sett::xchg_num

The documentation for this class was generated from the following files: