24
24
#include < goto-instrument/cover.h>
25
25
26
26
#include < iostream>
27
+ #include < java-testing-utils/load_java_class.h>
27
28
28
29
void validate_method_removal (
29
30
std::list<goto_programt::instructiont> instructions)
30
31
{
31
32
bool method_removed = true , replacement_nondet_exists = false ;
32
33
33
- // Quick loop to check that our method call has been replaced.
34
+ // Loop over our instructions to make sure the nondet java method call has
35
+ // been removed and that we can find an assignment/return with a nondet
36
+ // as it's right-hand side.
34
37
for (const auto &inst : instructions)
35
38
{
39
+ // Check that our NONDET(<type>) exists on a rhs somewhere.
36
40
if (inst.is_assign ())
37
41
{
38
42
const code_assignt &assignment = to_code_assign (inst.code );
@@ -46,6 +50,21 @@ void validate_method_removal(
46
50
}
47
51
}
48
52
53
+ if (inst.is_return ())
54
+ {
55
+ const code_returnt &ret_expr = to_code_return (inst.code );
56
+ if (ret_expr.return_value ().id () == ID_side_effect)
57
+ {
58
+ const side_effect_exprt &see =
59
+ to_side_effect_expr (ret_expr.return_value ());
60
+ if (see.get_statement () == ID_nondet)
61
+ {
62
+ replacement_nondet_exists = true ;
63
+ }
64
+ }
65
+ }
66
+
67
+ // And check to see that our nondet method call has been removed.
49
68
if (inst.is_function_call ())
50
69
{
51
70
const code_function_callt &function_call =
@@ -71,56 +90,146 @@ void validate_method_removal(
71
90
REQUIRE (replacement_nondet_exists);
72
91
}
73
92
74
- TEST_CASE (
75
- " Load class with a generated java nondet method call, run remove returns "
76
- " both before and after the nondet statements have been removed, check "
77
- " results are as expected." ,
93
+ void load_and_test_method (
94
+ const std::string &method_signature,
95
+ goto_functionst &functions,
96
+ journalling_symbol_tablet &symbol_table)
97
+ {
98
+ // Find the method under test.
99
+ const std::string function_name = " java::Main." + method_signature;
100
+ goto_functionst::goto_functiont &goto_function =
101
+ functions.function_map .at (function_name);
102
+
103
+ goto_model_functiont model_function (
104
+ symbol_table, functions, function_name, goto_function);
105
+
106
+ // Emulate some of the passes that we'd normally do before replace_java_nondet
107
+ // is called.
108
+ remove_instanceof (goto_function, symbol_table, null_message_handler);
109
+
110
+ remove_virtual_functions (model_function);
111
+
112
+ // Then test both situations.
113
+ THEN (
114
+ " Code should work when remove returns is called before "
115
+ " replace_java_nondet." )
116
+ {
117
+ remove_returns (model_function, [](const irep_idt &) { return false ; });
118
+
119
+ replace_java_nondet (model_function);
120
+
121
+ validate_method_removal (goto_function.body .instructions );
122
+ }
123
+
124
+ THEN (
125
+ " Code should work when remove returns is called after "
126
+ " replace_java_nondet." )
127
+ {
128
+ replace_java_nondet (model_function);
129
+
130
+ remove_returns (model_function, [](const irep_idt &) { return false ; });
131
+
132
+ validate_method_removal (goto_function.body .instructions );
133
+ }
134
+ }
135
+
136
+ SCENARIO (
137
+ " Testing replace_java_nondet correctly replaces CProver.nondet method calls." ,
78
138
" [core][java_bytecode][replace_nondet]" )
79
139
{
80
- GIVEN (" A class with a call to CProver.nondetWithoutNull() " )
140
+ GIVEN (" A class that holds nondet calls. " )
81
141
{
82
- symbol_tablet raw_symbol_table = load_java_class (
83
- " Main" , " ./java_bytecode/java_replace_nondet" , " Main.replaceNondet" );
142
+ // Load our main class.
143
+ symbol_tablet raw_symbol_table =
144
+ load_java_class (" Main" , " ./java_bytecode/java_replace_nondet" );
84
145
85
146
journalling_symbol_tablet symbol_table =
86
147
journalling_symbol_tablet::wrap (raw_symbol_table);
87
148
149
+ // Convert bytecode into goto.
88
150
goto_functionst functions;
89
151
goto_convert (symbol_table, functions, null_message_handler);
90
152
91
- const std::string function_name = " java::Main.replaceNondet:()V" ;
92
- goto_functionst::goto_functiont &goto_function =
93
- functions.function_map .at (function_name);
94
-
95
- goto_model_functiont model_function (
96
- symbol_table, functions, function_name, goto_function);
97
-
98
- remove_instanceof (goto_function, symbol_table, null_message_handler);
99
-
100
- remove_virtual_functions (model_function);
101
-
102
- WHEN (" Remove returns is called before java nondet." )
153
+ WHEN (" A method assigns a local Object variable with nondetWithoutNull." )
103
154
{
104
- remove_returns (model_function, [](const irep_idt &) { return false ; });
155
+ load_and_test_method (
156
+ " replaceNondetAssignment:()V" , functions, symbol_table);
157
+ }
105
158
106
- replace_java_nondet (functions);
159
+ WHEN (
160
+ " A method assigns an Integer variable with nondetWithoutNull. Causes "
161
+ " implicit cast." )
162
+ {
163
+ load_and_test_method (
164
+ " replaceNondetAssignmentImplicitCast:()V" , functions, symbol_table);
165
+ }
107
166
108
- THEN (" The nondet method call should have been removed." )
109
- {
110
- validate_method_removal (goto_function.body .instructions );
111
- }
167
+ WHEN (
168
+ " A method assigns an Integer variable with nondetWithoutNull. Uses "
169
+ " explicit cast." )
170
+ {
171
+ load_and_test_method (
172
+ " replaceNondetAssignmentExplicitCast:()V" , functions, symbol_table);
112
173
}
113
174
114
- WHEN (" Remove returns is called after java nondet ." )
175
+ WHEN (" A method directly returns a nonDetWithoutNull of type Object ." )
115
176
{
116
- replace_java_nondet (functions);
177
+ load_and_test_method (
178
+ " replaceNondetReturn:()Ljava/lang/Object;" , functions, symbol_table);
179
+ }
117
180
118
- remove_returns (model_function, [](const irep_idt &) { return false ; });
181
+ WHEN (
182
+ " A method directly returns a nonDetWithoutNull of type Integer. Causes "
183
+ " implicit cast." )
184
+ {
185
+ load_and_test_method (
186
+ " replaceNondetReturnWithImplicitCast:()Ljava/lang/Integer;" ,
187
+ functions,
188
+ symbol_table);
189
+ }
119
190
120
- THEN (" The nondet method call should have been removed." )
121
- {
122
- validate_method_removal (goto_function.body .instructions );
123
- }
191
+ WHEN (
192
+ " A method directly returns a nonDetWithoutNull of type Integer. Uses "
193
+ " explicit cast." )
194
+ {
195
+ load_and_test_method (
196
+ " replaceNondetReturnWithExplicitCast:()Ljava/lang/Integer;" ,
197
+ functions,
198
+ symbol_table);
124
199
}
200
+
201
+ // These currently cause an abort, issue detailed in https://github.com/diffblue/cbmc/issues/2281.
202
+
203
+ // WHEN(
204
+ // "A method directly returns a nonDetWithoutNull +3 with explicit int cast.")
205
+ // {
206
+ // load_and_test_method("replaceNondetReturnAddition:()Ljava/lang/Integer;", functions, symbol_table);
207
+ // }
208
+
209
+ // WHEN(
210
+ // "A method assigns an int variable with nondetWithoutNull. Causes "
211
+ // "unboxing.")
212
+ // {
213
+ // load_and_test_method("replaceNondetAssignmentUnbox:()V", functions, symbol_table);
214
+ // }
215
+
216
+ // WHEN(
217
+ // "A method assigns an int variable with nondetWithoutNull +3 with explicit cast.")
218
+ // {
219
+ // load_and_test_method("replaceNondetAssignmentAddition:()V", functions, symbol_table);
220
+ // }
221
+
222
+ // WHEN(
223
+ // "A method that calls nondetWithoutNull() without assigning the return value.")
224
+ // {
225
+ // load_and_test_method("replaceNondetUnused:()V", functions, symbol_table);
226
+ // }
227
+
228
+ // WHEN(
229
+ // "A method directly returns a nonDetWithoutNull of type int. Causes "
230
+ // "unboxing.")
231
+ // {
232
+ // load_and_test_method("replaceNondetReturnUnboxed:()I", functions, symbol_table);
233
+ // }
125
234
}
126
- }
235
+ }
0 commit comments