|
ESBMC
Efficient SMT-based Context-Bounded Model Checker
|
Trivial, conjunctive interval domain for both float and integers. More...
#include <interval_domain.h>
Public Types | |
| using | integer_intervalt = interval_templatet<BigInt> |
| using | real_intervalt |
| using | interval |
| using | interval_map = std::unordered_map<irep_idt, interval, irep_id_hash> |
Public Member Functions | |
| interval_domaint () | |
| void | transform (goto_programt::const_targett from, goto_programt::const_targett to, ai_baset &ai, const namespacet &ns) final override |
| how function calls are treated: a) there is an edge from each call site to the function head b) there is an edge from the last instruction (END_FUNCTION) of the function to the instruction following the call site (this also needs to set the LHS, if applicable) | |
| void | output (std::ostream &out) const override |
| void | dump () const |
| bool | merge (const interval_domaint &b, goto_programt::const_targett, goto_programt::const_targett to) |
| void | clear_state () |
| void | make_bottom () final override |
| no states | |
| void | make_top () final override |
| all states – the analysis doesn't use this, and domains may refuse to implement it. | |
| void | make_entry () final override |
| a reasonable entry-point state | |
| bool | is_bottom () const override final |
| bool | is_top () const override final |
| expr2tc | make_expression (const expr2tc &symbol) const |
| Creates an expression with the intervals found for the given symbol. | |
| void | assume (const expr2tc &) |
| Adds a restriction over all intervals. | |
| void | assume_assertion (const expr2tc &guard, const ai_baset &ai) |
Under –interval-analysis-assume-asserts, narrows the state to guard. | |
| void | process_instruction (goto_programt::const_targett from) |
| Updates the interval state based on a single goto-program instruction. | |
| void | join_snapshot (const std::shared_ptr< interval_map > &snapshot) |
| Join the domain recorded when another symex path was parked into this one, over every variable: a path narrows intervals by ASSUME as well as by assignment, so joining only the phi-assigned variables is unsound. | |
| void | havoc_rec (const expr2tc &expr) |
| Recursively explores an Expression until it reaches a symbol, then removes it from the int_map whatever the symbol's type. | |
| void | havoc_written_arguments (const code_function_call2t &call) |
| Forget what a body-less call that symex models may write through its pointer arguments (#8083). | |
| bool | havoc_pointee (const expr2tc &arg, bool any_type) |
Havoc the variable arg points into; false when that is unknown and arg, a pointer or any_type, may still have been written through. | |
| virtual bool | ai_simplify (expr2tc &condition, const namespacet &ns) const override |
| Uses the abstract state to simplify a given expression using context- specific information. | |
| void | copy_if_needed () |
| template<class Interval> | |
| Interval | get_interval (const expr2tc &e) const |
| Get the interval for expression. | |
| template<class Interval> | |
| Interval | get_interval_from_symbol (const symbol2t &sym) const |
| Get the interval from symbol object or top. | |
| template<size_t Index, class Interval> | |
| Interval | get_interval_from_variant (const symbol2t &sym) const |
| template<class Interval> | |
| bool | join_intervals (const std::shared_ptr< Interval > &after, std::shared_ptr< Interval > &dst, bool can_extrapolate) const |
| template<class Interval> | |
| Interval | get_interval_from_const (const expr2tc &sym) const |
| Get the interval from constant expression. | |
| template<class Interval> | |
| Interval | get_interval_from_typecast (const typecast2t &cast, Interval result) const |
| template<class Interval> | |
| Interval | get_top_interval_from_expr (const expr2tc &sym) const |
| template<class Interval> | |
| bool | is_mapped (const symbol2t &sym) const |
| template<class Interval> | |
| expr2tc | make_expression_helper (const expr2tc &symbol) const |
| template<class Interval> | |
| expr2tc | make_expression_value (const Interval &interval, const type2tc &type, bool upper) const |
| template<> | |
| interval_domaint::integer_intervalt | get_interval_from_symbol (const symbol2t &sym) const |
| template<> | |
| interval_domaint::real_intervalt | get_interval_from_symbol (const symbol2t &sym) const |
| template<> | |
| wrapped_interval | get_interval_from_symbol (const symbol2t &sym) const |
| template<> | |
| void | update_symbol_interval (const symbol2t &sym, const interval_domaint::integer_intervalt &value) |
| template<> | |
| void | update_symbol_interval (const symbol2t &sym, const interval_domaint::real_intervalt &value) |
| template<> | |
| void | update_symbol_interval (const symbol2t &sym, const wrapped_interval &value) |
| template<> | |
| interval_domaint::integer_intervalt | get_interval_from_const (const expr2tc &e) const |
| template<> | |
| interval_domaint::real_intervalt | get_interval_from_const (const expr2tc &e) const |
| template<> | |
| wrapped_interval | get_interval_from_const (const expr2tc &e) const |
| template<> | |
| interval_domaint::integer_intervalt | wrap_to_type (const integer_intervalt &i, const type2tc &t) const |
| template<class T> | |
| T | extrapolate_intervals (const T &before, const T &after) const |
| template<> | |
| wrapped_interval | extrapolate_intervals (const wrapped_interval &before, const wrapped_interval &after) const |
| template<> | |
| wrapped_interval | get_top_interval_from_expr (const expr2tc &e) const |
| template<class T> | |
| T | interpolate_intervals (const T &before, const T &after) |
| template<class T> | |
| T | get_interval_from_typecast (const typecast2t &cast, T result) const |
| template<class T> | |
| T | get_interval (const expr2tc &e) const |
| template<> | |
| bool | is_mapped (const symbol2t &sym) const |
| template<> | |
| expr2tc | make_expression_value (const wrapped_interval &interval, const type2tc &type, bool upper) const |
| template<> | |
| expr2tc | make_expression_helper (const expr2tc &symbol) const |
| Public Member Functions inherited from ai_domain_baset | |
| virtual | ~ai_domain_baset () |
| virtual bool | ai_simplify_lhs (expr2tc &condition, const namespacet &ns) const |
| Simplifies the expression but keeps it as an l-value. | |
| virtual expr2tc | to_predicate (void) const |
| Gives a Boolean condition that is true for all values represented by the domain. | |
Static Public Member Functions | |
| static void | set_options (const optionst &options) |
| static tvt | eval_boolean_expression (const expr2tc &cond, const interval_domaint &id) |
| Interpolate bound back after fixpoint. | |
| static std::shared_ptr< interval_map > | get_empty () |
Public Attributes | |
| std::shared_ptr< interval_map > | intervals |
| bool | copied = false |
Static Public Attributes | |
| static bool | enable_interval_arithmetic = false |
| static bool | enable_interval_bitwise_arithmetic = false |
| Enable simplification for arithmetic operators. | |
| static bool | enable_modular_intervals = false |
| Enable simplification for bitwise operations. | |
| static bool | enable_assertion_simplification = false |
| Make a modular operation after every assignment. | |
| static bool | enable_contraction_for_abstract_states = true |
| Simplify condition and assertions with the intervals. | |
| static bool | enable_wrapped_intervals = false |
| Use contractor for <= operations. | |
| static bool | enable_real_intervals = true |
| Enabled wrapped intervals (disables Integers). | |
| static bool | enable_assume_asserts = true |
| Enable real (floating-point) intervals. | |
| static bool | enable_eval_assumptions = true |
| Asserts are propagates as assumptions. | |
| static bool | enable_ibex_contractor = false |
| Try to evaluate in a guard in a TVT to accelerate bottoms. | |
| static bool | skip_inductive_step_instructions = false |
| Use ibex contractor. | |
| static unsigned | fixpoint_limit = 5 |
| static bool | widening_under_approximate_bound = false |
| Sets a limit for number of iterations before widening. | |
| static bool | widening_extrapolate = false |
| Whether to considers overflows for Integers. | |
| static bool | widening_narrowing = false |
| Extrapolate bound to infinity based on previous iteration. | |
Protected Member Functions | |
| bool | join (const interval_domaint &b, const goto_programt::const_targett &to) |
| Sets *this to the mathematical join between the two domains. | |
| void | assume_rec (const expr2tc &expr, bool negation=false) |
| Recursively explores intervals of an assume expression. | |
| void | assume_rec (const expr2tc &lhs, expr2t::expr_ids id, const expr2tc &rhs) |
| Recursively explores intervals over a comparation expression, inserting them into int_map. | |
| void | assign (const expr2tc &assignment, const bool recursive=false) |
| Computes an assignment expression. | |
| template<class Interval> | |
| void | apply_assignment (const expr2tc &lhs, const expr2tc &rhs, bool recursive) |
| Applies LHS <= RHS and RHS <= LHS from assignment instructions. | |
| template<class Interval> | |
| Interval | extrapolate_intervals (const Interval &before, const Interval &after) const |
| Applies Extrapolation widening algorithm. | |
| template<class Interval> | |
| Interval | interpolate_intervals (const Interval &before, const Interval &after) |
| Applies Interpolation narrowing algorithm. | |
| template<class Interval> | |
| void | apply_assume_less (const expr2tc &lhs, const expr2tc &rhs) |
| Applies LHS < RHS. | |
| template<class Interval> | |
| void | apply_assume_symbol_truth (const symbol2t &sym, bool is_false) |
| Applies symbol = truth. | |
| template<class Interval> | |
| Interval | generate_modular_interval (const type2tc &t) const |
| Generates interval with [min, max] of type t. | |
| template<class Interval> | |
| Interval | wrap_to_type (const Interval &i, const type2tc &t) const |
| Bring an interval computed over unbounded integers back into the range of the bitvector type t, as the solver's modular arithmetic would. | |
| template<class IntervalMap> | |
| bool | join (IntervalMap &new_map, const IntervalMap &previous_map, const bool is_guard_instruction=true) |
| template<class Interval> | |
| void | update_symbol_interval (const symbol2t &sym, const Interval &value) |
| Sets new interval for symbol. | |
| template<size_t Index, class Interval> | |
| void | update_symbol_from_variant (const symbol2t &sym, const Interval &value) |
| template<> | |
| wrapped_interval | generate_modular_interval (const type2tc &t) const |
| template<> | |
| void | apply_assume_less (const expr2tc &a, const expr2tc &b) |
| Protected Member Functions inherited from ai_domain_baset | |
| ai_domain_baset () | |
| The constructor is expected to produce 'false' or 'bottom'. | |
Protected Attributes | |
| bool | bottom |
| Is this state a bottom. | |
Trivial, conjunctive interval domain for both float and integers.
The categorization 'float' and 'integers' is done by is_int and is_float.
| using interval_domaint::interval_map = std::unordered_map<irep_idt, interval, irep_id_hash> |
|
inline |
|
overridevirtual |
Uses the abstract state to simplify a given expression using context- specific information.
| parameters | The expression to simplify. |
This implementation is aimed at reducing assertions to true, particularly range checks for arrays and other bounds checks.
Rather than work with the various kinds of exprt directly, we use assume, join and is_bottom. It is sufficient for the use case and avoids duplicating functionality that is in assume anyway.
As some expressions (1<=a && a<=2) can be represented exactly as intervals and some can't (a<1 || a>2), the way these operations are used varies depending on the structure of the expression to try to give the best results. For example negating a disjunction makes it easier for assume to handle.
Implements ai_domain_baset.
|
protected |
Applies LHS <= RHS and RHS <= LHS from assignment instructions.
This is separate from the usual assume_rec as LHS symbol may be inside RHS
| Interval | interval template specialization (Integers, Reals) |
| lhs | |
| rhs |
|
protected |
|
protected |
Applies LHS < RHS.
| Interval | interval template specialization (Integers, Reals) |
| lhs | |
| rhs | |
| less_than_equal | if operation should be <= |
|
protected |
Applies symbol = truth.
| Interval | interval template specialization (Integers, Reals) |
| symbol | |
| negation |
|
protected |
Computes an assignment expression.
This recomputes the interval of the LHS to be of RHS, i.e. LHS == RHS.
| assignment |
| void interval_domaint::assume | ( | const expr2tc & | cond | ) |
Adds a restriction over all intervals.
Do not mistake this by an ASSUME instruction! This can take any type of expression!
Under –interval-analysis-assume-asserts, narrows the state to guard.
Recursively explores intervals of an assume expression.
This is the entry-point of the function, it does the following:
| expr | |
| negation | sets whether the current expr is a negation |
|
protected |
Recursively explores intervals over a comparation expression, inserting them into int_map.
| lhs | |
| id | |
| rhs |
|
inline |
|
inline |
| void interval_domaint::dump | ( | ) | const |
|
static |
Interpolate bound back after fixpoint.
Eval whether a boolean expression is always true, always false, or either (for the current state)
|
protected |
Applies Extrapolation widening algorithm.
Given two intervals: (a0, b0) (before the computation) and (a1, b1) (after the computation): The objective of the extrapolation is to accelerate the convergence at the cost of precision
Example: int i = 0; while(i < 10) i++; <— what is the interval for i before the increment?
Computing the interval of sum would need 11 iterations to arrive to [0,9], it 1 = [0,0] it 2 = [0,1] it 3 = [0,2] ... it 10 = [0,9] it 11 = [0,9] fixpoint
By extrapolating, we can arrive at [0, +inf] in two iterations. it 1 = [0,0] it 2 = [0,1] => [0, inf] it 3 = [0,inf] fixpoint
Widening((a0,b0), (a1,b1)) = (a1 < a0 ? -infinity : a0, b1 > b0 ? infinity : b0 )
| Interval | interval template specialization (Integers, Reals) |
| lhs | |
| rhs |
| T interval_domaint::extrapolate_intervals | ( | const T & | before, |
| const T & | after ) const |
| wrapped_interval interval_domaint::extrapolate_intervals | ( | const wrapped_interval & | before, |
| const wrapped_interval & | after ) const |
|
protected |
|
protected |
Generates interval with [min, max] of type t.
| Interval | interval template specialization (Integers, Reals) |
| t |
|
inlinestatic |
| Interval interval_domaint::get_interval | ( | const expr2tc & | e | ) | const |
Get the interval for expression.
This computes the interval of a given expression and returns it
| Interval | interval template specialization (Integers, Reals) |
| e |
| wrapped_interval interval_domaint::get_interval_from_const | ( | const expr2tc & | e | ) | const |
| interval_domaint::real_intervalt interval_domaint::get_interval_from_const | ( | const expr2tc & | e | ) | const |
| interval_domaint::integer_intervalt interval_domaint::get_interval_from_const | ( | const expr2tc & | e | ) | const |
| Interval interval_domaint::get_interval_from_const | ( | const expr2tc & | sym | ) | const |
Get the interval from constant expression.
| Interval | interval template specialization (Integers, Reals) |
| sym |
| wrapped_interval interval_domaint::get_interval_from_symbol | ( | const symbol2t & | sym | ) | const |
| interval_domaint::real_intervalt interval_domaint::get_interval_from_symbol | ( | const symbol2t & | sym | ) | const |
| interval_domaint::integer_intervalt interval_domaint::get_interval_from_symbol | ( | const symbol2t & | sym | ) | const |
| Interval interval_domaint::get_interval_from_symbol | ( | const symbol2t & | sym | ) | const |
Get the interval from symbol object or top.
| Interval | interval template specialization (Integers, Reals) |
| sym |
| Interval interval_domaint::get_interval_from_typecast | ( | const typecast2t & | cast, |
| Interval | result ) const |
| T interval_domaint::get_interval_from_typecast | ( | const typecast2t & | cast, |
| T | result ) const |
| Interval interval_domaint::get_interval_from_variant | ( | const symbol2t & | sym | ) | const |
| wrapped_interval interval_domaint::get_top_interval_from_expr | ( | const expr2tc & | e | ) | const |
| Interval interval_domaint::get_top_interval_from_expr | ( | const expr2tc & | sym | ) | const |
Havoc the variable arg points into; false when that is unknown and arg, a pointer or any_type, may still have been written through.
| void interval_domaint::havoc_rec | ( | const expr2tc & | expr | ) |
Recursively explores an Expression until it reaches a symbol, then removes it from the int_map whatever the symbol's type.
TODO: There are a lot of expressions that are not supported TODO: A utility function that recursively extracts all the symbols of an expr would be very useful
| expr |
| void interval_domaint::havoc_written_arguments | ( | const code_function_call2t & | call | ) |
Forget what a body-less call that symex models may write through its pointer arguments (#8083).
|
protected |
Applies Interpolation narrowing algorithm.
Given two intervals: (a0, b0) (before the computation) and (a1, b1) (after the computation): The objective of the interpolation is to bring back some of the precision lost from an extrapolation.
Example: int i = 0; while(i < 10) i++; <— what is the interval for i before the increment?
Coming back from an extrapolation [0, +inf] (which is a fixpoint) we can narrow the interval by checking the interval post the loop condition (i < 10) it 4 = narrowing([0, inf], [0, 9]) => [0,9] it 5 = [0,9]
Narrowing((a0,b0), (a1,b1)) = (a0 == -inf ? a1 : a0, b0 = +inf ? b1 : b0)
| Interval | interval template specialization (Integers, Reals) |
| lhs | |
| rhs |
|
inlinefinaloverridevirtual |
Implements ai_domain_baset.
|
inlinefinaloverridevirtual |
Implements ai_domain_baset.
|
protected |
Sets *this to the mathematical join between the two domains.
This can be thought of as an abstract version of union; *this is increased so that it contains all of the values that are represented by b as well as its original intervals. The result is an overapproximation, for example: "[0,1]".join("[3,4]") --> "[0,4]" includes 2 which isn't in [0,1] or [3,4].
Join is used in several places, the most significant being
merge, which uses it to bring together two different paths
of analysis.
| b | The interval domain, b, to join to this domain. |
|
protected |
| bool interval_domaint::join_intervals | ( | const std::shared_ptr< Interval > & | after, |
| std::shared_ptr< Interval > & | dst, | ||
| bool | can_extrapolate ) const |
| void interval_domaint::join_snapshot | ( | const std::shared_ptr< interval_map > & | snapshot | ) |
Join the domain recorded when another symex path was parked into this one, over every variable: a path narrows intervals by ASSUME as well as by assignment, so joining only the phi-assigned variables is unsound.
|
inlinefinaloverridevirtual |
no states
Implements ai_domain_baset.
|
inlinefinaloverridevirtual |
a reasonable entry-point state
Implements ai_domain_baset.
Creates an expression with the intervals found for the given symbol.
For example, if given a symbol expression with the variable 'FOO'. If at the current abstract state the interval for it is of: [2, 42]
This would return an expression of the form: AND (>= FOO 2) (<= FOO 42)
If top, it will return a true expr. If bottom, it will return a false expr.
| symbol | to construct the interval |
| expr2tc interval_domaint::make_expression_value | ( | const Interval & | interval, |
| const type2tc & | type, | ||
| bool | upper ) const |
| expr2tc interval_domaint::make_expression_value | ( | const wrapped_interval & | interval, |
| const type2tc & | type, | ||
| bool | upper ) const |
|
inlinefinaloverridevirtual |
all states – the analysis doesn't use this, and domains may refuse to implement it.
Implements ai_domain_baset.
|
inline |
|
overridevirtual |
Implements ai_domain_baset.
| void interval_domaint::process_instruction | ( | goto_programt::const_targett | from | ) |
Updates the interval state based on a single goto-program instruction.
Handles ASSIGN, ASSUME, DECL, DEAD and FUNCTION_CALL without requiring an ai_baset reference. Intended for online use during symbolic execution (default guard pruning; disable guard with –no-interval-symex-guard; assertion pruning via –interval-symex-assert).
| from | iterator to the instruction to process |
|
static |
|
finaloverridevirtual |
how function calls are treated: a) there is an edge from each call site to the function head b) there is an edge from the last instruction (END_FUNCTION) of the function to the instruction following the call site (this also needs to set the LHS, if applicable)
"this" is the domain before the instruction "from" "from" is the instruction to be interpreted "to" is the next instruction (for GOTO, FUNCTION_CALL, END_FUNCTION)
PRECONDITION(from.is_dereferenceable(), "Must not be _::end()") PRECONDITION(to.is_dereferenceable(), "Must not be _::end()") PRECONDITION(are_comparable(from,to) || (from->is_function_call() || from->is_end_function())
Implements ai_domain_baset.
|
protected |
|
protected |
Sets new interval for symbol.
| Interval | interval template specialization (Integers, Reals) |
| sym | |
| value |
| void interval_domaint::update_symbol_interval | ( | const symbol2t & | sym, |
| const interval_domaint::integer_intervalt & | value ) |
| void interval_domaint::update_symbol_interval | ( | const symbol2t & | sym, |
| const interval_domaint::real_intervalt & | value ) |
| void interval_domaint::update_symbol_interval | ( | const symbol2t & | sym, |
| const wrapped_interval & | value ) |
| interval_domaint::integer_intervalt interval_domaint::wrap_to_type | ( | const integer_intervalt & | i, |
| const type2tc & | t ) const |
|
protected |
Bring an interval computed over unbounded integers back into the range of the bitvector type t, as the solver's modular arithmetic would.
|
protected |
Is this state a bottom.
I.e., there is a contradiction between an assignment and an assume
Make a modular operation after every assignment.
Simplify condition and assertions with the intervals.
Try to evaluate in a guard in a TVT to accelerate bottoms.
Enable simplification for arithmetic operators.
Enable simplification for bitwise operations.
Enabled wrapped intervals (disables Integers).
|
static |
| std::shared_ptr<interval_map> interval_domaint::intervals |
Use ibex contractor.
When set, the transformer skips any instruction whose inductive_step_instruction flag is true. Used by the post-k-induction loop-bounds pass: havoc'd assignments and entry-condition assumes that k-induction emitted before each loop head are made transparent, so the fixpoint at the loop head matches the bounds at the original loop head (before k-induction's transformation). The bounds are then a sound inductive hypothesis to assume right after the havoc.
thread_local so a future threaded –k-induction-parallel can run concurrent interval analyses without one transformer's "skip" leaking into another's. Always toggled via scoped_skip_inductive (interval_analysis.cpp), which save-and-restores the prior value so an exception or a nested call cannot leave it stuck.
Whether to considers overflows for Integers.
Extrapolate bound to infinity based on previous iteration.
Sets a limit for number of iterations before widening.