Skip to content

Commit c9b6c42

Browse files
Merge pull request #1513 from romainbrenguier/feature/input-string-printable
Input string printable TG-808
2 parents c4486f1 + d2c3752 commit c9b6c42

File tree

15 files changed

+170
-21
lines changed

15 files changed

+170
-21
lines changed
Binary file not shown.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
public class Test {
2+
3+
public static String check(String t) {
4+
String s = t.concat("$£¥\u0000\u0008\u0010\u001F");
5+
// This should be disallowed because "\u0000" is not printable
6+
assert(!s.equals("\u0000$£¥\u0000\u0008\u0010\u001F"));
7+
// This can fail when t="a" which is printable
8+
assert(!s.equals("a$£¥\u0000\u0008\u0010\u001F"));
9+
return s;
10+
}
11+
12+
public static boolean check_char(String s, char c) {
13+
if(s == null)
14+
return false;
15+
// This should be -1 for all non-printable character
16+
int i = s.indexOf(c);
17+
boolean b = (i == -1 || (c >= ' ' && c <= '~'));
18+
assert(b);
19+
return b;
20+
}
21+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
Test.class
3+
--refine-strings --function Test.check --string-max-length 100 --string-printable --java-assume-inputs-non-null
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion.* file Test.java line 6 .* SUCCESS
7+
assertion.* file Test.java line 8 .* FAILURE
8+
--
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
Test.class
3+
--refine-strings --function Test.check_char --string-max-length 100 --string-printable
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
assertion.* file Test.java line 18 .* SUCCESS
7+
--

src/cbmc/cbmc_solvers.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ std::unique_ptr<cbmc_solverst::solvert> cbmc_solverst::get_string_refinement()
180180
info.string_max_length=options.get_signed_int_option("string-max-length");
181181
info.string_non_empty=options.get_bool_option("string-non-empty");
182182
info.trace=options.get_bool_option("trace");
183-
info.string_printable=options.get_bool_option("string-printable");
184183
if(options.get_bool_option("max-node-refinement"))
185184
info.max_node_refinement=
186185
options.get_unsigned_int_option("max-node-refinement");

src/java_bytecode/java_bytecode_language.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ void java_bytecode_languaget::get_language_options(const cmdlinet &cmd)
5151
if(cmd.isset("string-max-input-length"))
5252
object_factory_parameters.max_nondet_string_length=
5353
std::stoi(cmd.get_value("string-max-input-length"));
54+
object_factory_parameters.string_printable = cmd.isset("string-printable");
5455
if(cmd.isset("java-max-vla-length"))
5556
max_user_array_length=std::stoi(cmd.get_value("java-max-vla-length"));
5657
if(cmd.isset("lazy-methods-context-sensitive"))

src/java_bytecode/java_bytecode_language.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ struct object_factory_parameterst final
7575
/// dereference a pointer using a 'depth counter'. We set a pointer to null if
7676
/// such depth becomes >= than this maximum value.
7777
size_t max_nondet_tree_depth=MAX_NONDET_TREE_DEPTH;
78+
79+
/// Force string content to be ASCII printable characters when set to true.
80+
bool string_printable = false;
7881
};
7982

8083
typedef std::pair<

src/java_bytecode/java_object_factory.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,8 @@ codet initialize_nondet_string_struct(
542542
const exprt &obj,
543543
const std::size_t &max_nondet_string_length,
544544
const source_locationt &loc,
545-
symbol_tablet &symbol_table)
545+
symbol_tablet &symbol_table,
546+
bool printable)
546547
{
547548
PRECONDITION(
548549
java_string_library_preprocesst::implements_java_char_sequence(obj.type()));
@@ -605,6 +606,13 @@ codet initialize_nondet_string_struct(
605606

606607
add_array_to_length_association(
607608
data_expr, length_expr, symbol_table, loc, code);
609+
610+
// Printable ASCII characters are between ' ' and '~'.
611+
if(printable)
612+
{
613+
add_character_set_constraint(
614+
array_pointer, length_expr, " -~", symbol_table, loc, code);
615+
}
608616
}
609617

610618
// tmp_object = struct_expr;
@@ -616,6 +624,7 @@ codet initialize_nondet_string_struct(
616624
/// content and association of its address to the pointer `expr`.
617625
/// \param expr: pointer to be affected
618626
/// \param max_nondet_string_length: maximum length of strings to initialize
627+
/// \param printable: Boolean, true to force content to be printable
619628
/// \param symbol_table: the symbol table
620629
/// \param loc: location in the source
621630
/// \param [out] code: code block in which initialization code is added
@@ -625,6 +634,7 @@ codet initialize_nondet_string_struct(
625634
static bool add_nondet_string_pointer_initialization(
626635
const exprt &expr,
627636
const std::size_t &max_nondet_string_length,
637+
bool printable,
628638
symbol_tablet &symbol_table,
629639
const source_locationt &loc,
630640
code_blockt &code)
@@ -644,7 +654,8 @@ static bool add_nondet_string_pointer_initialization(
644654
dereference_exprt(expr, struct_type),
645655
max_nondet_string_length,
646656
loc,
647-
symbol_table));
657+
symbol_table,
658+
printable));
648659
return false;
649660
}
650661

@@ -784,6 +795,7 @@ void java_object_factoryt::gen_nondet_pointer_init(
784795
add_nondet_string_pointer_initialization(
785796
expr,
786797
object_factory_parameters.max_nondet_string_length,
798+
object_factory_parameters.string_printable,
787799
symbol_table,
788800
loc,
789801
assignments);

src/java_bytecode/java_object_factory.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ codet initialize_nondet_string_struct(
156156
const exprt &obj,
157157
const std::size_t &max_nondet_string_length,
158158
const source_locationt &loc,
159-
symbol_tablet &symbol_table);
159+
symbol_tablet &symbol_table,
160+
bool printable);
160161

161162
#endif // CPROVER_JAVA_BYTECODE_JAVA_OBJECT_FACTORY_H

src/java_bytecode/java_string_library_preprocess.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,38 @@ void add_array_to_length_association(
704704
symbol_table));
705705
}
706706

707+
/// Add a call to a primitive of the string solver which ensures all characters
708+
/// belong to the character set.
709+
/// \param pointer: a character pointer expression
710+
/// \param length: length of the character sequence pointed by `pointer`
711+
/// \param char_set: character set given by a range expression consisting of
712+
/// two characters separated by an hyphen.
713+
/// For instance "a-z" denotes all lower case ascii letters.
714+
/// \param symbol_table: the symbol table
715+
/// \param loc: source location
716+
/// \param code [out] : code block to which declaration and calls get added
717+
void add_character_set_constraint(
718+
const exprt &pointer,
719+
const exprt &length,
720+
const irep_idt &char_set,
721+
symbol_tablet &symbol_table,
722+
const source_locationt &loc,
723+
code_blockt &code)
724+
{
725+
PRECONDITION(pointer.type().id() == ID_pointer);
726+
symbolt &return_sym = get_fresh_aux_symbol(
727+
java_int_type(), "cnstr_added", "cnstr_added", loc, ID_java, symbol_table);
728+
const exprt return_expr = return_sym.symbol_expr();
729+
code.add(code_declt(return_expr));
730+
const constant_exprt char_set_expr(char_set, string_typet());
731+
code.add(
732+
code_assign_function_application(
733+
return_expr,
734+
ID_cprover_string_constrain_characters_func,
735+
{length, pointer, char_set_expr},
736+
symbol_table));
737+
}
738+
707739
/// Create a refined_string_exprt `str` whose content and length are fresh
708740
/// symbols, calls the string primitive with name `function_name`.
709741
/// In the arguments of the primitive `str` takes the place of the result and

0 commit comments

Comments
 (0)