1/*******************************************************************\
3Module: Symbolic Execution
5Author: Daniel Kroening, kroening@kroening.com
7\*******************************************************************/
50 "assignments must be type consistent, got",
57 mstream <<
"Assignment to " << format(lhs) <<
" ["
58 << pointer_offset_bits(lhs.type(), ns).value_or(0) <<
" bits]"
62 // rvalues present within the lhs (for example, "some_array[this_rvalue]" or
63 // "byte_extract <type> from an_lvalue offset this_rvalue") can affect whether
64 // we use field-sensitive symbols or not, so L2-rename them up front:
91 // Let's hide return value assignments.
100 // We hide if we are in a hidden function.
104 // We hide if we are executing a hidden instruction.
105 if(state.
source.
pc->source_location().get_hide())
117 // Try to constant propagate potential side effects of the assignment, when
118 // simplification is turned on and there is one thread only. Constant
119 // propagation is only sound for sequential code as here we do not take into
120 // account potential writes from other threads when propagating the values.
128 // We may end up reading (and writing) all components of an object composed
129 // of multiple fields. In such cases, we must do so atomically to avoid
130 // overwriting components modified by another thread. Note that this also
131 // implies multiple shared reads on the rhs being treated as atomic.
174 static_assert(
CHAR_BIT == 8,
"bitwidth of char assumed to be 8");
179 sizeof(std::size_t) >=
n_chars,
180 "size_t shall be large enough to represent a character");
188 for(std::size_t i = 0; i <
n_chars; i++)
190 const char c_chunk =
static_cast<char>((
c_val >> (i * 8)) & 0xff);
218 // constant propagating the empty string always succeeds as it does
219 // not depend on potentially non-constant inputs
279 // We need to make sure that the length of the previous array isn't
280 // unconstrained, otherwise it could be arbitrarily large which causes
284 // assign length of string
301 "symbol shall have value derived from char array content");
380std::optional<std::reference_wrapper<const array_exprt>>
383 const exprt &content)
401std::optional<std::reference_wrapper<const constant_exprt>>
417 return std::optional<std::reference_wrapper<const constant_exprt>>(
427 const auto &length_type =
f_type.domain().at(0);
435 f_l1.arguments().size() >= 2,
436 "empty string primitive requires two output arguments");
455 const auto &length_type =
f_type.domain().at(0);
484 operands.end(),
s2_data.operands().begin(),
s2_data.operands().end());
510 const auto &length_type =
f_type.domain().at(0);
591 // The function application expression f_l1 takes the following arguments:
592 // - result string length (output parameter)
593 // - result string data array (output parameter)
594 // - integer to convert to a string
595 // - radix (optional, default 10)
602 const auto &length_type =
f_type.domain().at(0);
649 std::back_inserter(operands),
650 [&
char_type](
const char c) { return from_integer(tolower(c), char_type); });
670 // The function application expression f_l1 takes the following arguments:
671 // - result string length (output parameter)
672 // - result string data array (output parameter)
673 // - string to delete char from
674 // - index of char to delete
678 const auto &length_type =
f_type.domain().at(0);
711 operands.reserve(
s_data.operands().size() - 1);
717 s_data.operands().begin(),
718 std::next(
s_data.operands().begin(), i));
722 std::next(
s_data.operands().begin(), i + 1),
743 // The function application expression f_l1 takes the following arguments:
744 // - result string length (output parameter)
745 // - result string data array (output parameter)
746 // - string to delete substring from
747 // - index of start of substring to delete (inclusive)
748 // - index of end of substring to delete (exclusive)
752 const auto &length_type =
f_type.domain().at(0);
811 s_data.operands().begin(),
837 // The function application expression f_l1 takes the following arguments:
838 // - result string length (output parameter)
839 // - result string data array (output parameter)
841 // - new length of the string
845 const auto &length_type =
f_type.domain().at(0);
889 s_data.operands().begin(),
891 s_data.operands().begin(),
918 // The function application expression f_l1 takes the following arguments:
919 // - result string length (output parameter)
920 // - result string data array (output parameter)
922 // - index of char to set
927 const auto &length_type =
f_type.domain().at(0);
990 const auto &length_type =
f_type.domain().at(0);
1007 // Can't guarantee matches against non-ASCII characters.
1008 if(character >= 128)
1051 const auto &length_type =
f_type.domain().at(0);
1066 // Two main ways to perform a replace: characters or strings.
1102 // Copy data, then do initial search for a replace sequence.
1110 // If we've found a match, proceed to perform a replace on all instances.
1113 // Find the difference between our first/last match iterator.
1119 // Insert our replacement characters, then move the iterator to the end of
1120 // our new sequence.
1127 // Then search from there for any additional matches.
1159 const auto &length_type =
f_type.domain().at(0);
1170 return character >
' ';
1173 // Note the points where a trim would trim too.
1174 auto &operands =
s_data_opt->get().operands();
1180 // Then copy in the string with leading/trailing whitespace removed.
1181 // Note: if start_iter == operands.end it means the entire string is
1182 // whitespace, so we'll trim it to be empty anyway.
const integer_bitvector_typet & to_integer_bitvector_type(const typet &type)
Cast a typet to an integer_bitvector_typet.
bitvector_typet char_type()
bitvector_typet c_index_type()
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Array constructor from list of elements.
A constant literal expression.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Expression in which some part is missing and can be substituted for another expression.
Base class for all expressions.
std::vector< exprt > operandst
typet & type()
Return the type of the expression.
exprt apply(const namespacet &ns, goto_symex_statet &state, exprt expr, bool write) const
Turn an expression expr into a field-sensitive SSA expression.
bool is_divisible(const ssa_exprt &expr, bool disjoined_fields_only) const
Determine whether expr would translate to an atomic SSA expression (returns false) or a composite obj...
Application of (mathematical) function.
unsigned atomic_section_id
Threads.
sharing_mapt< irep_idt, exprt > propagation
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Central data structure: state.
call_stackt & call_stack()
exprt l2_rename_rvalues(exprt lvalue, const namespacet &ns)
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
symbol_tablet symbol_table
contains symbols that are minted during symbolic execution, such as dynamically created objects etc.
field_sensitivityt field_sensitivity
symex_targett::sourcet source
std::vector< threadt > threads
virtual void symex_assume(statet &state, const exprt &cond)
Symbolically execute an ASSUME instruction or simulate such an execution for a synthetic assumption.
virtual void symex_atomic_begin(statet &state)
Symbolically execute an ATOMIC_BEGIN instruction.
irep_idt language_mode
language_mode: ID_java, ID_C or another language identifier if we know the source language in use,...
bool constant_propagate_delete_char_at(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate deleting a character from a string.
bool constant_propagate_set_char_at(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate setting the char at the given index.
bool constant_propagate_assignment_with_side_effects(statet &state, symex_assignt &symex_assign, const exprt &lhs, const exprt &rhs)
Attempt to constant propagate side effects of the assignment (if any)
bool constant_propagate_delete(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate deleting a substring from a string.
static std::optional< std::reference_wrapper< const constant_exprt > > try_evaluate_constant(const statet &state, const exprt &expr)
void constant_propagate_empty_string(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Create an empty string constant.
symex_target_equationt & target
The equation that this execution is building up.
bool constant_propagate_case_change(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1, bool to_upper)
Attempt to constant propagate case changes, both upper and lower.
virtual void symex_allocate(statet &state, const exprt &lhs, const side_effect_exprt &code)
Symbolically execute an assignment instruction that has an allocate on the right hand side.
bool constant_propagate_integer_to_string(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate converting an integer to a string.
exprt clean_expr(exprt expr, statet &state, bool write)
Clean up an expression.
bool constant_propagate_trim(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate trim operations.
shadow_memoryt shadow_memory
Shadow memory instrumentation API.
virtual void symex_va_start(statet &, const exprt &lhs, const side_effect_exprt &)
namespacet ns
Initialized just before symbolic execution begins, to point to both outer_symbol_table and the symbol...
virtual void do_simplify(exprt &expr, const value_sett &value_set)
void symex_assign(statet &state, const exprt &lhs, const exprt &rhs)
Symbolically execute an ASSIGN instruction or simulate such an execution for a synthetic assignment.
const symbolt & get_new_string_data_symbol(statet &state, symex_assignt &symex_assign, const std::string &aux_symbol_name, const ssa_exprt &char_array, const array_exprt &new_char_array)
Installs a new symbol in the symbol table to represent the given character array, and assigns the cha...
void associate_array_to_pointer(statet &state, symex_assignt &symex_assign, const array_exprt &new_char_array, const address_of_exprt &string_data)
Generate array to pointer association primitive.
virtual void symex_cpp_new(statet &state, const exprt &lhs, const side_effect_exprt &code)
Handles side effects of type 'new' for C++ and 'new array' for C++ and Java language modes.
bool constant_propagate_set_length(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate setting the length of a string.
messaget log
The messaget to write log messages to.
const symex_configt symex_config
The configuration to use for this symbolic execution.
bool constant_propagate_string_substring(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate getting a substring of a string.
bool constant_propagate_replace(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant proagate character replacement.
bool constant_propagate_string_concat(statet &state, symex_assignt &symex_assign, const function_application_exprt &f_l1)
Attempt to constant propagate string concatenation.
virtual void symex_atomic_end(statet &state)
Symbolically execute an ATOMIC_END instruction.
void assign_string_constant(statet &state, symex_assignt &symex_assign, const ssa_exprt &length, const constant_exprt &new_length, const ssa_exprt &char_array, const array_exprt &new_char_array)
Assign constant string length and string data given by a char array to given ssa variables.
std::optional< std::reference_wrapper< const array_exprt > > try_evaluate_constant_string(const statet &state, const exprt &content)
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
const irep_idt & id() const
void conditional_output(mstreamt &mstream, const std::function< void(mstreamt &)> &output_generator) const
Generate output to message_stream using output_generator if the configured verbosity is at least as h...
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
const exprt & content() const
An expression containing a side effect.
Expression providing an SSA-renamed symbol of expressions.
Expression to hold a symbol (variable)
bool has_symbol(const irep_idt &name) const
Check whether a symbol exists in the symbol table.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Functor for symex assignment.
State type in value_set_domaint, used in value-set analysis and goto-symex.
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
static std::string get_alnum_string(const array_exprt &char_array)
Maps the given array expression containing constant characters to a string containing only alphanumer...
const std::string & id2string(const irep_idt &d)
API to expression classes for 'mathematical' expressions.
const function_application_exprt & to_function_application_expr(const exprt &expr)
Cast an exprt to a function_application_exprt.
const mathematical_function_typet & to_mathematical_function_type(const typet &type)
Cast a typet to a mathematical_function_typet.
const std::string integer2string(const mp_integer &n, unsigned base)
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
std::optional< std::reference_wrapper< const array_exprt > > try_get_string_data_array(const exprt &content, const namespacet &ns)
Get char sequence from content field of a refined string expression.
#define CHECK_RETURN(CONDITION)
#define UNREACHABLE
This should be used to mark dead code.
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
#define PRECONDITION(CONDITION)
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
bool is_ssa_expr(const exprt &expr)
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
side_effect_exprt & to_side_effect_expr(exprt &expr)
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
String expressions for the string solver.
refined_string_exprt & to_string_expr(exprt &expr)
std::string escape_non_alnum(std::string_view to_escape)
Replace non-alphanumeric characters with _xx escapes, where xx are hex digits.
goto_programt::const_targett pc
Symbolic Execution of assignments.