@@ -181,6 +181,10 @@ bool goto_symext::constant_propagate_assignment_with_side_effects(
181
181
constant_propagate_empty_string (state, symex_assign, f_l1);
182
182
return true ;
183
183
}
184
+ else if (func_id == ID_cprover_string_substring_func)
185
+ {
186
+ return constant_propagate_string_substring (state, symex_assign, f_l1);
187
+ }
184
188
}
185
189
}
186
190
@@ -310,6 +314,26 @@ goto_symext::try_evaluate_constant_string(
310
314
return try_get_string_data_array (s_pointer_opt->get (), ns);
311
315
}
312
316
317
+ optionalt<std::reference_wrapper<const constant_exprt>>
318
+ goto_symext::try_evaluate_constant (const statet &state, const exprt &expr)
319
+ {
320
+ if (expr.id () != ID_symbol)
321
+ {
322
+ return {};
323
+ }
324
+
325
+ const auto constant_expr_opt =
326
+ state.propagation .find (to_symbol_expr (expr).get_identifier ());
327
+
328
+ if (!constant_expr_opt || constant_expr_opt->get ().id () != ID_constant)
329
+ {
330
+ return {};
331
+ }
332
+
333
+ return optionalt<std::reference_wrapper<const constant_exprt>>(
334
+ to_constant_expr (constant_expr_opt->get ()));
335
+ }
336
+
313
337
void goto_symext::constant_propagate_empty_string (
314
338
statet &state,
315
339
symex_assignt &symex_assign,
@@ -387,3 +411,90 @@ bool goto_symext::constant_propagate_string_concat(
387
411
388
412
return true ;
389
413
}
414
+
415
+ bool goto_symext::constant_propagate_string_substring (
416
+ statet &state,
417
+ symex_assignt &symex_assign,
418
+ const function_application_exprt &f_l1)
419
+ {
420
+ const std::size_t num_operands = f_l1.arguments ().size ();
421
+
422
+ PRECONDITION (num_operands >= 4 );
423
+ PRECONDITION (num_operands <= 5 );
424
+
425
+ const auto &f_type = to_mathematical_function_type (f_l1.function ().type ());
426
+ const auto &length_type = f_type.domain ().at (0 );
427
+ const auto &char_type = to_pointer_type (f_type.domain ().at (1 )).subtype ();
428
+
429
+ const refined_string_exprt &s = to_string_expr (f_l1.arguments ().at (2 ));
430
+ const auto s_data_opt = try_evaluate_constant_string (state, s.content ());
431
+
432
+ if (!s_data_opt)
433
+ return false ;
434
+
435
+ const array_exprt &s_data = s_data_opt->get ();
436
+
437
+ mp_integer end_index;
438
+
439
+ if (num_operands == 5 )
440
+ {
441
+ const auto end_index_expr_opt =
442
+ try_evaluate_constant (state, f_l1.arguments ().at (4 ));
443
+
444
+ if (!end_index_expr_opt)
445
+ {
446
+ return false ;
447
+ }
448
+
449
+ end_index =
450
+ numeric_cast_v<mp_integer>(to_constant_expr (*end_index_expr_opt));
451
+
452
+ if (end_index < 0 || end_index > s_data.operands ().size ())
453
+ {
454
+ return false ;
455
+ }
456
+ }
457
+ else
458
+ {
459
+ end_index = s_data.operands ().size ();
460
+ }
461
+
462
+ const auto start_index_expr_opt =
463
+ try_evaluate_constant (state, f_l1.arguments ().at (3 ));
464
+
465
+ if (!start_index_expr_opt)
466
+ {
467
+ return false ;
468
+ }
469
+
470
+ const mp_integer start_index =
471
+ numeric_cast_v<mp_integer>(to_constant_expr (*start_index_expr_opt));
472
+
473
+ if (start_index < 0 || start_index > end_index)
474
+ {
475
+ return false ;
476
+ }
477
+
478
+ const constant_exprt new_char_array_length =
479
+ from_integer (end_index - start_index, length_type);
480
+
481
+ const array_typet new_char_array_type (char_type, new_char_array_length);
482
+
483
+ exprt::operandst operands (
484
+ std::next (
485
+ s_data.operands ().begin (), numeric_cast_v<std::size_t >(start_index)),
486
+ std::next (
487
+ s_data.operands ().begin (), numeric_cast_v<std::size_t >(end_index)));
488
+
489
+ const array_exprt new_char_array (std::move (operands), new_char_array_type);
490
+
491
+ assign_string_constant (
492
+ state,
493
+ symex_assign,
494
+ to_ssa_expr (f_l1.arguments ().at (0 )),
495
+ new_char_array_length,
496
+ to_ssa_expr (f_l1.arguments ().at (1 )),
497
+ new_char_array);
498
+
499
+ return true ;
500
+ }
0 commit comments