@@ -340,7 +340,16 @@ Function: string_refinementt::concretize_string
340
340
341
341
Purpose: If the expression is of type string, then adds constants
342
342
to the index set to force the solver to pick concrete values
343
- for each character, and fill the map `found_length`
343
+ for each character, and fill the maps `found_length` and
344
+ `found_content`.
345
+
346
+ The way this is done is by looking for the length of the string,
347
+ then for each `i` in the index set, look at the value found by
348
+ the solver and put it in the `result` table.
349
+ For indexes that are not present in the index set, we put the
350
+ same value as the next index that is present in the index set.
351
+ We do so by traversing the array backward, remembering the
352
+ last value that has been initialized.
344
353
345
354
\*******************************************************************/
346
355
@@ -357,29 +366,55 @@ void string_refinementt::concretize_string(const exprt &expr)
357
366
if (!to_integer (length, found_length))
358
367
{
359
368
assert (found_length.is_long ());
360
- if (found_length<0 )
361
- {
362
- // Lengths should not be negative.
363
- // TODO: Add constraints no the sign of string lengths.
364
- debug () << " concretize_results: WARNING found length is negative"
365
- << eom;
366
- }
367
- else
369
+ assert (found_length>=0 );
370
+ assert (found_length.to_long ()<=generator.max_string_length );
371
+ size_t concretize_limit=found_length.to_long ();
372
+ exprt content_expr=str.content ();
373
+ std::vector<exprt> result;
374
+
375
+ if (index_set[str.content ()].empty ())
376
+ return ;
377
+
378
+ // Use the last index as the default character value
379
+ exprt last_concretized=simplify_expr (
380
+ get (str[minus_exprt (length, from_integer (1 , length.type ()))]), ns);
381
+ result.resize (concretize_limit, last_concretized);
382
+
383
+ // Keep track of the indexes for which we have actual values
384
+ std::set<size_t > initialized;
385
+
386
+ for (const auto &i : index_set[str.content ()])
368
387
{
369
- size_t concretize_limit=found_length.to_long ();
370
- assert (concretize_limit<=generator.max_string_length );
371
- concretize_limit=concretize_limit>generator.max_string_length ?
372
- generator.max_string_length :concretize_limit;
373
- exprt content_expr=str.content ();
374
- for (size_t i=0 ; i<concretize_limit; ++i)
388
+ mp_integer mp_index;
389
+ exprt simple_i=simplify_expr (get (i), ns);
390
+ if (to_integer (simple_i, mp_index) ||
391
+ mp_index<0 ||
392
+ mp_index>=concretize_limit)
375
393
{
376
- auto i_expr=from_integer (i, str.length ().type ());
377
- debug () << " Concretizing " << from_expr (content_expr)
378
- << " / " << i << eom;
379
- current_index_set[str.content ()].insert (i_expr);
380
- index_set[str.content ()].insert (i_expr);
394
+ debug () << " concretize_string: ignoring out of bound index: "
395
+ << from_expr (simple_i) << eom;
396
+ }
397
+ else
398
+ {
399
+ // Add an entry in the result vector
400
+ size_t index =mp_index.to_long ();
401
+ exprt str_i=simplify_expr (str[simple_i], ns);
402
+ exprt value=simplify_expr (get (str_i), ns);
403
+ result[index ]=value;
404
+ initialized.insert (index );
381
405
}
382
406
}
407
+
408
+ // Pad the concretized values to the left to assign the uninitialized
409
+ // values of result. The indices greater than concretize_limit are
410
+ // already assigned to last_concretized.
411
+ pad_vector (result, initialized, last_concretized);
412
+
413
+ array_exprt arr (to_array_type (content.type ()));
414
+ arr.operands ()=result;
415
+ debug () << " Concretized " << from_expr (content_expr)
416
+ << " = " << from_expr (arr) << eom;
417
+ found_content[content]=arr;
383
418
}
384
419
}
385
420
}
@@ -574,6 +609,9 @@ decision_proceduret::resultt string_refinementt::dec_solve()
574
609
}
575
610
}
576
611
612
+ found_length.clear ();
613
+ found_content.clear ();
614
+
577
615
initial_index_set (universal_axioms);
578
616
update_index_set (cur);
579
617
cur.clear ();
@@ -613,7 +651,7 @@ decision_proceduret::resultt string_refinementt::dec_solve()
613
651
if (do_concretizing)
614
652
{
615
653
concretize_results ();
616
- do_concretizing= false ;
654
+ return D_SATISFIABLE ;
617
655
}
618
656
else
619
657
{
@@ -769,6 +807,7 @@ exprt string_refinementt::get_array(const exprt &arr, const exprt &size) const
769
807
770
808
if (arr_val.id ()==" array-list" )
771
809
{
810
+ std::set<unsigned > initialized;
772
811
for (size_t i=0 ; i<arr_val.operands ().size ()/2 ; i++)
773
812
{
774
813
exprt index =arr_val.operands ()[i*2 ];
@@ -779,9 +818,14 @@ exprt string_refinementt::get_array(const exprt &arr, const exprt &size) const
779
818
{
780
819
exprt value=arr_val.operands ()[i*2 +1 ];
781
820
to_unsigned_integer (to_constant_expr (value), concrete_array[idx]);
821
+ initialized.insert (idx);
782
822
}
783
823
}
784
824
}
825
+
826
+ // Pad the concretized values to the left to assign the uninitialized
827
+ // values of result.
828
+ pad_vector (concrete_array, initialized, concrete_array[n-1 ]);
785
829
}
786
830
else if (arr_val.id ()==ID_array)
787
831
{
@@ -1803,6 +1847,10 @@ exprt string_refinementt::get(const exprt &expr) const
1803
1847
replace_expr (symbol_resolve, ecopy);
1804
1848
if (is_char_array (ecopy.type ()))
1805
1849
{
1850
+ auto it_content=found_content.find (ecopy);
1851
+ if (it_content!=found_content.end ())
1852
+ return it_content->second ;
1853
+
1806
1854
auto it=found_length.find (ecopy);
1807
1855
if (it!=found_length.end ())
1808
1856
return get_array (ecopy, it->second );
0 commit comments