Skip to content

Commit 1366fa8

Browse files
author
owen-jones-diffblue
authored
Merge pull request diffblue#355 from diffblue/owen-jones-diffblue/fix-lvsa-crash
SEC-238: LVSA: Fix precise access path crashes
2 parents c08a675 + 6fe084e commit 1366fa8

18 files changed

+652
-219
lines changed

cbmc/src/pointer-analysis/value_set.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,7 @@ void value_sett::get_value_set_rec(
498498
get_reference_set(expr, reference_set, ns);
499499
const object_map_dt &object_map=reference_set.read();
500500

501-
if(object_map.begin()==object_map.end())
502-
insert(dest, exprt(ID_unknown, original_type));
503-
else
501+
if(object_map.begin() != object_map.end())
504502
{
505503
for(object_map_dt::const_iterator
506504
it1=object_map.begin();

regression/LVSA/TestEVS/Test$A.class

40 Bytes
Binary file not shown.

regression/LVSA/TestEVS/Test$B.class

93 Bytes
Binary file not shown.

regression/LVSA/TestEVS/Test$C.class

-65 Bytes
Binary file not shown.

regression/LVSA/TestEVS/Test$D.class

-484 Bytes
Binary file not shown.
-79 Bytes
Binary file not shown.

regression/LVSA/TestEVS/Test.class

1.8 KB
Binary file not shown.

regression/LVSA/TestEVS/Test.java

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class Test {
44
public static Node static_node;
55
public static Object static_object;
66

7-
public class Node {
7+
public static class Node {
88
Object left;
99
Object right;
1010
}
@@ -31,12 +31,24 @@ public void is_initializer_flag(Node parameter_node) {
3131
static_object = parameter_node.left;
3232
}
3333

34-
public class A {
34+
public static class A {
3535
Node node;
36+
37+
public Node get_special_node() {
38+
return node;
39+
}
3640
}
3741

38-
public class B extends A {
39-
Object extra_field;
42+
public static class B extends A {
43+
Node extra_node;
44+
45+
public Node get_special_node() {
46+
return extra_node;
47+
}
48+
}
49+
50+
public static class C extends B {
51+
Object extra_object;
4052
}
4153

4254
public void read_from_field_from_supertype(B b) {
@@ -58,6 +70,73 @@ public void write_to_field_of_B_through_A(B b, Node node_parameter) {
5870
static_node = b.node;
5971
}
6072

73+
// Do not test this function directly as it gives quite different results when
74+
// using CSVSA-driven lazy loading
75+
public void call_overridden_method_on_A(A a) {
76+
a.node = new Node();
77+
static_node = a.get_special_node();
78+
}
79+
80+
public void apply_call_overridden_method_on_A_with_A() {
81+
Node n = static_node; // workaround for SEC-209
82+
A a = new A();
83+
call_overridden_method_on_A(a);
84+
}
85+
86+
public void apply_call_overridden_method_on_A_with_B() {
87+
Node n = static_node; // workaround for SEC-209
88+
B b = new B();
89+
call_overridden_method_on_A(b);
90+
}
91+
92+
public void apply_call_overridden_method_on_A_with_C() {
93+
Node n = static_node; // workaround for SEC-209
94+
C c = new C();
95+
call_overridden_method_on_A(c);
96+
}
97+
98+
public void call_overridden_method_on_B(B b) {
99+
b.extra_node = new Node();
100+
static_node = b.get_special_node();
101+
}
102+
103+
public void call_overridden_method_on_C(C c) {
104+
c.extra_node = new Node();
105+
static_node = c.get_special_node();
106+
}
107+
108+
public void call_overridden_method_on_C_upcast_to_A(C c) {
109+
c.extra_node = new Node();
110+
A a = c;
111+
static_node = a.get_special_node();
112+
}
113+
114+
115+
public static void function_with_B_parameter(B b) {
116+
if (b instanceof C) {
117+
static_object = ((C)b).extra_object;
118+
}
119+
}
120+
121+
public void call_function_with_B_parameter_with_C_argument(C c) {
122+
Object o = static_object; // workaround for SEC-209
123+
Test.function_with_B_parameter(c);
124+
}
125+
126+
public void call_function_with_B_parameter_with_A_argument_cast_to_C(A a) {
127+
Object o = static_object; // workaround for SEC-209
128+
if (a instanceof C) {
129+
Test.function_with_B_parameter((C)a);
130+
}
131+
}
132+
133+
public void
134+
apply_call_function_with_B_parameter_with_A_argument_cast_to_C_with_C(C c) {
135+
Object o = static_object; // workaround for SEC-209
136+
c.extra_object = new Object();
137+
call_function_with_B_parameter_with_A_argument_cast_to_C(c);
138+
}
139+
61140
public void read_from_array(Object object_array[]) {
62141
static_object = object_array[0];
63142
}
@@ -76,21 +155,17 @@ public void write_to_field_of_object_in_array(Node node_array[]) {
76155
static_object = node_array[0].left;
77156
}
78157

79-
public class C {
158+
public class P {
80159
Object object_array[];
81160
}
82161

83-
public class D {
84-
A a_array[];
85-
}
86-
87-
public void read_from_array_field(C c) {
88-
static_object = c.object_array[0];
162+
public void read_from_array_field(P p) {
163+
static_object = p.object_array[0];
89164
}
90165

91-
public void write_to_array_field(C c) {
92-
c.object_array[0] = new Object();
93-
static_object = c.object_array[0];
166+
public void write_to_array_field(P p) {
167+
p.object_array[0] = new Object();
168+
static_object = p.object_array[0];
94169
}
95170

96171
public void function_which_sets_static_variable() {

regression/LVSA/TestEVS/test_evs.py

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
from regression.LVSA.lvsa_driver import LvsaDriver, EvsType
24

35
folder_name = 'TestEVS'
@@ -70,8 +72,7 @@ def test_read_from_field_from_supertype(tmpdir):
7072

7173
value_set_expectation.check_number_of_values(2)
7274
value_set_expectation.check_contains_per_field_evs(access_path=['.left'])
73-
value_set_expectation.check_contains_precise_evs(label_suffix='b', access_path=['[email protected]$A.node',
74-
'.left'])
75+
value_set_expectation.check_contains_precise_evs(label_suffix='b', access_path=['.node', '.left'])
7576

7677

7778
def test_write_to_field_from_supertype(tmpdir):
@@ -83,7 +84,8 @@ def test_write_to_field_from_supertype(tmpdir):
8384
value_set_expectation.check_number_of_values(3)
8485
value_set_expectation.check_contains_dynamic_object()
8586
value_set_expectation.check_contains_per_field_evs(access_path=['.left'])
86-
value_set_expectation.check_contains_precise_evs(access_path=['[email protected]$A.node', '.left'])
87+
value_set_expectation.check_contains_precise_evs(access_path=['.node', '.left'],
88+
decl_on_types=['LVSA.TestEVS.Test$A', 'LVSA.TestEVS.Test$Node'])
8789

8890

8991
def test_write_to_field_of_B_through_A(tmpdir):
@@ -95,7 +97,114 @@ def test_write_to_field_of_B_through_A(tmpdir):
9597
value_set_expectation.check_number_of_values(3)
9698
value_set_expectation.check_contains_root_object_evs(label_suffix='node_parameter')
9799
value_set_expectation.check_contains_per_field_evs(access_path=['.node'])
98-
value_set_expectation.check_contains_precise_evs(label_suffix='b', access_path=['[email protected]$A.node'])
100+
value_set_expectation.check_contains_precise_evs(label_suffix='b', access_path=['.node'],
101+
decl_on_types=['LVSA.TestEVS.Test$A'])
102+
103+
104+
def test_apply_call_overridden_method_on_A_with_A(tmpdir):
105+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_call_overridden_method_on_A_with_A')
106+
lvsa_expectation = lvsa_driver.run()
107+
108+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
109+
110+
value_set_expectation.check_number_of_values(2)
111+
value_set_expectation.check_contains_dynamic_object()
112+
value_set_expectation.check_contains_root_object_evs(label_suffix='static_node')
113+
114+
115+
def test_apply_call_overridden_method_on_A_with_B(tmpdir):
116+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_call_overridden_method_on_A_with_B')
117+
lvsa_expectation = lvsa_driver.run()
118+
119+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
120+
121+
# Only test for what's important as CSVSA-driven-lazy-loading changes the results
122+
value_set_expectation.check_contains_null_object()
123+
value_set_expectation.check_contains_root_object_evs(label_suffix='static_node')
124+
125+
126+
def test_apply_call_overridden_method_on_A_with_C(tmpdir):
127+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_call_overridden_method_on_A_with_C')
128+
lvsa_expectation = lvsa_driver.run()
129+
130+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
131+
132+
# Only test for what's important as CSVSA-driven-lazy-loading changes the results
133+
value_set_expectation.check_contains_null_object()
134+
value_set_expectation.check_contains_root_object_evs(label_suffix='static_node')
135+
136+
137+
def test_call_overridden_method_on_B(tmpdir):
138+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('call_overridden_method_on_B')
139+
lvsa_expectation = lvsa_driver.run()
140+
141+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
142+
143+
value_set_expectation.check_number_of_values(2)
144+
value_set_expectation.check_contains_dynamic_object()
145+
value_set_expectation.check_contains_per_field_evs(access_path=['.extra_node'])
146+
147+
148+
def test_call_overridden_method_on_C(tmpdir):
149+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('call_overridden_method_on_C')
150+
lvsa_expectation = lvsa_driver.run()
151+
152+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
153+
154+
value_set_expectation.check_number_of_values(2)
155+
value_set_expectation.check_contains_dynamic_object()
156+
value_set_expectation.check_contains_per_field_evs(access_path=['.extra_node'])
157+
158+
159+
def test_call_overridden_method_on_C_upcast_to_A(tmpdir):
160+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('call_overridden_method_on_C_upcast_to_A')
161+
lvsa_expectation = lvsa_driver.run()
162+
163+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
164+
165+
# Only test for what's important as CSVSA-driven-lazy-loading changes the results
166+
value_set_expectation.check_contains_dynamic_object()
167+
value_set_expectation.check_contains_per_field_evs(access_path=['.extra_node'])
168+
169+
170+
def test_call_function_with_B_parameter_with_C_argument(tmpdir):
171+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('call_function_with_B_parameter_with_C_argument')
172+
lvsa_expectation = lvsa_driver.run()
173+
174+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_object')
175+
176+
value_set_expectation.check_number_of_values(3)
177+
value_set_expectation.check_contains_root_object_evs(label_suffix='static_object')
178+
value_set_expectation.check_contains_precise_evs(label_suffix='c', access_path=['.extra_object'])
179+
value_set_expectation.check_contains_per_field_evs(access_path=['.extra_object'], is_initializer=True)
180+
181+
182+
def test_call_function_with_B_parameter_with_A_argument_cast_to_C(tmpdir):
183+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function(
184+
'call_function_with_B_parameter_with_A_argument_cast_to_C')
185+
lvsa_expectation = lvsa_driver.run()
186+
187+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_object')
188+
189+
value_set_expectation.check_number_of_values(3)
190+
value_set_expectation.check_contains_root_object_evs(label_suffix='static_object')
191+
value_set_expectation.check_contains_per_field_evs(access_path=['.extra_object'],
192+
decl_on_types=['LVSA.TestEVS.Test$C'], is_initializer=True)
193+
value_set_expectation.check_contains_precise_evs(access_path=['.extra_object'],
194+
decl_on_types=['LVSA.TestEVS.Test$C'])
195+
196+
197+
def test_apply_call_function_with_B_parameter_with_A_argument_cast_to_C_with_C(tmpdir):
198+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function(
199+
'apply_call_function_with_B_parameter_with_A_argument_cast_to_C_with_C')
200+
lvsa_expectation = lvsa_driver.run()
201+
202+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_object')
203+
204+
value_set_expectation.check_number_of_values(3)
205+
value_set_expectation.check_contains_root_object_evs(label_suffix='static_object')
206+
value_set_expectation.check_contains_dynamic_object()
207+
value_set_expectation.check_contains_per_field_evs(access_path=['.extra_object'], is_initializer=True)
99208

100209

101210
def test_read_from_array(tmpdir):
@@ -152,7 +261,7 @@ def test_read_from_array_field(tmpdir):
152261

153262
value_set_expectation.check_number_of_values(2)
154263
value_set_expectation.check_contains_per_field_evs(access_path=['[]'])
155-
value_set_expectation.check_contains_precise_evs(access_path=['.object_array','.data', '[]'])
264+
value_set_expectation.check_contains_precise_evs(access_path=['.object_array', '.data', '[]'])
156265

157266

158267
def test_write_to_array_field(tmpdir):
@@ -164,7 +273,7 @@ def test_write_to_array_field(tmpdir):
164273
value_set_expectation.check_number_of_values(3)
165274
value_set_expectation.check_contains_dynamic_object()
166275
value_set_expectation.check_contains_per_field_evs(access_path=['[]'])
167-
value_set_expectation.check_contains_precise_evs(access_path=['.object_array','.data', '[]'])
276+
value_set_expectation.check_contains_precise_evs(access_path=['.object_array', '.data', '[]'])
168277

169278

170279
def test_apply_function_which_sets_static_variable(tmpdir):

regression/LVSA/TestPreciseAccessPaths/test_precise_access_paths.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def test_read_field_before_writing_to_aliasable_field(tmpdir):
119119

120120
@pytest.mark.xfail(strict=True)
121121
def test_apply_read_field_before_writing_to_aliasable_field(tmpdir):
122+
# SEC-266: Erroneous initialiser per field EVSs
122123
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function(
123124
'apply_read_field_before_writing_to_aliasable_field')
124125
lvsa_expectation = lvsa_driver.run()
@@ -150,6 +151,7 @@ def test_read_field_after_writing_to_aliasable_field(tmpdir):
150151

151152
@pytest.mark.xfail(strict=True)
152153
def test_apply_read_field_after_writing_to_aliasable_field(tmpdir):
154+
# SEC-266: Erroneous initialiser per field EVSs
153155
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function(
154156
'apply_read_field_after_writing_to_aliasable_field')
155157
lvsa_expectation = lvsa_driver.run()
@@ -176,6 +178,7 @@ def test_call_function_to_allocate_new_object(tmpdir):
176178

177179
@pytest.mark.xfail(strict=True)
178180
def test_apply_call_function_to_allocate_new_object(tmpdir):
181+
# SEC-266: Erroneous initialiser per field EVSs
179182
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_call_function_to_allocate_new_object')
180183
lvsa_expectation = lvsa_driver.run()
181184

@@ -222,6 +225,7 @@ def test_two_field_derefs(tmpdir):
222225

223226
@pytest.mark.xfail(strict=True)
224227
def test_apply_two_field_derefs(tmpdir):
228+
# SEC-266: Erroneous initialiser per field EVSs
225229
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_two_field_derefs')
226230
lvsa_expectation = lvsa_driver.run()
227231

@@ -245,6 +249,7 @@ def test_array_deref(tmpdir):
245249

246250
@pytest.mark.xfail(strict=True)
247251
def test_apply_array_deref(tmpdir):
252+
# SEC-266: Erroneous initialiser per field EVSs
248253
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_array_deref')
249254
lvsa_expectation = lvsa_driver.run()
250255

0 commit comments

Comments
 (0)