Skip to content

Commit 8bd258e

Browse files
committed
Implement constant propagation of ID_cprover_string_concat_func
This is required to allow constant propagation of StringBuilder.append() and String concatenation with +.
1 parent 1a7a63a commit 8bd258e

File tree

10 files changed

+100
-7
lines changed

10 files changed

+100
-7
lines changed
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class Main {
2+
public void test() {
3+
StringBuilder sb = new StringBuilder("abc");
4+
sb.append("xyz");
5+
String s = sb.toString();
6+
assert s.startsWith("abcxyz");
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
Main.class
3+
--function Main.test --property "java::Main.test:()V.assertion.1"
4+
^Generated [0-9]+ VCC\(s\), 0 remaining after simplification$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class Main {
2+
public void test() {
3+
String s1 = "abc";
4+
String s2 = "xyz";
5+
String s3 = s1 + s2;
6+
assert s3.startsWith("abcxyz");
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
Main.class
3+
--function Main.test --property "java::Main.test:()V.assertion.1"
4+
^Generated [0-9]+ VCC\(s\), 0 remaining after simplification$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--

src/goto-symex/symex_assign.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,55 @@ bool symex_assignt::constant_propagate_empty_string(
444444
return true;
445445
}
446446

447+
bool symex_assignt::constant_propagate_concat(
448+
const function_application_exprt &f_l1,
449+
const function_application_exprt &f_l2)
450+
{
451+
const refined_string_exprt &s1 = to_string_expr(f_l2.arguments().at(2));
452+
const auto s1_data_opt = try_get_string_data_array(s1, ns);
453+
454+
if(!s1_data_opt)
455+
return false;
456+
457+
const array_exprt &s1_data = s1_data_opt->get();
458+
459+
const refined_string_exprt &s2 = to_string_expr(f_l2.arguments().at(3));
460+
const auto s2_data_opt = try_get_string_data_array(s2, ns);
461+
462+
if(!s2_data_opt)
463+
return false;
464+
465+
const array_exprt &s2_data = s2_data_opt->get();
466+
467+
const std::size_t new_size =
468+
s1_data.operands().size() + s2_data.operands().size();
469+
470+
const constant_exprt new_char_array_length =
471+
from_integer(new_size, length_type);
472+
473+
array_typet new_char_array_type(
474+
char_type,
475+
new_char_array_length);
476+
477+
exprt::operandst operands(s1_data.operands());
478+
operands.insert(
479+
operands.end(),
480+
s2_data.operands().begin(),
481+
s2_data.operands().end());
482+
483+
array_exprt new_char_array(
484+
std::move(operands),
485+
new_char_array_type);
486+
487+
assign_constants(
488+
to_ssa_expr(f_l1.arguments().at(0)),
489+
new_char_array_length,
490+
to_ssa_expr(f_l1.arguments().at(1)),
491+
new_char_array);
492+
493+
return true;
494+
}
495+
447496
void symex_assignt::assign_non_struct_symbol(
448497
const ssa_exprt &lhs, // L1
449498
const expr_skeletont &full_lhs,
@@ -493,7 +542,11 @@ void symex_assignt::assign_non_struct_symbol(
493542

494543
int ret = false;
495544

496-
if(func_id == ID_cprover_string_empty_string_func)
545+
if(func_id == ID_cprover_string_concat_func)
546+
{
547+
ret = constant_propagate_concat(f_l1, f_l2);
548+
}
549+
else if(func_id == ID_cprover_string_empty_string_func)
497550
{
498551
ret = constant_propagate_empty_string(f_l1);
499552
}

src/goto-symex/symex_assign.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ class symex_assignt
119119
bool constant_propagate_empty_string(
120120
const function_application_exprt &f_l1);
121121

122+
bool constant_propagate_concat(
123+
const function_application_exprt &f_l1,
124+
const function_application_exprt &f_l2);
125+
122126
void assign_constants(
123127
const ssa_exprt &length,
124128
const constant_exprt &new_length,

src/util/simplify_expr.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,6 @@ struct simplify_expr_cachet
6464
simplify_expr_cachet simplify_expr_cache;
6565
#endif
6666

67-
static optionalt<std::reference_wrapper<const array_exprt>>
68-
try_get_string_data_array(
69-
const refined_string_exprt &s,
70-
const namespacet &ns);
71-
7267
simplify_exprt::resultt<> simplify_exprt::simplify_abs(const abs_exprt &expr)
7368
{
7469
if(expr.op().is_constant())
@@ -1924,7 +1919,7 @@ optionalt<std::string> simplify_exprt::expr2bits(
19241919
/// \return array expression representing the char sequence which forms the
19251920
/// content of the refined string expression, empty optional if the content
19261921
/// cannot be determined
1927-
static optionalt<std::reference_wrapper<const array_exprt>>
1922+
optionalt<std::reference_wrapper<const array_exprt>>
19281923
try_get_string_data_array(
19291924
const refined_string_exprt &s,
19301925
const namespacet &ns)

src/util/simplify_expr.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ Author: Daniel Kroening, [email protected]
1010
#ifndef CPROVER_UTIL_SIMPLIFY_EXPR_H
1111
#define CPROVER_UTIL_SIMPLIFY_EXPR_H
1212

13+
class array_exprt;
1314
class exprt;
1415
class namespacet;
16+
class refined_string_exprt;
17+
18+
#include <util/optional.h>
1519

1620
//
1721
// simplify an expression
@@ -27,4 +31,9 @@ bool simplify(
2731
// this is the preferred interface
2832
exprt simplify_expr(exprt src, const namespacet &ns);
2933

34+
optionalt<std::reference_wrapper<const array_exprt>>
35+
try_get_string_data_array(
36+
const refined_string_exprt &s,
37+
const namespacet &ns);
38+
3039
#endif // CPROVER_UTIL_SIMPLIFY_EXPR_H

0 commit comments

Comments
 (0)