@@ -14,6 +14,8 @@ Author: Daniel Kroening, kroening@kroening.com
1414#include < util/arith_tools.h>
1515#include < util/c_types.h>
1616#include < util/expr_initializer.h>
17+ #include < util/expr_util.h>
18+ #include < util/fresh_symbol.h>
1719#include < util/invariant_utils.h>
1820#include < util/optional.h>
1921#include < util/pointer_offset_size.h>
@@ -206,24 +208,44 @@ void goto_symext::symex_allocate(
206208 code_assignt (lhs, typecast_exprt::conditional_cast (rhs, lhs.type ())));
207209}
208210
209- irep_idt get_symbol (const exprt &src)
211+ // / Construct an entry for the var args array. Visual Studio complicates this as
212+ // / we need to put immediate values or pointers in there, depending on the size
213+ // / of the parameter.
214+ static exprt va_list_entry (
215+ const irep_idt ¶meter,
216+ const pointer_typet &lhs_type,
217+ const namespacet &ns)
210218{
211- if (src.id ()==ID_typecast)
212- return get_symbol (to_typecast_expr (src).op ());
213- else if (src.id ()==ID_address_of)
219+ static const pointer_typet void_ptr_type = pointer_type (empty_typet{});
220+
221+ symbol_exprt parameter_expr = ns.lookup (parameter).symbol_expr ();
222+
223+ // Visual Studio has va_list == char* and stores parameters of size no
224+ // greater than the size of a pointer as immediate values
225+ if (lhs_type.subtype ().id () != ID_pointer)
214226 {
215- exprt op=to_address_of_expr (src).object ();
216- if (op.id ()==ID_symbol &&
217- op.get_bool (ID_C_SSA_symbol))
218- return to_ssa_expr (op).get_object_name ();
219- else
220- return irep_idt ();
227+ auto parameter_size = size_of_expr (parameter_expr.type (), ns);
228+ CHECK_RETURN (parameter_size.has_value ());
229+
230+ binary_predicate_exprt fits_slot{
231+ *parameter_size,
232+ ID_le,
233+ from_integer (lhs_type.get_width (), parameter_size->type ())};
234+
235+ return if_exprt{
236+ fits_slot,
237+ typecast_exprt::conditional_cast (parameter_expr, void_ptr_type),
238+ typecast_exprt::conditional_cast (
239+ address_of_exprt{parameter_expr}, void_ptr_type)};
221240 }
222241 else
223- return irep_idt ();
242+ {
243+ return typecast_exprt::conditional_cast (
244+ address_of_exprt{std::move (parameter_expr)}, void_ptr_type);
245+ }
224246}
225247
226- void goto_symext::symex_gcc_builtin_va_arg_next (
248+ void goto_symext::symex_va_start (
227249 statet &state,
228250 const exprt &lhs,
229251 const side_effect_exprt &code)
@@ -233,42 +255,52 @@ void goto_symext::symex_gcc_builtin_va_arg_next(
233255 if (lhs.is_nil ())
234256 return ; // ignore
235257
236- // to allow constant propagation
237- exprt tmp = state.rename (code.op0 (), ns).get ();
238- do_simplify (tmp);
239- irep_idt id=get_symbol (tmp);
240-
241- const auto zero = zero_initializer (lhs.type (), code.source_location (), ns);
242- CHECK_RETURN (zero.has_value ());
243- exprt rhs (*zero);
258+ // create an array holding pointers to the parameters, starting after the
259+ // parameter that the operand points to
260+ const exprt &op = skip_typecast (code.op0 ());
261+ // this must be the address of a symbol
262+ const irep_idt start_parameter =
263+ to_ssa_expr (to_address_of_expr (op).object ()).get_object_name ();
244264
245- if (!id.empty ())
265+ exprt::operandst va_arg_operands;
266+ bool parameter_id_found = false ;
267+ for (auto ¶meter : state.call_stack ().top ().parameter_names )
246268 {
247- // strip last name off id to get function name
248- std::size_t pos=id2string (id).rfind (" ::" );
249- if (pos!=std::string::npos)
269+ if (!parameter_id_found)
250270 {
251- irep_idt function_identifier=std::string (id2string (id), 0 , pos);
252- std::string base=id2string (function_identifier)+" ::va_arg" ;
253-
254- if (has_prefix (id2string (id), base))
255- id=base+std::to_string (
256- safe_string2unsigned (
257- std::string (id2string (id), base.size (), std::string::npos))+1 );
258- else
259- id=base+" 0" ;
260-
261- const symbolt *symbol;
262- if (!ns.lookup (id, symbol))
263- {
264- const symbol_exprt symbol_expr (symbol->name , symbol->type );
265- rhs = typecast_exprt::conditional_cast (
266- address_of_exprt (symbol_expr), lhs.type ());
267- }
271+ parameter_id_found = parameter == start_parameter;
272+ continue ;
268273 }
269- }
270274
271- symex_assign (state, code_assignt (lhs, rhs));
275+ va_arg_operands.push_back (
276+ va_list_entry (parameter, to_pointer_type (lhs.type ()), ns));
277+ }
278+ const std::size_t va_arg_size = va_arg_operands.size ();
279+ exprt array =
280+ array_exprt{std::move (va_arg_operands),
281+ array_typet{pointer_type (empty_typet{}),
282+ from_integer (va_arg_size, size_type ())}};
283+
284+ symbolt &va_array = get_fresh_aux_symbol (
285+ array.type (),
286+ id2string (state.source .function_id ),
287+ " va_args" ,
288+ state.source .pc ->source_location ,
289+ ns.lookup (state.source .function_id ).mode ,
290+ state.symbol_table );
291+ va_array.value = array;
292+
293+ clean_expr (array, state, false );
294+ array = state.rename (std::move (array), ns).get ();
295+ do_simplify (array);
296+ symex_assign (state, code_assignt{va_array.symbol_expr (), std::move (array)});
297+
298+ exprt rhs = address_of_exprt{
299+ index_exprt{va_array.symbol_expr (), from_integer (0 , index_type ())}};
300+ rhs = state.rename (std::move (rhs), ns).get ();
301+ symex_assign (
302+ state,
303+ code_assignt{lhs, typecast_exprt::conditional_cast (rhs, lhs.type ())});
272304}
273305
274306irep_idt get_string_argument_rec (const exprt &src)
0 commit comments