ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
migrate.cpp File Reference
Include dependency graph for migrate.cpp:

Typedefs

using back_cachet
 Legacy forms of migrated aggregate types, keyed on node identity.

Functions

expr2tc invoke_intrinsic (const std::string &name, const typet &type, const std::vector< exprt > &args)
 An ESBMC intrinsic invoked from an expression position, as a sideeffect2t of allockind::function_call carrying the call's result type.
static void restore_padding_flag (struct_union_typet::componentt &component)
static struct_union_typet::componentst migrate_components_back (const std::vector< type2tc > &members, const std::vector< irep_idt > &names, const std::vector< irep_idt > &pretty_names, const std::vector< irep_idt > &base_names)
static code_typet::argumentst migrate_arguments_back (const code_type2t &ref2)
const BigInt & binary2bigint (irep_idt binary, bool is_signed)
static expr2tc fixup_containerof_in_sizeof (const expr2tc &_expr)
static unsigned get_pragma_unroll (const exprt &expr)
static pointer_ref_kindt pointer_ref_kind (const typet &type)
static BigInt explicit_alignment (const typet &type)
 An explicit alignas in bytes, or zero when the record has none.
static bool migrates_to_empty (const typet &type)
 Type ids that carry no storage and so migrate to the empty type: an unset or nil id; an ellipsis, which is not a type at all; clang's BoundMember, the type of obj.
static std::vector< irep_idt > struct_bases (const typet &type)
static irep_idt ctor_dtor_marker (const typet &ret)
static void migrate_exception_spec (const typet &type, irep_idt &kind, std::vector< irep_idt > &types, std::vector< type2tc > &decl)
static std::vector< expr2tc > migrate_arg_defaults (const code_typet::argumentst &old_args)
static type2tc migrate_type0 (const typet &type)
type2tc migrate_type (const typet &type)
type2tc migrate_symbol_type (const symbolt &sym)
void migrate_symbol_value (const symbolt &sym, expr2tc &dest)
void set_symbol_type (symbolt &sym, const type2tc &t)
expr2tc symbol_expr2tc (const symbolt &sym)
expr2tc side_effect_function_call2tc (const type2tc &return_type, const expr2tc &function, const std::vector< expr2tc > &arguments)
static const typet & decide_on_expr_type (const exprt &side1, const exprt &side2)
static exprt splice_expr (const exprt &expr)
static void splice_expr (const exprt &expr, expr2tc &new_expr_ref)
static void promote_complex_operand (const type2tc &t, expr2tc &op)
 Clang does not cast a binary operator's real operand to complex – it hands over double + _Complex double and leaves the promotion to the consumer, so clang_c_adjust's complex lowering pairs the real with a zero imaginary part before anything migrates.
static void decay_array_operand (expr2tc &op)
 C11 6.3.2.1p3.
static void convert_operand_pair (const exprt &expr, expr2tc &arg1, expr2tc &arg2)
static bool handle_introspection_expr (const exprt &expr, expr2tc &new_expr_ref)
expr2tc sym_name_to_symbol (const irep_idt &init, const type2tc &type)
static expr2tc migrate_sizeof (const exprt &expr)
 sizeof(T): op0 (a type_exprt) carries the measured type T, op1 the eagerly-computed byte-size value.
static expr2tc migrate_builtin_va_arg (const exprt &expr)
 clang_c_adjust::adjust_builtin_va_arg lowers this to a __ESBMC_va_arg call, and IREP2 has no builtin_va_arg kind – so under –clang-c-irep2-adjust-only the node would die before anything could rewrite it.
static expr2tc migrate_rounding_mode (const exprt &expr)
 The rounding mode a legacy ieee_* node carries.
static bool migrate_ieee_arith_2op (const exprt &expr, expr2tc &new_expr_ref)
 The two-operand IEEE nodes migrate identically: an n-ary irep splices into nested binaries, and the rounding mode comes from the irep's attribute when it carries one.
static void coerce_ternary_branch (expr2tc &branch, const type2tc &type)
 Bring one ternary branch to the ternary's own type.
static expr2tc coerce_to_type (const expr2tc &e, const type2tc &type)
static expr2tc migrate_pointer_ok (const exprt &expr)
 _CPROVER{r,w,rw}_ok(p, n): the n bytes from p lie inside one live object.
static const exprt & cpp_new_size (const exprt &expr)
 cpp_new[] hides the array size in a size field.
static bool migrate_before_dispatch (const exprt &expr, expr2tc &new_expr_ref)
 The two forms recognised before the id dispatch below: a nil expression, and a node carrying a #derived_to_base marker.
static bool migrate_right_shift (const exprt &expr, expr2tc &new_expr_ref)
 The right-shift family.
static void migrate_cpp_delete (const exprt &expr, std::vector< expr2tc > &args)
static void migrate_cpp_new (const exprt &expr, expr2tc &thesize, std::vector< expr2tc > &args)
static void wrap_padded_union_member (const type2tc &type, const irep_idt &component, std::vector< expr2tc > &members)
static bool is_all_zero_bytes (const expr2tc &e)
static expr2tc union_member_update (const type2tc &type, const expr2tc &source, const expr2tc &offs, const expr2tc &update)
static expr2tc byte_update_bytes (const type2tc &type, expr2tc result, const expr2tc &offs, const expr2tc &update, bool big_endian)
static expr2tc migrate_byte_update (const type2tc &type, const expr2tc &source, const expr2tc &offs, const expr2tc &update, bool big_endian)
void migrate_expr (const exprt &expr, expr2tc &new_expr_ref)
void migrate_type_back_cache_clear ()
static void migrate_struct_bases_back (const struct_type2t &ref, typet &type)
static void migrate_ctor_dtor_marker_back (const code_type2t &ref, code_typet &code)
static void migrate_exception_spec_back (const code_type2t &ref, code_typet &code)
static typet migrate_type_back_uncached (const type2tc &ref)
typet migrate_type_back (const type2tc &ref)
static void restore_type_comments (typet &t, bool constant_qualified, const irep_idt &cpp_type)
 #constant and #cpp_type are comment fields: writing them when unset still inserts the key, which the printer then reads back as a qualifier or a spelling (§158).
static void set_implicit_flag (exprt &e, bool implicit)
static const char * back_sideeffect_statement (sideeffect2t::allockind kind)
static void back_sideeffect_cpp_delete (const sideeffect2t &ref2, exprt &theexpr)
static void back_sideeffect_cpp_new (const sideeffect2t &ref2, exprt &theexpr)
static void back_sideeffect_operands (const sideeffect2t &ref2, exprt &theexpr)
static exprt back_sideeffect (const expr2tc &ref)
static exprt with_cformat (exprt e, const irep_idt &cformat)
 Restores #cformat only when there is one: it is a comment field, but an empty one still makes c_expr2string prefer it over deriving the text, so it would print nothing at all (§63).
static exprt migrate_expr_back_dispatch (const expr2tc &ref)
exprt migrate_expr_back (const expr2tc &ref)
static exprt back_typecast (const typecast2t &ref2)
 A cast's legacy form, with the base-conversion markers the adjust passes dispatch on.
static exprt migrate_expr_back_rest6 (const expr2tc &ref)
static exprt migrate_expr_back_rest5 (const expr2tc &ref)
static exprt migrate_expr_back_rest4 (const expr2tc &ref)
static exprt migrate_expr_back_rest3 (const expr2tc &ref)
static exprt migrate_expr_back_rest2 (const expr2tc &ref)
void migrate_census (const contextt &context)
 Migrate every symbol's type, and its value where it has one, and report what could not be represented.

Variables

const namespacet * migrate_namespace_lookup = nullptr
static std::map< irep_idt, BigInt > bin2int_map_signed
static std::map< irep_idt, BigInt > bin2int_map_unsigned
static std::mutex bin2int_map_signed_mutex
static std::mutex bin2int_map_unsigned_mutex
static back_cachet back_cache
static constexpr size_t back_cache_capacity = 4096

Typedef Documentation

◆ back_cachet

using back_cachet
Initial value:
std::unordered_map<const type2t *, std::pair<type2tc, typet>>

Legacy forms of migrated aggregate types, keyed on node identity.

Identity keying is sound because the entry pins the type2tc, so the node cannot be freed and its address reused, and irep_container is copy-on-write: a node the cache references detaches on write rather than mutating in place. migrate_type_back() reads no globals, so the legacy form is a pure function of the node – unlike the forward direction, which reads config and migrate_namespace_lookup, so this key scheme must not be copied to it. The pinned type2tc keeps the key valid; the typet is the memoised result.

Function Documentation

◆ back_sideeffect()

exprt back_sideeffect ( const expr2tc & ref)
static

◆ back_sideeffect_cpp_delete()

void back_sideeffect_cpp_delete ( const sideeffect2t & ref2,
exprt & theexpr )
static

◆ back_sideeffect_cpp_new()

void back_sideeffect_cpp_new ( const sideeffect2t & ref2,
exprt & theexpr )
static

◆ back_sideeffect_operands()

void back_sideeffect_operands ( const sideeffect2t & ref2,
exprt & theexpr )
static

◆ back_sideeffect_statement()

const char * back_sideeffect_statement ( sideeffect2t::allockind kind)
static

◆ back_typecast()

exprt back_typecast ( const typecast2t & ref2)
static

A cast's legacy form, with the base-conversion markers the adjust passes dispatch on.

A same-type cast carrying #derived_to_base is the wrapper migrate_expr builds for a marker on a node that is not a cast, so the marker goes back on the node itself rather than leaving an identity cast behind.

◆ binary2bigint()

const BigInt & binary2bigint ( irep_idt binary,
bool is_signed )

◆ byte_update_bytes()

expr2tc byte_update_bytes ( const type2tc & type,
expr2tc result,
const expr2tc & offs,
const expr2tc & update,
bool big_endian )
static

◆ coerce_ternary_branch()

void coerce_ternary_branch ( expr2tc & branch,
const type2tc & type )
static

Bring one ternary branch to the ternary's own type.

C11 6.3.2.1p3: an array operand converts to a pointer to its first element. That is not a cast of the array object, and the frontend's own conversion (c_typecastt::do_typecast) spells it &a[0]; coerced as a plain typecast the node reaches the encoder as typecast(array, pointer) and aborts it.

◆ coerce_to_type()

expr2tc coerce_to_type ( const expr2tc & e,
const type2tc & type )
static

◆ convert_operand_pair()

void convert_operand_pair ( const exprt & expr,
expr2tc & arg1,
expr2tc & arg2 )
static

◆ cpp_new_size()

const exprt & cpp_new_size ( const exprt & expr)
static

cpp_new[] hides the array size in a size field.

The frontend stores it under "size" (size_irep); the pipeline later mirrors it into "#size" (cmt_size). Under –irep2-bodies the body is migrated before that mirroring runs, so "#size" is still empty – read "size" then, or the size is silently dropped. A present-but-empty irep is a third state is_not_nil() reports as present, so the choice is made on the id.

◆ ctor_dtor_marker()

irep_idt ctor_dtor_marker ( const typet & ret)
static

◆ decay_array_operand()

void decay_array_operand ( expr2tc & op)
static

C11 6.3.2.1p3.

clang_c_convert drops CK_ArrayToPointerDecay and leaves clang_c_adjust to insert the &a[0], so an expression migrated before that pass – which –clang-c-irep2-adjust-only does – still carries the array, and add2t/sub2t assert on it (esbmc/esbmc#4715).

◆ decide_on_expr_type()

const typet & decide_on_expr_type ( const exprt & side1,
const exprt & side2 )
static

◆ explicit_alignment()

BigInt explicit_alignment ( const typet & type)
static

An explicit alignas in bytes, or zero when the record has none.

It travels as an alignment sub-irep and add_padding reads it back to size a record's trailing pad (docs/roadmap/scope-clang-cpp-irep2.md §7.4).

◆ fixup_containerof_in_sizeof()

expr2tc fixup_containerof_in_sizeof ( const expr2tc & _expr)
static

◆ get_pragma_unroll()

unsigned get_pragma_unroll ( const exprt & expr)
static

◆ handle_introspection_expr()

bool handle_introspection_expr ( const exprt & expr,
expr2tc & new_expr_ref )
static

◆ invoke_intrinsic()

expr2tc invoke_intrinsic ( const std::string & name,
const typet & type,
const std::vector< exprt > & args )
inline

An ESBMC intrinsic invoked from an expression position, as a sideeffect2t of allockind::function_call carrying the call's result type.

It has to be an expression node, not a code_function_call2t: the latter is void-typed, and an enclosing arithmetic constructor asserts on an operand whose type is not its own – CBMC serialises object_size under +, so the abort landed while the binary was still being read, long before lift_call_expressions() gets a chance to hoist the call out (#7410).

◆ is_all_zero_bytes()

bool is_all_zero_bytes ( const expr2tc & e)
static

◆ migrate_arg_defaults()

std::vector< expr2tc > migrate_arg_defaults ( const code_typet::argumentst & old_args)
static

◆ migrate_arguments_back()

code_typet::argumentst migrate_arguments_back ( const code_type2t & ref2)
static

◆ migrate_before_dispatch()

bool migrate_before_dispatch ( const exprt & expr,
expr2tc & new_expr_ref )
static

The two forms recognised before the id dispatch below: a nil expression, and a node carrying a #derived_to_base marker.

That marker names whichever node is being converted, and that is almost never a cast: over regression/esbmc-cpp it lands on a symbol 32474 times and on a typecast 58. IREP2 has nowhere to hang a flag on an arbitrary node, so it becomes a same-type typecast2t around it – the identity – which back_typecast unwraps. Dropping it loses the base displacement and silently proves false assertions (docs/roadmap/scope-clang-cpp-irep2.md §3.12).

◆ migrate_builtin_va_arg()

expr2tc migrate_builtin_va_arg ( const exprt & expr)
static

clang_c_adjust::adjust_builtin_va_arg lowers this to a __ESBMC_va_arg call, and IREP2 has no builtin_va_arg kind – so under –clang-c-irep2-adjust-only the node would die before anything could rewrite it.

The lowering is a pure function of the node's type and operand, which migration may compute (§72, §80). The callee symbol is declared by clang_c_adjust_irep2::declare_implicit_callee, and goto_convert's __ESBMC_va_arg arm (builtin_functions.cpp) enforces the one-argument contract and settles the operand's final shape. The normal pipeline adjusts first and never reaches this function.

◆ migrate_byte_update()

expr2tc migrate_byte_update ( const type2tc & type,
const expr2tc & source,
const expr2tc & offs,
const expr2tc & update,
bool big_endian )
static

◆ migrate_census()

void migrate_census ( const contextt & context)

Migrate every symbol's type, and its value where it has one, and report what could not be represented.

Migration signals failure by throwing a std::string, so each symbol is wrapped: one unrepresentable construct names itself and the walk continues, which is what makes this a census rather than a bisection. Walks the whole linked context, operational models included, which is the set goto_convert migrates anyway.

Frontend-agnostic on purpose: clang-cpp and solidity share one definition, so a census taken on either is the same measurement (docs/roadmap/scope-solidity-irep2.md §3, step S.2).

◆ migrate_components_back()

struct_union_typet::componentst migrate_components_back ( const std::vector< type2tc > & members,
const std::vector< irep_idt > & names,
const std::vector< irep_idt > & pretty_names,
const std::vector< irep_idt > & base_names )
static

◆ migrate_cpp_delete()

void migrate_cpp_delete ( const exprt & expr,
std::vector< expr2tc > & args )
static

◆ migrate_cpp_new()

void migrate_cpp_new ( const exprt & expr,
expr2tc & thesize,
std::vector< expr2tc > & args )
static

◆ migrate_ctor_dtor_marker_back()

void migrate_ctor_dtor_marker_back ( const code_type2t & ref,
code_typet & code )
static

◆ migrate_exception_spec()

void migrate_exception_spec ( const typet & type,
irep_idt & kind,
std::vector< irep_idt > & types,
std::vector< type2tc > & decl )
static

◆ migrate_exception_spec_back()

void migrate_exception_spec_back ( const code_type2t & ref,
code_typet & code )
static

◆ migrate_expr()

void migrate_expr ( const exprt & expr,
expr2tc & new_expr_ref )

◆ migrate_expr_back()

exprt migrate_expr_back ( const expr2tc & ref)

◆ migrate_expr_back_dispatch()

exprt migrate_expr_back_dispatch ( const expr2tc & ref)
static

◆ migrate_expr_back_rest2()

exprt migrate_expr_back_rest2 ( const expr2tc & ref)
static

◆ migrate_expr_back_rest3()

exprt migrate_expr_back_rest3 ( const expr2tc & ref)
static

◆ migrate_expr_back_rest4()

exprt migrate_expr_back_rest4 ( const expr2tc & ref)
static

◆ migrate_expr_back_rest5()

exprt migrate_expr_back_rest5 ( const expr2tc & ref)
static

◆ migrate_expr_back_rest6()

exprt migrate_expr_back_rest6 ( const expr2tc & ref)
static

◆ migrate_ieee_arith_2op()

bool migrate_ieee_arith_2op ( const exprt & expr,
expr2tc & new_expr_ref )
static

The two-operand IEEE nodes migrate identically: an n-ary irep splices into nested binaries, and the rounding mode comes from the irep's attribute when it carries one.

False when expr is not one of them.

◆ migrate_pointer_ok()

expr2tc migrate_pointer_ok ( const exprt & expr)
static

_CPROVER{r,w,rw}_ok(p, n): the n bytes from p lie inside one live object.

Migrating these to true made every assertion over them pass vacuously – CBMC refutes __CPROVER_r_ok(malloc(8), 16) and ESBMC proved it. ESBMC draws no read/write distinction (it models no read-only storage), so all three get the same encoding.

◆ migrate_right_shift()

bool migrate_right_shift ( const exprt & expr,
expr2tc & new_expr_ref )
static

The right-shift family.

lshr and ashr name their kind; the Solidity converter also emits a kind-less shr for >>, and IREP2 has no node for it. clang_c_adjust resolves that one by the left operand's signedness before anything migrates, but –clang-cpp-irep2-adjust-only replaces that pass, so the resolution belongs here (docs/roadmap/scope-solidity-irep2.md §7.21). The three are extracted together because migrate_expr is over the complexity gate: an arm added inline fails it.

◆ migrate_rounding_mode()

expr2tc migrate_rounding_mode ( const exprt & expr)
static

The rounding mode a legacy ieee_* node carries.

The frontends leave it implicit on most of them, in which case it is the global symbol.

◆ migrate_sizeof()

expr2tc migrate_sizeof ( const exprt & expr)
static

sizeof(T): op0 (a type_exprt) carries the measured type T, op1 the eagerly-computed byte-size value.

Both become reflected sizeof2t fields, replacing the legacy sizeof-type side channel (esbmc/esbmc#5337).

◆ migrate_struct_bases_back()

void migrate_struct_bases_back ( const struct_type2t & ref,
typet & type )
static

◆ migrate_symbol_type()

type2tc migrate_symbol_type ( const symbolt & sym)

◆ migrate_symbol_value()

void migrate_symbol_value ( const symbolt & sym,
expr2tc & dest )

◆ migrate_type()

type2tc migrate_type ( const typet & type)

◆ migrate_type0()

type2tc migrate_type0 ( const typet & type)
static

◆ migrate_type_back()

typet migrate_type_back ( const type2tc & ref)

◆ migrate_type_back_cache_clear()

void migrate_type_back_cache_clear ( )

◆ migrate_type_back_uncached()

typet migrate_type_back_uncached ( const type2tc & ref)
static

◆ migrates_to_empty()

bool migrates_to_empty ( const typet & type)
static

Type ids that carry no storage and so migrate to the empty type: an unset or nil id; an ellipsis, which is not a type at all; clang's BoundMember, the type of obj.

*pmf before it is called, which is a placeholder rather than storage – clang_c_adjust::adjust_ptr_mem replaces the whole node with the member function, and a ptr_mem2t typed empty is exactly that placeholder, a pointer-to-*data*-member selection carrying the member's own type (docs/roadmap/scope-clang-cpp-irep2.md §7.5); and the return types of a destructor and of a constructor, which is a void method on an existing object rather than something that returns a value.

◆ pointer_ref_kind()

pointer_ref_kindt pointer_ref_kind ( const typet & type)
static

◆ promote_complex_operand()

void promote_complex_operand ( const type2tc & t,
expr2tc & op )
static

Clang does not cast a binary operator's real operand to complex – it hands over double + _Complex double and leaves the promotion to the consumer, so clang_c_adjust's complex lowering pairs the real with a zero imaginary part before anything migrates.

Under –clang-c-irep2-adjust-only that pass does not run and the mixed node reaches the arith constructors, whose width assertion fires before clang_c_adjust_irep2 can lower it. The promotion is a pure function of the node's type and the operand, so migration may do it (§80).

◆ restore_padding_flag()

void restore_padding_flag ( struct_union_typet::componentt & component)
static

◆ restore_type_comments()

void restore_type_comments ( typet & t,
bool constant_qualified,
const irep_idt & cpp_type )
static

#constant and #cpp_type are comment fields: writing them when unset still inserts the key, which the printer then reads back as a qualifier or a spelling (§158).

◆ set_implicit_flag()

void set_implicit_flag ( exprt & e,
bool implicit )
static

◆ set_symbol_type()

void set_symbol_type ( symbolt & sym,
const type2tc & t )

◆ side_effect_function_call2tc()

expr2tc side_effect_function_call2tc ( const type2tc & return_type,
const expr2tc & function,
const std::vector< expr2tc > & arguments )

◆ splice_expr() [1/2]

exprt splice_expr ( const exprt & expr)
static

◆ splice_expr() [2/2]

void splice_expr ( const exprt & expr,
expr2tc & new_expr_ref )
static

◆ struct_bases()

std::vector< irep_idt > struct_bases ( const typet & type)
static

◆ sym_name_to_symbol()

expr2tc sym_name_to_symbol ( const irep_idt & init,
const type2tc & type )

◆ symbol_expr2tc()

expr2tc symbol_expr2tc ( const symbolt & sym)

◆ union_member_update()

expr2tc union_member_update ( const type2tc & type,
const expr2tc & source,
const expr2tc & offs,
const expr2tc & update )
static

◆ with_cformat()

exprt with_cformat ( exprt e,
const irep_idt & cformat )
static

Restores #cformat only when there is one: it is a comment field, but an empty one still makes c_expr2string prefer it over deriving the text, so it would print nothing at all (§63).

◆ wrap_padded_union_member()

void wrap_padded_union_member ( const type2tc & type,
const irep_idt & component,
std::vector< expr2tc > & members )
static

Variable Documentation

◆ back_cache

back_cachet back_cache
thread_localstatic

◆ back_cache_capacity

size_t back_cache_capacity = 4096
staticconstexpr

◆ bin2int_map_signed

std::map<irep_idt, BigInt> bin2int_map_signed
static

◆ bin2int_map_signed_mutex

std::mutex bin2int_map_signed_mutex
static

◆ bin2int_map_unsigned

std::map<irep_idt, BigInt> bin2int_map_unsigned
static

◆ bin2int_map_unsigned_mutex

std::mutex bin2int_map_unsigned_mutex
static

◆ migrate_namespace_lookup

const namespacet* migrate_namespace_lookup = nullptr
thread_local