Skip to content

Commit ff1f6c7

Browse files
Merge pull request diffblue#5104 from owen-mc-diffblue/owen/change-how-cprover-nondetinitialize-is-called
Make cproverNondetInitialize be inherited [TG-8677]
2 parents b30b06a + 13eac31 commit ff1f6c7

20 files changed

+169
-12
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import org.cprover.CProver;
2+
3+
class A {
4+
int x;
5+
6+
public void cproverNondetInitialize() { CProver.assume(x == 42); }
7+
}
8+
9+
class B extends A {}
10+
11+
class C extends B {}
12+
13+
class F extends A {
14+
public void cproverNondetInitialize() {}
15+
}
16+
17+
interface I {
18+
}
19+
20+
class J extends A implements I {
21+
}
22+
23+
class K extends A {
24+
int y;
25+
26+
public void cproverNondetInitialize() {
27+
super.cproverNondetInitialize();
28+
CProver.assume(y == 6);
29+
}
30+
}
31+
32+
abstract class M {
33+
int x;
34+
35+
public void cproverNondetInitialize() { CProver.assume(x == 42); }
36+
}
37+
38+
class N extends M {}
39+
40+
public class Test {
41+
42+
void inheritanceTwoLevels(C c) {
43+
if (c != null)
44+
assert (c.x == 42);
45+
}
46+
47+
void override(F f) {
48+
if (f != null)
49+
assert (f.x == 42);
50+
}
51+
52+
void callingSuperCproverNondetInitialize(K k) {
53+
if (k != null) {
54+
assert (k.x == 42);
55+
assert (k.y == 6);
56+
}
57+
}
58+
59+
void inheritanceFromAbstractClass(N n) {
60+
if (n != null)
61+
assert (n.x == 42);
62+
}
63+
64+
void alsoImplementsInterface(J j) {
65+
if (j != null)
66+
assert (j.x == 42);
67+
}
68+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
Test.class
3+
--function Test.alsoImplementsInterface --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Check that if J extends A and implements the interface I,
11+
J.cproverNondetInitialize doesn't exist and A.cproverNondetInitialize does then
12+
a nondet J gets the constraints specified in A.cproverNondetInitialize.
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.callingSuperCproverNondetInitialize --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Check that calls to super.cproverNondetInitialize call cproverNondetInitialize
11+
in the base class.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
Test.class
3+
--function Test.inheritanceFromAbstractClass --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Check that if N extends the abstract class M, N.cproverNondetInitialize doesn't
11+
exist and M.cproverNondetInitialize does and is defined then a
12+
nondet N gets the constraints specified in M.cproverNondetInitialize.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
Test.class
3+
--function Test.inheritanceTwoLevels --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Check that if C extends B, B extends A, B.cproverNondetInitialize and
11+
C.cproverNondetInitialize don't exist and A.cproverNondetInitialize does then a
12+
nondet C gets the constraints specified in A.cproverNondetInitialize.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
Test.class
3+
--function Test.override --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
^warning: ignoring
9+
--
10+
Check that if F extends A, and A.cproverNondetInitialize and
11+
F.cproverNondetInitialize both exist then a nondet F doesn't get the constraint
12+
specified in A.cproverNondetInitialize. Specifically, it doesn't get the
13+
constraint that x must be 42, so when we assert that x is 42 jbmc is able to
14+
falsify it.

jbmc/src/java_bytecode/ci_lazy_methods_needed.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Author: Chris Smowton, [email protected]
1111

1212
#include "ci_lazy_methods_needed.h"
1313

14+
#include <goto-programs/resolve_inherited_component.h>
15+
1416
#include <util/namespace.h>
1517
#include <util/std_types.h>
1618

@@ -43,6 +45,24 @@ void ci_lazy_methods_neededt::add_clinit_call(const irep_idt &class_id)
4345
add_needed_method(clinit_wrapper);
4446
}
4547

48+
/// For a given class id, if cproverNondetInitialize exists on it or any of its
49+
/// ancestors then note that it is needed.
50+
/// \param class_id: The given class id
51+
void ci_lazy_methods_neededt::add_cprover_nondet_initialize_if_it_exists(
52+
const irep_idt &class_id)
53+
{
54+
resolve_inherited_componentt resolve_inherited_component{symbol_table};
55+
optionalt<resolve_inherited_componentt::inherited_componentt>
56+
cprover_nondet_initialize = resolve_inherited_component(
57+
class_id, "cproverNondetInitialize:()V", true);
58+
59+
if(cprover_nondet_initialize)
60+
{
61+
add_needed_method(
62+
cprover_nondet_initialize->get_full_component_identifier());
63+
}
64+
}
65+
4666
/// Notes class `class_symbol_name` will be instantiated, or a static field
4767
/// belonging to it will be accessed. Also notes that its static initializer is
4868
/// therefore reachable.
@@ -54,11 +74,7 @@ bool ci_lazy_methods_neededt::add_needed_class(
5474
if(!instantiated_classes.insert(class_symbol_name).second)
5575
return false;
5676

57-
const std::string &class_name_string = id2string(class_symbol_name);
58-
const irep_idt cprover_validate(
59-
class_name_string + ".cproverNondetInitialize:()V");
60-
if(symbol_table.symbols.count(cprover_validate))
61-
add_needed_method(cprover_validate);
77+
add_cprover_nondet_initialize_if_it_exists(class_symbol_name);
6278

6379
// Special case for enums. We may want to generalise this, the comment in
6480
// \ref java_object_factoryt::gen_nondet_pointer_init (TG-4689).

jbmc/src/java_bytecode/ci_lazy_methods_needed.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class ci_lazy_methods_neededt
5757
const select_pointer_typet &pointer_type_selector;
5858

5959
void add_clinit_call(const irep_idt &class_id);
60+
void add_cprover_nondet_initialize_if_it_exists(const irep_idt &class_id);
6061

6162
void initialize_instantiated_classes_from_pointer(
6263
const pointer_typet &pointer_type,

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -897,17 +897,25 @@ void java_object_factoryt::gen_nondet_struct_init(
897897
}
898898
}
899899

900-
// If <class_identifier>.cproverNondetInitialize() can be found in the
901-
// symbol table, we add a call:
900+
// If cproverNondetInitialize() can be found in the symbol table as a method
901+
// on this class or any parent, we add a call:
902902
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
903903
// expr.cproverNondetInitialize();
904904
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
905905

906-
const irep_idt init_method_name =
907-
"java::" + id2string(struct_tag) + ".cproverNondetInitialize:()V";
908-
if(const auto init_func = symbol_table.lookup(init_method_name))
906+
resolve_inherited_componentt resolve_inherited_component{symbol_table};
907+
optionalt<resolve_inherited_componentt::inherited_componentt>
908+
cprover_nondet_initialize = resolve_inherited_component(
909+
"java::" + id2string(struct_tag), "cproverNondetInitialize:()V", true);
910+
911+
if(cprover_nondet_initialize)
912+
{
913+
const symbolt &cprover_nondet_initialize_symbol =
914+
ns.lookup(cprover_nondet_initialize->get_full_component_identifier());
909915
assignments.add(
910-
code_function_callt{init_func->symbol_expr(), {address_of_exprt{expr}}});
916+
code_function_callt{cprover_nondet_initialize_symbol.symbol_expr(),
917+
{address_of_exprt{expr}}});
918+
}
911919
}
912920

913921
/// Generate code block that verifies that an expression of type float or

jbmc/unit/java_bytecode/java_object_factory/gen_nondet_string_init.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ SCENARIO(
3030
register_language(new_java_bytecode_language);
3131

3232
// Add java.lang.Object to symbol table
33+
java_class_typet jlo_class_type;
34+
jlo_class_type.set_tag("java.lang.Object");
35+
jlo_class_type.set_name("java::java.lang.Object");
3336
symbolt jlo_sym;
3437
jlo_sym.name = "java::java.lang.Object";
35-
jlo_sym.type = struct_typet();
38+
jlo_sym.type = jlo_class_type;
3639
jlo_sym.is_type = true;
3740
java_root_class(jlo_sym);
3841
bool failed = symbol_table.add(jlo_sym);

0 commit comments

Comments
 (0)