Skip to content

Commit 8baaadd

Browse files
author
Vojtech Forejt
committed
Add a switch for fixed strings on input
1 parent d7dc967 commit 8baaadd

File tree

9 files changed

+123
-27
lines changed

9 files changed

+123
-27
lines changed
Binary file not shown.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
public class Test {
2+
3+
static void checkStringInputValue(String s) {
4+
if (s.length() == 2)
5+
assert(false);
6+
else if (s.length() == 3)
7+
assert(false);
8+
else if (s.length() == 4)
9+
assert(false);
10+
assert(false);
11+
}
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
Test.class
3+
--verbosity 10 --string-input-value fo --string-input-value barr --function Test.checkStringInputValue
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion.1.*FAILURE
7+
assertion.2.*SUCCESS
8+
assertion.3.*FAILURE
9+
assertion.4.*SUCCESS

jbmc/src/java_bytecode/java_entry_point.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,21 @@ static void java_static_lifetime_init(
131131
code_blockt &code_block=to_code_block(to_code(initialize_symbol.value));
132132
object_factory_parameters.function_id = initialize_symbol.name;
133133

134+
// If there are strings given using --string-input-value, we need to add
135+
// them to the symbol table now, so that they appear in __CPROVER_initialize
136+
// and we can refer to them later when we initialise input values.
137+
for(const auto &val : object_factory_parameters.string_input_values)
138+
{
139+
exprt my_literal(ID_java_string_literal);
140+
my_literal.set(ID_value, val);
141+
// We ignore the return value of the following call, we just need to
142+
// make sure the string is in the symbol table.
143+
get_or_create_string_literal_symbol(
144+
my_literal,
145+
symbol_table,
146+
string_refinement_enabled);
147+
}
148+
134149
// We need to zero out all static variables, or nondet-initialize if they're
135150
// external. Iterate over a copy of the symtab, as its iterators are
136151
// invalidated by object_factory:

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ Author: Daniel Kroening, kroening@kroening.com
1111
#include <util/expr_initializer.h>
1212
#include <util/fresh_symbol.h>
1313
#include <util/nondet_bool.h>
14+
#include <util/nondet.h>
1415
#include <util/pointer_offset_size.h>
1516

1617
#include <goto-programs/class_identifier.h>
1718
#include <goto-programs/goto_functions.h>
1819

1920
#include "generic_parameter_specialization_map_keys.h"
2021
#include "java_root_class.h"
22+
#include "java_string_literals.h"
2123

2224
class java_object_factoryt
2325
{
@@ -1010,37 +1012,74 @@ void java_object_factoryt::gen_nondet_struct_init(
10101012
::implements_java_char_sequence(struct_type);
10111013
bool has_data_length =
10121014
struct_type.has_component("length") && struct_type.has_component("data");
1015+
// following is true if we were not given fixed string input values
1016+
// using --string-input-value
1017+
bool no_input_values =
1018+
object_factory_parameters.string_input_values.empty();
1019+
1020+
if(!is_char_sequence || !has_data_length || no_input_values)
1021+
{ // Either not a string, or user did not specify --string-input-values
1022+
1023+
// Add an initial all-zero write. Most of the fields of this will be
1024+
// overwritten, but it helps to have a whole-structure write that analysis
1025+
// passes can easily recognise leaves no uninitialised state behind.
1026+
1027+
// This code mirrors the `remove_java_new` pass:
1028+
auto initial_object =
1029+
zero_initializer(struct_type, source_locationt(), ns);
1030+
CHECK_RETURN(initial_object.has_value());
1031+
irep_idt qualified_clsid = "java::" + id2string(class_identifier);
1032+
set_class_identifier(
1033+
to_struct_expr(*initial_object), ns, symbol_typet(qualified_clsid));
1034+
1035+
if(is_char_sequence && has_data_length)
1036+
{ // We're dealing with a string
1037+
skip_special_string_fields = true;
1038+
initialize_nondet_string_fields(
1039+
to_struct_expr(*initial_object),
1040+
assignments,
1041+
object_factory_parameters.min_nondet_string_length,
1042+
object_factory_parameters.max_nondet_string_length,
1043+
loc,
1044+
object_factory_parameters.function_id,
1045+
symbol_table,
1046+
object_factory_parameters.string_printable);
1047+
}
1048+
// in the else case we have
1049+
// '!is_char_sequence || !has_data_length'
1050+
// and so we are not dealing with a string
10131051

1014-
// Add an initial all-zero write. Most of the fields of this will be
1015-
// overwritten, but it helps to have a whole-structure write that analysis
1016-
// passes can easily recognise leaves no uninitialised state behind.
1052+
assignments.add(code_assignt(expr, *initial_object));
1053+
}
1054+
else
1055+
{ // We're dealing with a string and we should set fixed input values.
1056+
skip_special_string_fields = true;
10171057

1018-
// This code mirrors the `remove_java_new` pass:
1019-
auto initial_object =
1020-
zero_initializer(struct_type, source_locationt(), ns);
1021-
CHECK_RETURN(initial_object.has_value());
1022-
irep_idt qualified_clsid = "java::" + id2string(class_identifier);
1023-
set_class_identifier(
1024-
to_struct_expr(*initial_object), ns, symbol_typet(qualified_clsid));
1058+
// We create a switch statement where each case is an assignment
1059+
// of one of the fixed input strings to the input variable in question
10251060

1026-
if(is_char_sequence && has_data_length)
1027-
{ // we're dealing with a string
1028-
skip_special_string_fields = true;
1029-
initialize_nondet_string_fields(
1030-
to_struct_expr(*initial_object),
1031-
assignments,
1032-
object_factory_parameters.min_nondet_string_length,
1033-
object_factory_parameters.max_nondet_string_length,
1034-
loc,
1035-
object_factory_parameters.function_id,
1036-
symbol_table,
1037-
object_factory_parameters.string_printable);
1038-
}
1039-
// in the else case we have
1040-
// '!is_char_sequence || !has_data_length'
1041-
// and so we are not dealing with a string
1061+
// the following invariant is due to no_input_values==false
1062+
auto size = object_factory_parameters.string_input_values.size();
1063+
INVARIANT(size > 0, "No string-input-value parameter given");
10421064

1043-
assignments.add(code_assignt(expr, *initial_object));
1065+
alternate_casest cases;
1066+
for(const auto &val : object_factory_parameters.string_input_values)
1067+
{
1068+
exprt name_literal(ID_java_string_literal);
1069+
name_literal.set(ID_value, val);
1070+
symbol_exprt s =
1071+
get_or_create_string_literal_symbol(name_literal, symbol_table, true);
1072+
cases.push_back(code_assignt(expr, s));
1073+
}
1074+
1075+
assignments.add(generate_nondet_switch(
1076+
id2string(object_factory_parameters.function_id),
1077+
cases,
1078+
java_int_type(),
1079+
ID_java,
1080+
loc,
1081+
symbol_table));
1082+
}
10441083
}
10451084

10461085
for(const auto &component : components)

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,22 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
252252
if(cmdline.isset("string-printable"))
253253
options.set_option("string-printable", true);
254254

255+
if(cmdline.isset("string-input-value"))
256+
options.set_option(
257+
"string-input-value",
258+
cmdline.get_values("string-input-value"));
259+
255260
if(cmdline.isset("no-refine-strings") && cmdline.isset("string-printable"))
256261
{
257262
warning() << "--string-printable ignored due to --no-refine-strings" << eom;
258263
}
259264

265+
if(cmdline.isset("no-refine-strings") && cmdline.isset("string-input-value"))
266+
{
267+
warning() << "--string-input-value ignored due to --no-refine-strings"
268+
<< eom;
269+
}
270+
260271
if(
261272
cmdline.isset("no-refine-strings") &&
262273
cmdline.isset("max-nondet-string-length"))

src/solvers/refinement/string_refinement.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ Author: Alberto Griggio, alberto.griggio@gmail.com
3333
#define OPT_STRING_REFINEMENT \
3434
"(no-refine-strings)" \
3535
"(string-printable)" \
36+
"(string-input-value):" \
3637
"(string-non-empty)" \
3738
"(max-nondet-string-length):"
3839

3940
#define HELP_STRING_REFINEMENT \
4041
" --no-refine-strings turn off string refinement\n" \
4142
" --string-printable restrict to printable strings (experimental)\n" /* NOLINT(*) */ \
4243
" --string-non-empty restrict to non-empty strings (experimental)\n" /* NOLINT(*) */ \
44+
" --string-printable st restrict non-null strings to a fixed value(s)\n" /* NOLINT(*) */ \
4345
" --max-nondet-string-length n bound the length of nondet (e.g. input) strings\n" /* NOLINT(*) */
4446

4547
// The integration of the string solver into CBMC is incomplete. Therefore,

src/util/object_factory_parameters.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ void object_factory_parameterst::set(const optionst &options)
3737
{
3838
string_printable = options.get_bool_option("string-printable");
3939
}
40+
if(options.is_set("string-input-value"))
41+
{
42+
string_input_values = options.get_list_option("string-input-value");
43+
}
4044
if(options.is_set("min-nondet-string-length"))
4145
{
4246
min_nondet_string_length =

src/util/object_factory_parameters.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, kroening@kroening.com
1111

1212
#include <cstdint>
1313
#include <limits>
14+
#include <list>
1415

1516
#include <util/irep.h>
1617

@@ -69,6 +70,9 @@ struct object_factory_parameterst
6970
/// Force string content to be ASCII printable characters when set to true.
7071
bool string_printable = false;
7172

73+
/// Force one of finitely many explicitly given input strings
74+
std::list<std::string> string_input_values;
75+
7276
/// Function id, used as a prefix for identifiers of temporaries
7377
irep_idt function_id;
7478

0 commit comments

Comments
 (0)