14
14
#include < util/arith_tools.h>
15
15
#include < util/c_types.h>
16
16
#include < util/expr_initializer.h>
17
+ #include < util/expr_util.h>
18
+ #include < util/fresh_symbol.h>
17
19
#include < util/invariant_utils.h>
18
20
#include < util/optional.h>
19
21
#include < util/pointer_offset_size.h>
@@ -206,24 +208,44 @@ void goto_symext::symex_allocate(
206
208
code_assignt (lhs, typecast_exprt::conditional_cast (rhs, lhs.type ())));
207
209
}
208
210
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)
210
218
{
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)
214
226
{
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)};
221
240
}
222
241
else
223
- return irep_idt ();
242
+ {
243
+ return typecast_exprt::conditional_cast (
244
+ address_of_exprt{std::move (parameter_expr)}, void_ptr_type);
245
+ }
224
246
}
225
247
226
- void goto_symext::symex_gcc_builtin_va_arg_next (
248
+ void goto_symext::symex_va_start (
227
249
statet &state,
228
250
const exprt &lhs,
229
251
const side_effect_exprt &code)
@@ -233,42 +255,52 @@ void goto_symext::symex_gcc_builtin_va_arg_next(
233
255
if (lhs.is_nil ())
234
256
return ; // ignore
235
257
236
- // to allow constant propagation
237
- exprt tmp = state.rename (code.op0 (), ns);
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 ();
244
264
245
- if (!id.empty ())
265
+ exprt::operandst va_arg_operands;
266
+ bool parameter_id_found = false ;
267
+ for (auto ¶meter : state.top ().parameter_names )
246
268
{
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)
250
270
{
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 ;
268
273
}
269
- }
270
274
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);
295
+ do_simplify (array);
296
+ symex_assign (state, code_assignt{va_array.symbol_expr (), std::move (array)});
297
+
298
+ address_of_exprt rhs{
299
+ index_exprt{va_array.symbol_expr (), from_integer (0 , index_type ())}};
300
+ state.rename (rhs, ns);
301
+ symex_assign (
302
+ state,
303
+ code_assignt{lhs, typecast_exprt::conditional_cast (rhs, lhs.type ())});
272
304
}
273
305
274
306
irep_idt get_string_argument_rec (const exprt &src)
0 commit comments