Skip to content

Improve length handling in string preprocessing #994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions regression/strings-smoke-tests/java_length/test.desc
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
CORE
test_length.class
--refine-strings
^EXIT=0$
^EXIT=10$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
^VERIFICATION FAILED$
[.*assertion.1] .* line 7 .*: SUCCESS
[.*assertion.2] .* line 8 .*: FAILURE
--
Binary file modified regression/strings-smoke-tests/java_length/test_length.class
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public static void main(/*String[] argv*/)
String s = new String("Abc");
int l = s.length();
assert(l == 3);
assert(l != 3);
}
}
Binary file not shown.
10 changes: 10 additions & 0 deletions regression/strings-smoke-tests/java_length2/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FUTURE
test.class
--refine-strings --function test.check
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
This test currently fails because we do not handle the case where the argument
's' is null. This should be handled in the String model.
The issue number for that is: diffblue/test-gen#500
12 changes: 12 additions & 0 deletions regression/strings-smoke-tests/java_length2/test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
public class test
{
public static int check(String s)
{
if(s.equals("abc")){
assert s.length() == 3;
return 0;
}
return 1;
}
}

77 changes: 66 additions & 11 deletions src/java_bytecode/java_string_library_preprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1024,8 +1024,8 @@ Function: java_string_library_preprocesst::
Output: return the following code:
> lhs = { {Object}, length=rhs_length, data=rhs_array }

Purpose: Produce code for an assignemnrt of a string expr to a
Java string, component-wise.
Purpose: Produce code for an assignment of a string expr to a
Java string.

\*******************************************************************/

Expand Down Expand Up @@ -1864,8 +1864,7 @@ codet java_string_library_preprocesst::make_copy_string_code(

/*******************************************************************\

Function:
java_string_library_preprocesst::make_copy_constructor_code
Function: java_string_library_preprocesst::make_copy_constructor_code

Inputs:
type - type of the function
Expand Down Expand Up @@ -1913,6 +1912,52 @@ codet java_string_library_preprocesst::make_copy_constructor_code(

/*******************************************************************\

Function: java_string_library_preprocesst::make_string_length_code

Inputs:
type - type of the function
loc - location in the source
symbol_table - symbol table

Outputs: Code corresponding to:
> str_expr = java_string_to_string_expr(this)
> str_expr_sym = str_expr
> return this->length

Purpose: Generates code for the String.length method

\*******************************************************************/

codet java_string_library_preprocesst::make_string_length_code(
const code_typet &type,
const source_locationt &loc,
symbol_tablet &symbol_table)
{
// Code for the output
code_blockt code;

code_typet::parameterst params=type.parameters();
symbol_exprt arg_this(params[0].get_identifier(), params[0].type());
dereference_exprt deref(arg_this, arg_this.type().subtype());

// Create a new string_exprt to be picked up by the solver
string_exprt str_expr=fresh_string_expr(loc, symbol_table, code);

// Assign this to str_expr
code.add(
code_assign_java_string_to_string_expr(str_expr, arg_this, symbol_table));

// Assign str_expr to str_expr_sym for that expression to be present in the
// symbol table in order to be processed by the string solver
exprt str_expr_sym=fresh_string_expr_symbol(loc, symbol_table, code);
code.add(code_assignt(str_expr_sym, str_expr));
code.add(code_returnt(get_length(deref, symbol_table)));

return code;
}

/*******************************************************************\

Function: java_string_library_preprocesst::code_for_function

Inputs:
Expand Down Expand Up @@ -2112,9 +2157,14 @@ void java_string_library_preprocesst::initialize_conversion_table()
cprover_equivalent_to_java_function
["java::java.lang.String.lastIndexOf:(Ljava/lang/String;I)I"]=
ID_cprover_string_last_index_of_func;
cprover_equivalent_to_java_function
conversion_table
["java::java.lang.String.length:()I"]=
ID_cprover_string_length_func;
std::bind(
&java_string_library_preprocesst::make_string_length_code,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3);
// Not supported "java.lang.String.matches"
cprover_equivalent_to_java_function
["java::java.lang.String.offsetByCodePoints:(II)I"]=
Expand Down Expand Up @@ -2307,9 +2357,9 @@ void java_string_library_preprocesst::initialize_conversion_table()
"Ljava/lang/StringBuilder;"]=
ID_cprover_string_insert_func;
// Not supported "java.lang.StringBuilder.lastIndexOf"
cprover_equivalent_to_java_function
conversion_table
["java::java.lang.StringBuilder.length:()I"]=
ID_cprover_string_length_func;
conversion_table["java::java.lang.String.length:()I"];
// Not supported "java.lang.StringBuilder.offsetByCodePoints"
// Not supported "java.lang.StringBuilder.replace"
// Not supported "java.lang.StringBuilder.reverse"
Expand Down Expand Up @@ -2434,9 +2484,9 @@ void java_string_library_preprocesst::initialize_conversion_table()
"Ljava/lang/StringBuffer;"]=
ID_cprover_string_insert_func;
// Not supported "java.lang.StringBuffer.lastIndexOf"
cprover_equivalent_to_java_function
conversion_table
["java::java.lang.StringBuffer.length:()I"]=
ID_cprover_string_length_func;
conversion_table["java::java.lang.String.length:()I"];
// Not supported "java.lang.StringBuffer.offsetByCodePoints"
// Not supported "java.lang.StringBuffer.replace"
// Not supported "java.lang.StringBuffer.reverse"
Expand All @@ -2463,7 +2513,7 @@ void java_string_library_preprocesst::initialize_conversion_table()
std::placeholders::_3);
// Not supported "java.lang.StringBuffer.trimToSize"

// Other libraries
// CharSequence library
cprover_equivalent_to_java_function
["java::java.lang.CharSequence.charAt:(I)C"]=
ID_cprover_string_char_at_func;
Expand All @@ -2475,6 +2525,11 @@ void java_string_library_preprocesst::initialize_conversion_table()
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3);
conversion_table
["java::java.lang.CharSequence.length:()I"]=
conversion_table["java::java.lang.String.length:()I"];

// Other libraries
conversion_table
["java::java.lang.Float.toString:(F)Ljava/lang/String;"]=
std::bind(
Expand Down
5 changes: 5 additions & 0 deletions src/java_bytecode/java_string_library_preprocess.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ class java_string_library_preprocesst:public messaget
const source_locationt &loc,
symbol_tablet &symbol_table);

codet make_string_length_code(
const code_typet &type,
const source_locationt &loc,
symbol_tablet &symbol_table);

// Auxiliary functions
codet code_for_scientific_notation(
const exprt &arg,
Expand Down