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