Skip to content

Commit 1055edc

Browse files
authored
Merge pull request #5060 from smowton/smowton/feature/model-create-array-with-type
Model CProver.createArrayWithType function
2 parents a62c309 + 8f9eb63 commit 1055edc

File tree

14 files changed

+241
-1
lines changed

14 files changed

+241
-1
lines changed
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import org.cprover.CProver;
2+
3+
public class Test {
4+
5+
public static void test() {
6+
7+
String[] strings = new String[5];
8+
9+
Object[] clone = CProver.createArrayWithType(1, strings);
10+
assert clone instanceof String[];
11+
assert clone.length == 1;
12+
assert clone[0] == null;
13+
assert clone instanceof Object[];
14+
assert clone instanceof Integer[]; // Should fail
15+
}
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
Test.class
3+
--function Test.test --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
\[java::Test\.test:\(\)V\.assertion\.1\] line 10 assertion.*: SUCCESS
5+
\[java::Test\.test:\(\)V\.assertion\.2\] line 11 assertion.*: SUCCESS
6+
\[java::Test\.test:\(\)V\.assertion\.3\] line 12 assertion.*: SUCCESS
7+
\[java::Test\.test:\(\)V\.assertion\.4\] line 13 assertion.*: SUCCESS
8+
\[java::Test\.test:\(\)V\.assertion\.5\] line 14 assertion.*: FAILURE
9+
^VERIFICATION FAILED$
10+
^EXIT=10$
11+
^SIGNAL=0$
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import org.cprover.CProver;
2+
3+
public class Test {
4+
5+
public static void test() {
6+
7+
String[] strings = new String[0];
8+
9+
Object[] clone = CProver.createArrayWithType(1, strings);
10+
assert clone instanceof String[];
11+
assert clone.length == 1;
12+
assert clone[0] == null;
13+
assert clone instanceof Object[];
14+
assert clone instanceof Integer[]; // Should fail
15+
}
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
Test.class
3+
--function Test.test --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
\[java::Test\.test:\(\)V\.assertion\.1\] line 10 assertion.*: SUCCESS
5+
\[java::Test\.test:\(\)V\.assertion\.2\] line 11 assertion.*: SUCCESS
6+
\[java::Test\.test:\(\)V\.assertion\.3\] line 12 assertion.*: SUCCESS
7+
\[java::Test\.test:\(\)V\.assertion\.4\] line 13 assertion.*: SUCCESS
8+
\[java::Test\.test:\(\)V\.assertion\.5\] line 14 assertion.*: FAILURE
9+
^VERIFICATION FAILED$
10+
^EXIT=10$
11+
^SIGNAL=0$
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import org.cprover.CProver;
2+
3+
public class Test {
4+
5+
public static void test() {
6+
7+
String[][] stringArrays = new String[1][1];
8+
9+
Object[] clone = CProver.createArrayWithType(1, stringArrays);
10+
assert clone instanceof String[][];
11+
assert clone.length == 1;
12+
assert clone[0] == null;
13+
assert clone instanceof Object[];
14+
assert clone instanceof String[]; // Should fail
15+
}
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
Test.class
3+
--function Test.test --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
\[java::Test\.test:\(\)V\.assertion\.1\] line 10 assertion.*: SUCCESS
5+
\[java::Test\.test:\(\)V\.assertion\.2\] line 11 assertion.*: SUCCESS
6+
\[java::Test\.test:\(\)V\.assertion\.3\] line 12 assertion.*: SUCCESS
7+
\[java::Test\.test:\(\)V\.assertion\.4\] line 13 assertion.*: SUCCESS
8+
\[java::Test\.test:\(\)V\.assertion\.5\] line 14 assertion.*: FAILURE
9+
^VERIFICATION FAILED$
10+
^EXIT=10$
11+
^SIGNAL=0$

jbmc/src/java_bytecode/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ SRC = assignments_from_json.cpp \
44
ci_lazy_methods.cpp \
55
ci_lazy_methods_needed.cpp \
66
convert_java_nondet.cpp \
7+
create_array_with_type_intrinsic.cpp \
78
expr2java.cpp \
89
generic_parameter_specialization_map.cpp \
910
generic_parameter_specialization_map_keys.cpp \
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*******************************************************************\
2+
3+
Module: Implementation of CProver.createArrayWithType intrinsic
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Implementation of CProver.createArrayWithType intrinsic
11+
12+
#include "create_array_with_type_intrinsic.h"
13+
14+
#include <goto-programs/class_identifier.h>
15+
#include <java_bytecode/java_types.h>
16+
#include <util/fresh_symbol.h>
17+
#include <util/namespace.h>
18+
#include <util/symbol_table_base.h>
19+
20+
/// Returns the symbol name for `org.cprover.CProver.createArrayWithType`
21+
irep_idt get_create_array_with_type_name()
22+
{
23+
static irep_idt create_array_with_type_name =
24+
"java::org.cprover.CProver.createArrayWithType:"
25+
"(I[Ljava/lang/Object;)[Ljava/lang/Object;";
26+
return create_array_with_type_name;
27+
}
28+
29+
/// Returns the internal implementation for
30+
/// `org.cprover.CProver.createArrayWithType`. Our implementation copies the
31+
/// internal type information maintained by jbmc that tracks the runtime type
32+
/// of an array object rather than using reflection to achieve similar type
33+
/// cloning.
34+
/// \param function_id: identifier of the function being produced. Currently
35+
/// always `get_create_array_with_type_name()`
36+
/// \param symbol_table: global symbol table
37+
/// \param message_handler: any GOTO program conversion errors are logged here
38+
/// \return new GOTO program body for `org.cprover.CProver.createArrayWithType`.
39+
codet create_array_with_type_body(
40+
const irep_idt &function_id,
41+
symbol_table_baset &symbol_table,
42+
message_handlert &message_handler)
43+
{
44+
// Replace CProver.createArrayWithType, which uses reflection to copy the
45+
// type but not the content of a given array, with a java_new_array statement
46+
// followed by overwriting its element type and dimension, similar to our
47+
// implementation (in java_bytecode_convert_class.cpp) of the
48+
// array[reference].clone() method.
49+
50+
PRECONDITION(function_id == get_create_array_with_type_name());
51+
52+
namespacet ns{symbol_table};
53+
54+
const symbolt &function_symbol =
55+
symbol_table.lookup_ref(get_create_array_with_type_name());
56+
const auto &function_type = to_code_type(function_symbol.type);
57+
const auto &length_argument = function_type.parameters().at(0);
58+
symbol_exprt length_argument_symbol_expr{length_argument.get_identifier(),
59+
length_argument.type()};
60+
const auto &existing_array_argument = function_type.parameters().at(1);
61+
symbol_exprt existing_array_argument_symbol_expr{
62+
existing_array_argument.get_identifier(), existing_array_argument.type()};
63+
64+
symbolt &new_array_symbol = get_fresh_aux_symbol(
65+
function_type.parameters().at(1).type(),
66+
id2string(get_create_array_with_type_name()),
67+
"new_array",
68+
source_locationt(),
69+
ID_java,
70+
symbol_table);
71+
const auto new_array_symbol_expr = new_array_symbol.symbol_expr();
72+
73+
code_blockt code_block;
74+
75+
// Declare new_array temporary:
76+
code_block.add(code_declt(new_array_symbol_expr));
77+
78+
// new_array = new Object[length];
79+
side_effect_exprt new_array_expr{
80+
ID_java_new_array, new_array_symbol.type, source_locationt{}};
81+
new_array_expr.copy_to_operands(length_argument_symbol_expr);
82+
code_block.add(code_assignt(new_array_symbol_expr, new_array_expr));
83+
84+
dereference_exprt existing_array(existing_array_argument_symbol_expr);
85+
dereference_exprt new_array(new_array_symbol_expr);
86+
87+
// new_array.@array_dimensions = existing_array.@array_dimensions
88+
// new_array.@element_class_identifier =
89+
// existing_array.@element_class_identifier
90+
member_exprt old_array_dimension(
91+
existing_array, JAVA_ARRAY_DIMENSION_FIELD_NAME, java_int_type());
92+
member_exprt old_array_element_classid(
93+
existing_array, JAVA_ARRAY_ELEMENT_CLASSID_FIELD_NAME, string_typet());
94+
95+
member_exprt new_array_dimension(
96+
new_array, JAVA_ARRAY_DIMENSION_FIELD_NAME, java_int_type());
97+
member_exprt new_array_element_classid(
98+
new_array, JAVA_ARRAY_ELEMENT_CLASSID_FIELD_NAME, string_typet());
99+
100+
code_block.add(code_assignt(new_array_dimension, old_array_dimension));
101+
code_block.add(
102+
code_assignt(new_array_element_classid, old_array_element_classid));
103+
104+
// return new_array
105+
code_block.add(code_returnt(new_array_symbol_expr));
106+
107+
return std::move(code_block);
108+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*******************************************************************\
2+
3+
Module: Implementation of CProver.createArrayWithType intrinsic
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Implementation of CProver.createArrayWithType intrinsic
11+
12+
#ifndef CPROVER_JAVA_BYTECODE_CREATE_ARRAY_WITH_TYPE_INTRINSIC_H
13+
#define CPROVER_JAVA_BYTECODE_CREATE_ARRAY_WITH_TYPE_INTRINSIC_H
14+
15+
#include <util/message.h>
16+
#include <util/std_code.h>
17+
#include <util/symbol_table_base.h>
18+
19+
irep_idt get_create_array_with_type_name();
20+
21+
codet create_array_with_type_body(
22+
const irep_idt &function_id,
23+
symbol_table_baset &symbol_table,
24+
message_handlert &message_handler);
25+
26+
#endif

jbmc/src/java_bytecode/java_bytecode_language.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Author: Daniel Kroening, [email protected]
2727
#include <goto-programs/class_hierarchy.h>
2828

2929
#include "ci_lazy_methods.h"
30+
#include "create_array_with_type_intrinsic.h"
3031
#include "java_bytecode_concurrency_instrumentation.h"
3132
#include "java_bytecode_convert_class.h"
3233
#include "java_bytecode_convert_method.h"
@@ -740,6 +741,14 @@ bool java_bytecode_languaget::typecheck(
740741
}
741742
}
742743

744+
// Register synthetic method that replaces a real definition if one is
745+
// available:
746+
if(symbol_table.has_symbol(get_create_array_with_type_name()))
747+
{
748+
synthetic_methods[get_create_array_with_type_name()] =
749+
synthetic_method_typet::CREATE_ARRAY_WITH_TYPE;
750+
}
751+
743752
// Now add synthetic classes for every invokedynamic instruction found (it
744753
// makes this easier that all interface types and their methods have been
745754
// created above):
@@ -1209,6 +1218,18 @@ bool java_bytecode_languaget::convert_single_method(
12091218
writable_symbol.value = invokedynamic_synthetic_method(
12101219
function_id, symbol_table, get_message_handler());
12111220
break;
1221+
case synthetic_method_typet::CREATE_ARRAY_WITH_TYPE:
1222+
{
1223+
INVARIANT(
1224+
cmb,
1225+
"CProver.createArrayWithType should only be registered if "
1226+
"we have a real implementation available");
1227+
java_bytecode_initialize_parameter_names(
1228+
writable_symbol, cmb->get().method.local_variable_table, symbol_table);
1229+
writable_symbol.value = create_array_with_type_body(
1230+
function_id, symbol_table, get_message_handler());
1231+
break;
1232+
}
12121233
}
12131234
// Notify lazy methods of static calls made from the newly generated
12141235
// function:

jbmc/src/java_bytecode/synthetic_methods_map.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ enum class synthetic_method_typet
4242
INVOKEDYNAMIC_CAPTURE_CONSTRUCTOR,
4343
/// A generated method for a class capturing the parameters of an
4444
/// invokedynamic instruction
45-
INVOKEDYNAMIC_METHOD
45+
INVOKEDYNAMIC_METHOD,
46+
/// Our internal implementation of CProver.createArrayWithType, which needs to
47+
/// access internal type-id fields
48+
CREATE_ARRAY_WITH_TYPE
4649
};
4750

4851
/// Maps method names on to a synthetic method kind.

0 commit comments

Comments
 (0)