Skip to content

Commit c24ff8a

Browse files
Merge pull request #4868 from jeannielynnmoulton/jeannie/CharacterPrintable
--string-printable option also forces chars to be printable
2 parents 836042f + 27f2894 commit c24ff8a

21 files changed

+271
-12
lines changed
Binary file not shown.

jbmc/regression/strings-smoke-tests/java_string_printable/Test.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,39 @@ public static boolean check_char(String s, char c) {
1818
assert(b);
1919
return b;
2020
}
21+
22+
public static boolean printable_char(char c) {
23+
boolean b = c >= ' ' && c <= '~';
24+
assert(b);
25+
return b;
26+
}
27+
28+
public char charField;
29+
30+
public boolean test_char_field() {
31+
boolean b = charField >= ' ' && charField <= '~';
32+
assert(b);
33+
return b;
34+
}
35+
36+
public static boolean printable_char_array(char[] c) {
37+
if(c.length != 3 || c == null)
38+
return false;
39+
boolean b0 = c[0] >= ' ' && c[0] <= '~';
40+
boolean b1 = c[1] >= ' ' && c[1] <= '~';
41+
boolean b2 = c[2] >= ' ' && c[2] <= '~';
42+
assert(b0 || b1 || b2);
43+
return b0 || b1 || b2;
44+
}
45+
46+
public static char charStaticField = 'a';
47+
48+
public boolean test_char_field_static() {
49+
if(charStaticField == 'a')
50+
return false;
51+
boolean b = charStaticField >= ' ' && charStaticField <= '~';
52+
assert(b);
53+
return b;
54+
}
55+
2156
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
Test.class
3+
--function Test.check_char --max-nondet-string-length 100
4+
VERIFICATION FAILED
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion can be violated when string-printable is not enabled
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FUTURE
2+
Test.class
3+
--function Test.printable_char_array --max-nondet-string-length 100
4+
assertion.* file Test.java line 42 .* FAILURE
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion can be violated when string-printable is not enabled
9+
for character arrays
10+
11+
The constraint has not been implemented for char arrays.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
Test.class
3+
--function Test.test_char_field --max-nondet-string-length 100
4+
VERIFICATION FAILED
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion can be violated when string-printable is not enabled
9+
for character field
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
Test.class
3+
--function Test.test_char_field_static --max-nondet-string-length 100 --nondet-static
4+
VERIFICATION FAILED
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion can be violated when string-printable is not enabled
9+
for character static field
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
Test.class
3+
--function Test.check_char --max-nondet-string-length 100 --string-printable
4+
VERIFICATION SUCCESSFUL
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion cannot be violated when string-printable is enabled
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FUTURE
2+
Test.class
3+
--function Test.printable_char_array --max-nondet-string-length 100 --string-printable
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
--
7+
assertion.* file Test.java line 42 .* FAILURE
8+
--
9+
Shows that the assertion can be violated when string-printable is not enabled
10+
for character arrays
11+
12+
The constraint has not been implemented for char arrays.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
Test.class
3+
--function Test.test_char_field --max-nondet-string-length 100 --string-printable
4+
VERIFICATION SUCCESSFUL
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion cannot be violated when string-printable is enabled for
9+
character field
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
Test.class
3+
--function Test.test_char_field_static --max-nondet-string-length 100 --string-printable --nondet-static
4+
VERIFICATION SUCCESSFUL
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
Shows that the assertion cannot be violated when string-printable is enabled for
9+
character static field

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Author: Daniel Kroening, [email protected]
1717

1818
#include <goto-programs/class_identifier.h>
1919
#include <goto-programs/goto_functions.h>
20+
#include <util/interval_constraint.h>
2021

2122
#include "generic_parameter_specialization_map_keys.h"
2223
#include "java_root_class.h"
@@ -303,6 +304,20 @@ class recursion_set_entryt
303304
}
304305
};
305306

307+
/// Interval that represents the printable character range
308+
/// range U+0020-U+007E, i.e. ' ' to '~'
309+
const integer_intervalt printable_char_range(' ', '~');
310+
311+
/// Converts and \ref integer_intervalt to a a string of the for [lower]-[upper]
312+
static irep_idt integer_interval_to_string(const integer_intervalt &interval)
313+
{
314+
std::string result;
315+
result += numeric_cast_v<char>(interval.lower);
316+
result += "-";
317+
result += numeric_cast_v<char>(interval.upper);
318+
return result;
319+
}
320+
306321
/// Initialise length and data fields for a nondeterministic String structure.
307322
///
308323
/// If the structure is not a nondeterministic structure, the call results in
@@ -417,7 +432,13 @@ void initialize_nondet_string_fields(
417432
if(printable)
418433
{
419434
add_character_set_constraint(
420-
array_pointer, length_expr, " -~", symbol_table, loc, function_id, code);
435+
array_pointer,
436+
length_expr,
437+
integer_interval_to_string(printable_char_range),
438+
symbol_table,
439+
loc,
440+
function_id,
441+
code);
421442
}
422443
}
423444

@@ -1039,6 +1060,11 @@ void java_object_factoryt::gen_nondet_init(
10391060
assign.add_source_location() = location;
10401061

10411062
assignments.add(assign);
1063+
if(type == java_char_type() && object_factory_parameters.string_printable)
1064+
{
1065+
assignments.add(
1066+
code_assumet(interval_constraint(expr, printable_char_range)));
1067+
}
10421068
// add assumes to obey numerical restrictions
10431069
if(type != java_boolean_type() && type != java_char_type())
10441070
{

jbmc/src/java_bytecode/java_string_library_preprocess.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ void add_array_to_length_association(
669669
/// belong to the character set.
670670
/// \param pointer: a character pointer expression
671671
/// \param length: length of the character sequence pointed by `pointer`
672-
/// \param char_set: character set given by a range expression consisting of
672+
/// \param char_range: character set given by a range expression consisting of
673673
/// two characters separated by an hyphen. For instance "a-z" denotes all
674674
/// lower case ascii letters.
675675
/// \param symbol_table: the symbol table
@@ -679,7 +679,7 @@ void add_array_to_length_association(
679679
void add_character_set_constraint(
680680
const exprt &pointer,
681681
const exprt &length,
682-
const irep_idt &char_set,
682+
const irep_idt &char_range,
683683
symbol_table_baset &symbol_table,
684684
const source_locationt &loc,
685685
const irep_idt &function_id,
@@ -690,7 +690,7 @@ void add_character_set_constraint(
690690
java_int_type(), "cnstr_added", loc, function_id, symbol_table);
691691
const auto return_expr = return_sym.symbol_expr();
692692
code.add(code_declt(return_expr), loc);
693-
const constant_exprt char_set_expr(char_set, string_typet());
693+
const constant_exprt char_set_expr(char_range, string_typet());
694694
code.add(
695695
code_assign_function_application(
696696
return_expr,

jbmc/src/java_bytecode/java_string_library_preprocess.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ void add_array_to_length_association(
334334
void add_character_set_constraint(
335335
const exprt &pointer,
336336
const exprt &length,
337-
const irep_idt &char_set,
337+
const irep_idt &char_range,
338338
symbol_table_baset &symbol_table,
339339
const source_locationt &loc,
340340
const irep_idt &function_id,

jbmc/src/java_bytecode/module_dependencies.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ langapi # should go away
99
library
1010
linking
1111
miniz
12+
solvers/strings
1213
util

src/solvers/strings/string_constraint_generator_main.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Author: Romain Brenguier, [email protected]
2929
#include <util/simplify_expr.h>
3030
#include <util/ssa_expr.h>
3131
#include <util/string_constant.h>
32+
#include <util/interval_constraint.h>
3233

3334
string_constraint_generatort::string_constraint_generatort(const namespacet &ns)
3435
: array_pool(fresh_symbol), ns(ns)
@@ -139,17 +140,16 @@ string_constraintst add_constraint_on_characters(
139140
// Parse char_set
140141
PRECONDITION(char_set.length() == 3);
141142
PRECONDITION(char_set[1] == '-');
142-
const char &low_char = char_set[0];
143-
const char &high_char = char_set[2];
143+
const integer_intervalt char_range(char_set[0], char_set[2]);
144144

145145
// Add constraint
146146
const symbol_exprt qvar = fresh_symbol("char_constr", s.length_type());
147147
const exprt chr = s[qvar];
148-
const and_exprt char_in_set(
149-
binary_relation_exprt(chr, ID_ge, from_integer(low_char, chr.type())),
150-
binary_relation_exprt(chr, ID_le, from_integer(high_char, chr.type())));
151148
const string_constraintt sc(
152-
qvar, zero_if_negative(start), zero_if_negative(end), char_in_set);
149+
qvar,
150+
zero_if_negative(start),
151+
zero_if_negative(end),
152+
interval_constraint(chr, char_range));
153153
return {{}, {sc}, {}};
154154
}
155155

src/solvers/strings/string_refinement.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Author: Alberto Griggio, [email protected]
4141

4242
#define HELP_STRING_REFINEMENT \
4343
" --no-refine-strings turn off string refinement\n" \
44-
" --string-printable restrict to printable strings (experimental)\n" /* NOLINT(*) */ \
44+
" --string-printable restrict to printable strings and characters\n" /* NOLINT(*) */ \
4545
" --string-non-empty restrict to non-empty strings (experimental)\n" /* NOLINT(*) */ \
4646
" --string-input-value st restrict non-null strings to a fixed value st;\n" /* NOLINT(*) */ \
4747
" the switch can be used multiple times to give\n" /* NOLINT(*) */ \

src/util/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ SRC = allocate_objects.cpp \
3434
irep_hash_container.cpp \
3535
irep_ids.cpp \
3636
irep_serialization.cpp \
37+
interval_constraint.cpp \
3738
invariant_utils.cpp \
3839
json.cpp \
3940
json_irep.cpp \

src/util/interval_constraint.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*******************************************************************\
2+
3+
Module: Interval constraint
4+
5+
Author: Jeannie Moulton
6+
7+
\*******************************************************************/
8+
9+
#include "interval_constraint.h"
10+
#include "arith_tools.h"
11+
12+
exprt interval_constraint(const exprt &expr, const integer_intervalt &interval)
13+
{
14+
// expr >= lower_bound && expr <= upper_bound
15+
return and_exprt(
16+
binary_relation_exprt(
17+
expr, ID_ge, from_integer(interval.lower, expr.type())),
18+
binary_relation_exprt(
19+
expr, ID_le, from_integer(interval.upper, expr.type())));
20+
}

src/util/interval_constraint.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*******************************************************************\
2+
3+
Module: Interval constraint
4+
5+
Author: Jeannie Moulton
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_UTIL_INTERVAL_CONSTRAINT_H
10+
#define CPROVER_UTIL_INTERVAL_CONSTRAINT_H
11+
12+
#include "integer_interval.h"
13+
14+
class exprt;
15+
16+
/// Given an exprt and an integer interval return an exprt that represents
17+
/// restricting the expression to the range in the interval (inclusive).
18+
exprt interval_constraint(const exprt &expr, const integer_intervalt &interval);
19+
20+
#endif // CPROVER_UTIL_INTERVAL_CONSTRAINT_H

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ SRC += analyses/ai/ai.cpp \
6868
util/format_number_range.cpp \
6969
util/get_base_name.cpp \
7070
util/graph.cpp \
71+
util/interval_constraint.cpp \
7172
util/irep.cpp \
7273
util/irep_sharing.cpp \
7374
util/json_array.cpp \

unit/util/interval_constraint.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for interval_constraint in
4+
util/interval_constraint.cpp
5+
6+
Author: Diffblue Ltd.
7+
8+
\*******************************************************************/
9+
10+
#include <testing-utils/use_catch.h>
11+
12+
#include <util/interval_constraint.h>
13+
#include <util/std_expr.h>
14+
#include <util/std_types.h>
15+
16+
SCENARIO(
17+
"interval_constraint with characters",
18+
"[core][util][interval_constraint]")
19+
{
20+
GIVEN("A string representing a character range and an character expression")
21+
{
22+
const integer_intervalt char_range('a', 'z');
23+
const exprt expr{"dummy", unsignedbv_typet(16)};
24+
25+
WHEN("interval_constraint is called")
26+
{
27+
const auto result = interval_constraint(expr, char_range);
28+
29+
THEN(
30+
"expect that the result is an and_exprt with two inequality "
31+
"expressions representing a <= expr && expr <= z")
32+
{
33+
REQUIRE(can_cast_expr<and_exprt>(result));
34+
35+
REQUIRE(result.op0().id() == ID_ge);
36+
REQUIRE(result.op0().op0().type() == unsignedbv_typet(16));
37+
REQUIRE(can_cast_expr<constant_exprt>(result.op0().op1()));
38+
REQUIRE(to_constant_expr(result.op0().op1()).get_value() == "61"); // a
39+
40+
REQUIRE(result.op1().id() == ID_le);
41+
REQUIRE(result.op1().op0().type() == unsignedbv_typet(16));
42+
REQUIRE(can_cast_expr<constant_exprt>(result.op1().op1()));
43+
REQUIRE(to_constant_expr(result.op1().op1()).get_value() == "7A"); // b
44+
}
45+
}
46+
}
47+
}
48+
49+
SCENARIO(
50+
"interval_constraint with integers",
51+
"[core][util][interval_constraint]")
52+
{
53+
GIVEN("A string representing a int range and an int expression")
54+
{
55+
const integer_intervalt int_range(6, 9);
56+
const exprt expr{"dummy", unsignedbv_typet(32)};
57+
58+
WHEN("interval_constraint is called")
59+
{
60+
const auto result = interval_constraint(expr, int_range);
61+
62+
THEN(
63+
"expect that the result is an and_exprt with two inequality "
64+
"expressions representing 6 <= expr && expr <= 9")
65+
{
66+
REQUIRE(can_cast_expr<and_exprt>(result));
67+
68+
REQUIRE(result.op0().id() == ID_ge);
69+
REQUIRE(result.op0().op0().type() == unsignedbv_typet(32));
70+
REQUIRE(can_cast_expr<constant_exprt>(result.op0().op1()));
71+
REQUIRE(to_constant_expr(result.op0().op1()).get_value() == "6");
72+
73+
REQUIRE(result.op1().id() == ID_le);
74+
REQUIRE(result.op1().op0().type() == unsignedbv_typet(32));
75+
REQUIRE(can_cast_expr<constant_exprt>(result.op1().op1()));
76+
REQUIRE(to_constant_expr(result.op1().op1()).get_value() == "9");
77+
}
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)