1/*******************************************************************\
3Module: Program Transformation
5Author: Daniel Kroening, kroening@kroening.com
7\*******************************************************************/
41 // make it a side effect if there is an LHS
42 if(arguments.size() != 2)
45 error() <<
"'" << identifier <<
"' expected to have two arguments" <<
eom;
52 error() <<
"'" << identifier <<
"' expected to have LHS" <<
eom;
62 error() <<
"'" << identifier <<
"' expected other type" <<
eom;
67 arguments[0].type().
id() != lhs.
type().
id() ||
68 arguments[1].type().id() != lhs.
type().
id())
71 error() <<
"'" << identifier
72 <<
"' expected operands to be of same type as LHS" <<
eom;
79 error() <<
"'" << identifier
80 <<
"' expected operands to be constant literals" <<
eom;
91 error() <<
"error converting operands" <<
eom;
98 error() <<
"expected lower bound to be smaller or equal to the "
99 <<
"upper bound" <<
eom;
103 rhs.add_to_operands(
exprt{arguments[0]},
exprt{arguments[1]});
118 // make it a side effect if there is an LHS
119 if(arguments.size() != 2)
122 error() <<
"'" << identifier <<
"' expected to have two arguments" <<
eom;
129 error() <<
"'" << identifier <<
"' expected to have LHS" <<
eom;
138 error() <<
"'" << identifier <<
"' expected bool" <<
eom;
145 error() <<
"'" << identifier <<
"' expected first operand to be "
146 <<
"a constant literal of type unsigned long" <<
eom;
153 error() <<
"'" << identifier <<
"' expected second operand to be "
154 <<
"a constant literal of type unsigned long" <<
eom;
165 error() <<
"error converting operands" <<
eom;
172 error() <<
"probability has to be smaller than 1" <<
eom;
179 error() <<
"denominator may not be zero" <<
eom;
217 if(arguments.empty())
220 error() <<
"scanf takes at least one argument" <<
eom;
249 // A string. We first need a nondeterministic size.
262 // now use array copy
285 // make it nondet for now
299 // we'll just do nothing
311 const exprt &function,
315 if(arguments.size() < 2)
318 error() <<
"input takes at least two arguments" <<
eom;
326 const exprt &function,
330 if(arguments.size() < 2)
333 error() <<
"output takes at least two arguments" <<
eom;
349 error() <<
"atomic_begin does not expect an LHS" <<
eom;
353 if(!arguments.empty())
356 error() <<
"atomic_begin takes no arguments" <<
eom;
372 error() <<
"atomic_end does not expect an LHS" <<
eom;
376 if(!arguments.empty())
379 error() <<
"atomic_end takes no arguments" <<
eom;
394 error() <<
"do_cpp_new without lhs is yet to be implemented" <<
eom;
398 // build size expression
411 // might have side-effect
418 // is this a placement new?
419 if(rhs.
operands().empty())
// no, "regular" one
421 // call __new or __new_array
431 "new has one or two parameters");
440 new_call.arguments().push_back(count);
451 // call __placement_new
462 "placement new has two or three parameters");
471 new_call.arguments().push_back(count);
479 for(std::size_t i = 0; i <
code_type.parameters().size(); i++)
490 error() <<
"cpp_new expected to have 0 or 1 operands" <<
eom;
545 error() <<
"expected array-pointer as argument" <<
eom;
554 error() <<
"expected array-element as argument" <<
eom;
563 error() <<
"expected array as argument" <<
eom;
577 if(arguments.size() != 2)
580 error() <<
id <<
" expects two arguments" <<
eom;
588 // lhs is only used with array_equal, in all other cases it should be nil (as
589 // they are of type void)
601 // aarch64 ABI mandates that va_list has struct type with member names as
603 const auto &components = ns.
follow_tag(*struct_tag_type).components();
605 components.size() == 5,
606 "va_list struct type expected to have 5 components");
612 // if it's an address of an lvalue, we take that
638 // We disable checks on the generated instructions
639 // because we add our own rw_ok assertion that takes size into account
641 source_location.add_pragma(
"disable:pointer-check");
642 source_location.add_pragma(
"disable:pointer-overflow-check");
643 source_location.add_pragma(
"disable:pointer-primitive-check");
646 if(arguments.size() != 2)
649 error() <<
"'" << identifier <<
"' expected to have two arguments" <<
eom;
653 // check argument types
657 error() <<
"'" << identifier
658 <<
"' first argument expected to have `void *` type" <<
eom;
665 error() <<
"'" << identifier
666 <<
"' second argument expected to have `size_t` type" <<
eom;
674 error() <<
"'" << identifier <<
"' not expected to have a LHS" <<
eom;
678 // insert instructions
679 // assert(rw_ok(argument[0], argument[1]));
680 // char nondet_contents[argument[1]];
681 // __CPROVER_array_replace(p, nondet_contents);
684 ok_expr.add_source_location() = source_location;
725 error() <<
"'alloca' function called, but 'alloca' has not been declared "
726 <<
"with expected 'void *' return type." <<
eom;
734 error() <<
"'alloca' function called, but 'alloca' has not been declared "
735 <<
"with expected single 'size_t' parameter." <<
eom;
741 // make sure we have a left-hand side to track the allocation even when the
742 // original program did not
747 alloca_type.return_type(),
"alloca", dest, source_location, mode)
751 // do the actual function call
756 // Don't add instrumentation when we're in alloca (which might in turn call
757 // __builtin_alloca) -- the instrumentation will be done for the call of
758 // alloca. Also, we can only add instrumentation when we're in a function
767 // create a symbol to eventually (and non-deterministically) mark the
768 // allocation as dead; this symbol has function scope and is initialised to
785 targets.prefix->destructive_insert(
788 // non-deterministically update this_alloca_ptr
799 // mark pointer to alloca result as dead, unless the alloca result (in
800 // this_alloca_ptr) is still NULL
813 targets.suffix->insert_before_swap(
814 targets.suffix->instructions.begin(), assign);
816 targets.suffix->instructions.begin(),
838 error() <<
"function '" << identifier <<
"' not found" <<
eom;
845 error() <<
"function '" << identifier <<
"' type mismatch: expected code"
850 // User-provided function definitions always take precedence over built-ins.
851 // Front-ends do not (yet) consistently set ID_C_incomplete, thus also test
852 // whether the symbol actually has some non-nil value (which might be
858 // use symbol->symbol_expr() to ensure we use the type from the symbol table
860 lhs, symbol->
symbol_expr().with_source_location(function), arguments);
863 // remove void-typed assignments, which may have been created when the
864 // front-end was unable to detect them in type checking for a lack of
865 // available declarations
883 identifier ==
CPROVER_PREFIX "assume" || identifier ==
"__VERIFIER_assume")
885 if(arguments.size() != 1)
888 error() <<
"'" << identifier <<
"' expected to have one argument" <<
eom;
892 // let's double-check the type of the argument
902 error() << identifier <<
" expected not to have LHS" <<
eom;
906 else if(identifier ==
"__VERIFIER_error")
908 if(!arguments.empty())
911 error() <<
"'" << identifier <<
"' expected to have no arguments" <<
eom;
923 error() << identifier <<
" expected not to have LHS" <<
eom;
927 // __VERIFIER_error has abort() semantics, even if no assertions
932 dest.
instructions.back().labels.push_back(
"__VERIFIER_abort");
935 identifier ==
"assert" &&
938 if(arguments.size() != 1)
941 error() <<
"'" << identifier <<
"' expected to have one argument" <<
eom;
945 // let's double-check the type of the argument
950 "assertion " +
from_expr(
ns, identifier, arguments.front()));
958 error() << identifier <<
" expected not to have LHS" <<
eom;
967 if(arguments.size() != 2)
970 error() <<
"'" << identifier <<
"' expected to have two arguments" <<
eom;
979 // let's double-check the type of the argument
1005 error() << identifier <<
" expected not to have LHS" <<
eom;
1011 if(arguments.size() != 1)
1014 error() <<
"'" << identifier <<
"' expected to have one argument" <<
eom;
1021 error() << identifier <<
" expected not to have LHS" <<
eom;
1033 do_printf(lhs, function, arguments, dest);
1037 do_scanf(lhs, function, arguments, dest);
1040 identifier ==
CPROVER_PREFIX "input" || identifier ==
"__CPROVER::input")
1045 error() << identifier <<
" expected not to have LHS" <<
eom;
1049 do_input(function, arguments, dest);
1052 identifier ==
CPROVER_PREFIX "output" || identifier ==
"__CPROVER::output")
1057 error() << identifier <<
" expected not to have LHS" <<
eom;
1065 identifier ==
"__CPROVER::atomic_begin" ||
1066 identifier ==
"java::org.cprover.CProver.atomicBegin:()V" ||
1067 identifier ==
"__VERIFIER_atomic_begin")
1073 identifier ==
"__CPROVER::atomic_end" ||
1074 identifier ==
"java::org.cprover.CProver.atomicEnd:()V" ||
1075 identifier ==
"__VERIFIER_atomic_end")
1091 // make it a side effect if there is an LHS
1097 // We need to special-case for _Bool, which
1098 // can only be 0 or 1.
1117 // make it a side effect if there is an LHS
1124 error() <<
"'" << identifier <<
"' is not declared, "
1125 <<
"missing type information required to construct call to "
1126 <<
"uninterpreted function" <<
eom;
1160 identifier ==
"__assert_fail" || identifier ==
"_assert" ||
1161 identifier ==
"__assert_c99" || identifier ==
"_wassert")
1163 // __assert_fail is Linux
1164 // These take four arguments:
1165 // "expression", "file.c", line, __func__
1166 // klibc has __assert_fail with 3 arguments
1167 // "expression", "file.c", line
1170 // void _assert (const char*, const char*, int);
1171 // with three arguments:
1172 // "expression", "file.c", line
1174 // This has been seen in Solaris 11.
1176 // void __assert_c99(
1177 // const char *desc, const char *file, int line, const char *func);
1179 // _wassert is Windows. The arguments are
1180 // L"expression", L"file.c", line
1182 if(arguments.size() != 4 && arguments.size() != 3)
1185 error() <<
"'" << identifier <<
"' expected to have four arguments"
1198 // we ignore any LHS
1200 else if(identifier ==
"__assert_rtn" || identifier ==
"__assert")
1202 // __assert_rtn has been seen on MacOS;
1203 // __assert is FreeBSD and Solaris 11.
1204 // These take four arguments:
1205 // __func__, "file.c", line, "expression"
1206 // On Solaris 11, it's three arguments:
1207 // "expression", "file", line
1211 if(arguments.size() == 4)
1215 else if(arguments.size() == 3)
1222 error() <<
"'" << identifier <<
"' expected to have four arguments"
1232 // we ignore any LHS
1235 identifier ==
"__assert_func" || identifier ==
"__assert2" ||
1236 identifier ==
"__assert13")
1238 // __assert_func is newlib (used by, e.g., cygwin)
1239 // __assert2 is OpenBSD
1240 // __assert13 is NetBSD
1241 // These take four arguments:
1242 // "file.c", line, __func__, "expression"
1243 if(arguments.size() != 4)
1246 error() <<
"'" << identifier <<
"' expected to have four arguments"
1258 // we might be building newlib, where __assert_func is passed
1259 // a pointer-typed symbol; the warning will still have been
1261 description =
"assertion";
1269 // we ignore any LHS
1273 if(arguments.empty())
1276 error() <<
"'" << identifier <<
"' expected to have at least one argument"
1283 for(
const auto &
argument : arguments)
1288 else if(identifier ==
"__builtin_prefetch")
1292 else if(identifier ==
"__builtin_unreachable")
1294 // says something like UNREACHABLE;
1298 // This does two things.
1299 // 1) Return value of argument.
1300 // This is just dereferencing.
1301 // 2) Move list pointer to next argument.
1302 // This is just an increment.
1304 if(arguments.size() != 1)
1307 error() <<
"'" << identifier <<
"' expected to have one argument" <<
eom;
1346 else if(identifier ==
"__builtin_va_copy")
1348 if(arguments.size() != 2)
1351 error() <<
"'" << identifier <<
"' expected to have two arguments" <<
eom;
1361 error() <<
"va_copy argument expected to be lvalue" <<
eom;
1368 else if(identifier ==
"__builtin_va_start" || identifier ==
"__va_start")
1370 // Set the list argument to be the address of the
1371 // parameter argument.
1372 if(arguments.size() != 2)
1375 error() <<
"'" << identifier <<
"' expected to have two arguments" <<
eom;
1384 error() <<
"va_start argument expected to be lvalue" <<
eom;
1398 rhs.add_to_operands(
1404 else if(identifier ==
"__builtin_va_end")
1406 // Invalidates the argument. We do so by setting it to NULL.
1407 if(arguments.size() != 1)
1410 error() <<
"'" << identifier <<
"' expected to have one argument" <<
eom;
1419 error() <<
"va_end argument expected to be lvalue" <<
eom;
1423 // our __builtin_va_list is a pointer
1434 identifier ==
"__builtin_isgreater" ||
1435 identifier ==
"__builtin_isgreaterequal" ||
1436 identifier ==
"__builtin_isless" || identifier ==
"__builtin_islessequal" ||
1437 identifier ==
"__builtin_islessgreater" ||
1438 identifier ==
"__builtin_isunordered")
1440 // these support two double or two float arguments; we call the
1441 // appropriate internal version
1443 arguments.size() != 2 ||
1450 error() <<
"'" << identifier
1451 <<
"' expected to have two float/double arguments" <<
eom;
1458 if(arguments[0].type() != arguments[1].type())
1474 f_type.remove_ellipsis();
1479 // replace __builtin_ by CPROVER_PREFIX
1481 // append d or f for double/float
1486 "builtin declaration should match constructed type");
1497 else if(identifier ==
"alloca" || identifier ==
"__builtin_alloca")
1499 do_alloca(lhs, function, arguments, dest, mode);
1505 // insert function call
1506 // use symbol->symbol_expr() to ensure we use the type from the symbol table
1508 lhs, symbol->
symbol_expr().with_source_location(function), arguments);
1511 // remove void-typed assignments, which may have been created when the
1512 // front-end was unable to detect them in type checking for a lack of
1513 // available declarations
static exprt make_va_list(const exprt &expr, const namespacet &ns)
floatbv_typet float_type()
signedbv_typet signed_int_type()
pointer_typet pointer_type(const typet &subtype)
signedbv_typet pointer_diff_type()
bitvector_typet char_type()
bitvector_typet c_index_type()
floatbv_typet double_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...
A goto_instruction_codet representing an assignment in the program.
goto_instruction_codet representation of a function call statement.
A goto_instruction_codet representing the declaration that an output of a particular description has ...
std::vector< parametert > parameterst
Data structure for representing an arbitrary statement in a program.
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Base class for all expressions.
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
std::vector< exprt > operandst
void copy_to_operands(const exprt &expr)
Copy the given argument to the end of exprt's operands.
typet & type()
Return the type of the expression.
const source_locationt & source_location() const
source_locationt & add_source_location()
The Boolean constant false.
Application of (mathematical) function.
void do_havoc_slice(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
symbol_table_baset & symbol_table
void do_input(const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest)
void do_array_op(const irep_idt &id, const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
irep_idt get_string_constant(const exprt &expr)
void copy(const codet &code, goto_program_instruction_typet type, goto_programt &dest)
void do_prob_coin(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
struct goto_convertt::targetst targets
symbolt & new_tmp_symbol(const typet &type, const std::string &suffix, goto_programt &dest, const source_locationt &, const irep_idt &mode)
void do_atomic_end(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
virtual void do_function_call_symbol(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
add function calls to function queue for later processing
void do_output(const exprt &rhs, const exprt::operandst &arguments, goto_programt &dest)
void cpp_new_initializer(const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest)
builds a goto program for object initialization after new
void do_printf(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
exprt get_array_argument(const exprt &src)
void do_alloca(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest, const irep_idt &mode)
alloca allocates memory that is freed when leaving the function (and not the block,...
void do_scanf(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
void convert(const codet &code, goto_programt &dest, const irep_idt &mode)
converts 'code' and appends the result to 'dest'
void do_atomic_begin(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
static void replace_new_object(const exprt &object, exprt &dest)
virtual void do_cpp_new(const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest)
clean_expr_resultt clean_expr(exprt &expr, const irep_idt &mode, bool result_is_used=true)
void do_prob_uniform(const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest)
A generic container class for the GOTO intermediate representation of one function.
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
instructionst instructions
The list of instructions in the goto program.
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
static instructiont make_atomic_end(const source_locationt &l=source_locationt::nil())
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_other(const goto_instruction_codet &_code, const source_locationt &l=source_locationt::nil())
static instructiont make_atomic_begin(const source_locationt &l=source_locationt::nil())
targett add(instructiont &&instruction)
Adds a given instruction at the end.
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
The trinary if-then-else operator.
bool get_bool(const irep_idt &name) const
const irept & find(const irep_idt &name) const
const irep_idt & get(const irep_idt &name) const
void set(const irep_idt &name, const irep_idt &value)
const irep_idt & id() const
A type for mathematical functions (do not confuse with functions/methods in code)
std::vector< typet > domaint
Extract member of struct or union.
source_locationt source_location
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The null pointer constant.
The plus expression Associativity is not specified.
A base class for a predicate that indicates that an address range is ok to read or write or both.
A side_effect_exprt that returns a non-deterministically chosen value.
An expression containing a side effect.
const irep_idt & get_statement() const
Expression to hold a symbol (variable)
void identifier(const irep_idt &identifier)
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
typet type
Type of symbol.
exprt value
Initial value of symbol.
Semantic type conversion.
static exprt conditional_cast(const exprt &expr, const typet &type)
The type of an expression, extends irept.
source_locationt & add_source_location()
void destruct_locals(const std::list< irep_idt > &vars, goto_programt &dest, const namespacet &ns)
std::optional< exprt > zero_initializer(const typet &type, const source_locationt &source_location, const namespacet &ns)
Create the equivalent of zero for type type.
Expression Initialization.
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
bool is_assignable(const exprt &expr)
Returns true iff the argument is one of the following:
Deprecated expression utility functions.
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.
const std::string & id2string(const irep_idt &d)
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
API to expression classes for 'mathematical' expressions.
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
exprt object_size(const exprt &pointer)
exprt simplify_expr(exprt src, const namespacet &ns)
#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)
const codet & to_code(const exprt &expr)
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
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 code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
std::list< irep_idt > temporaries
Identifiers of temporaries introduced while cleaning an expression.
void add(clean_expr_resultt &&other)
void add_temporary(const irep_idt &id)
goto_programt side_effects
Statements implementing side effects of the expression that was subject to cleaning.
const type_with_subtypet & to_type_with_subtype(const typet &type)