Skip to content

Commit 850c824

Browse files
author
owen-jones-diffblue
authored
Merge pull request diffblue#332 from diffblue/owen-jones-diffblue/export-precise-evs-in-most-cases
Export precise access path EVSs in most cases
2 parents 6fc8f97 + bd1bbe6 commit 850c824

File tree

8 files changed

+53
-94
lines changed

8 files changed

+53
-94
lines changed
-326 Bytes
Binary file not shown.

regression/LVSA/TestPreciseAccessPaths/Test.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,4 @@ public void check_using_precise_access_paths() {
138138
simple_function_should_export_precise_access_paths(dynamic_object_2);
139139
output = dynamic_object_1.object;
140140
}
141-
142-
public void simple_function_should_export_imprecise_access_paths(A param_a) {
143-
param_a.object = new Object();
144-
static_list_node.data = null;
145-
}
146-
147-
public void check_using_imprecise_access_paths() {
148-
A dynamic_object_1 = new A();
149-
A dynamic_object_2 = new A();
150-
simple_function_should_export_imprecise_access_paths(dynamic_object_2);
151-
output = dynamic_object_1.object;
152-
}
153141
}

regression/LVSA/TestPreciseAccessPaths/test_precise_access_paths.py

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ def test_apply_field_getter(tmpdir):
4444

4545
value_set_expectation = lvsa_expectation.get_value_set_for_return_value()
4646

47-
value_set_expectation.check_number_of_values(1)
47+
value_set_expectation.check_number_of_values(2)
4848
value_set_expectation.check_contains_per_field_evs(access_path=['.object'])
49+
value_set_expectation.check_contains_precise_evs(access_path=['.a1', '.object'])
4950

5051

5152
def test_set_field_of_external_object(tmpdir):
@@ -113,21 +114,17 @@ def test_read_field_before_writing_to_aliasable_field(tmpdir):
113114
value_set_expectation_2.check_contains_per_field_evs(access_path=['.object'])
114115

115116

117+
@pytest.mark.xfail(strict=True)
116118
def test_apply_read_field_before_writing_to_aliasable_field(tmpdir):
117119
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function(
118120
'apply_read_field_before_writing_to_aliasable_field')
119121
lvsa_expectation = lvsa_driver.run()
120122

121-
value_set_expectation_1 = lvsa_expectation.get_value_set_for_per_field_evs(inner_class_name='A', suffix='.object')
122-
123-
value_set_expectation_1.check_number_of_values(2)
124-
value_set_expectation_1.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
125-
value_set_expectation_1.check_contains_dynamic_object()
126-
127-
value_set_expectation_2 = lvsa_expectation.get_value_set_for_output()
123+
value_set_expectation = lvsa_expectation.get_value_set_for_output()
128124

129-
value_set_expectation_2.check_number_of_values(1)
130-
value_set_expectation_2.check_contains_per_field_evs(access_path=['.object'])
125+
value_set_expectation.check_number_of_values(1)
126+
value_set_expectation.check_contains_precise_evs(label_suffix='this', access_path=['.a2','.object'])
127+
# value_set_expectation.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
131128

132129

133130
def test_read_field_after_writing_to_aliasable_field(tmpdir):
@@ -148,22 +145,18 @@ def test_read_field_after_writing_to_aliasable_field(tmpdir):
148145
value_set_expectation_2.check_contains_dynamic_object()
149146

150147

148+
@pytest.mark.xfail(strict=True)
151149
def test_apply_read_field_after_writing_to_aliasable_field(tmpdir):
152150
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function(
153151
'apply_read_field_after_writing_to_aliasable_field')
154152
lvsa_expectation = lvsa_driver.run()
155153

156-
value_set_expectation_1 = lvsa_expectation.get_value_set_for_per_field_evs(inner_class_name='A', suffix='.object')
157-
158-
value_set_expectation_1.check_number_of_values(2)
159-
value_set_expectation_1.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
160-
value_set_expectation_1.check_contains_dynamic_object()
161-
162-
value_set_expectation_2 = lvsa_expectation.get_value_set_for_output()
154+
value_set_expectation = lvsa_expectation.get_value_set_for_output()
163155

164-
value_set_expectation_2.check_number_of_values(2)
165-
value_set_expectation_2.check_contains_per_field_evs(access_path=['.object'])
166-
value_set_expectation_2.check_contains_dynamic_object()
156+
value_set_expectation.check_number_of_values(2)
157+
value_set_expectation.check_contains_precise_evs(label_suffix='this', access_path=['.a2', '.object'])
158+
value_set_expectation.check_contains_dynamic_object()
159+
# value_set_expectation.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
167160

168161

169162
def test_call_function_to_allocate_new_object(tmpdir):
@@ -178,15 +171,17 @@ def test_call_function_to_allocate_new_object(tmpdir):
178171
value_set_expectation.check_contains_dynamic_object()
179172

180173

174+
@pytest.mark.xfail(strict=True)
181175
def test_apply_call_function_to_allocate_new_object(tmpdir):
182176
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_call_function_to_allocate_new_object')
183177
lvsa_expectation = lvsa_driver.run()
184178

185179
value_set_expectation = lvsa_expectation.get_value_set_for_output()
186180

187181
value_set_expectation.check_number_of_values(2)
188-
value_set_expectation.check_contains_per_field_evs(access_path=['.object'])
182+
value_set_expectation.check_contains_precise_evs(label_suffix='param_A', access_path=['.object'])
189183
value_set_expectation.check_contains_dynamic_object()
184+
# value_set_expectation.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
190185

191186

192187
def test_get_list_node(tmpdir):
@@ -208,7 +203,7 @@ def test_apply_get_list_node(tmpdir):
208203
value_set_expectation = lvsa_expectation.get_value_set_for_output()
209204

210205
value_set_expectation.check_number_of_values(1)
211-
value_set_expectation.check_contains_per_field_evs()
206+
value_set_expectation.check_contains_per_field_evs(access_path=['.data'])
212207

213208

214209
def test_two_field_derefs(tmpdir):
@@ -222,14 +217,16 @@ def test_two_field_derefs(tmpdir):
222217
value_set_expectation.check_contains_per_field_evs(access_path=['.object'])
223218

224219

220+
@pytest.mark.xfail(strict=True)
225221
def test_apply_two_field_derefs(tmpdir):
226222
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_two_field_derefs')
227223
lvsa_expectation = lvsa_driver.run()
228224

229225
value_set_expectation = lvsa_expectation.get_value_set_for_output()
230226

231227
value_set_expectation.check_number_of_values(1)
232-
value_set_expectation.check_contains_per_field_evs(access_path=['.object'])
228+
value_set_expectation.check_contains_precise_evs(label_suffix='parameter_b', access_path=['.a', '.object'])
229+
# value_set_expectation.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
233230

234231

235232
def test_array_deref(tmpdir):
@@ -243,32 +240,13 @@ def test_array_deref(tmpdir):
243240
value_set_expectation.check_contains_per_field_evs(access_path=['[]'])
244241

245242

243+
@pytest.mark.xfail(strict=True)
246244
def test_apply_array_deref(tmpdir):
247245
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('apply_array_deref')
248246
lvsa_expectation = lvsa_driver.run()
249247

250248
value_set_expectation = lvsa_expectation.get_value_set_for_output()
251249

252250
value_set_expectation.check_number_of_values(1)
253-
value_set_expectation.check_contains_per_field_evs(access_path=['[]'])
254-
255-
256-
def test_check_using_precise_access_paths(tmpdir):
257-
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('check_using_precise_access_paths')
258-
lvsa_expectation = lvsa_driver.run()
259-
260-
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('output')
261-
262-
value_set_expectation.check_number_of_values(1)
263-
value_set_expectation.check_contains_null_object()
264-
265-
266-
def test_check_using_imprecise_access_paths(tmpdir):
267-
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('check_using_imprecise_access_paths')
268-
lvsa_expectation = lvsa_driver.run()
269-
270-
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('output')
271-
272-
value_set_expectation.check_number_of_values(2)
273-
value_set_expectation.check_contains_null_object()
274-
value_set_expectation.check_contains_dynamic_object()
251+
value_set_expectation.check_contains_precise_evs(label_suffix='object_array', access_path=['.data', '[]'])
252+
# value_set_expectation.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)

regression/LVSA/TestTest/.gitignore

Whitespace-only changes.

src/pointer-analysis/local_value_set.cpp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,6 @@ void local_value_sett::get_value_set_rec(
248248
expr.type(), suffix, ns, declared_on_type, suffix_without_supertypes);
249249
if(field_type.id() == ID_pointer)
250250
{
251-
// Temporary: keep track of whether we read from an EVS, so we can
252-
// ignore precise access path EVSs when applying function summaries if
253-
// there are any reads from EVSs.
254-
++num_reads_of_field_of_external_object;
255-
256251
const auto &extinit = to_external_value_set(expr);
257252

258253
// If we're reading from `EVS(A.b)` then initialize an entry for that
@@ -563,14 +558,6 @@ void local_value_sett::assign_rec(
563558
const typet &field_type = type_from_suffix(
564559
lhs.type(), suffix, ns, declared_on_type, suffix_without_supertypes);
565560

566-
if(field_type.id() == ID_pointer)
567-
{
568-
// Temporary: keep track of how many times we write to a field of an EVS,
569-
// so we can ignore precise access path EVSs when applying function
570-
// summaries if there is more than one write to a field of an EVS.
571-
++num_writes_to_field_of_external_object;
572-
}
573-
574561
if(evsi.can_extend_to_imprecise())
575562
{
576563
std::string access_path_suffix =
@@ -622,11 +609,12 @@ void local_value_sett::assign_rec(
622609
{
623610
const std::string basename =
624611
new_ext_set.get_access_path_basename(declared_on_type);
625-
std::string entryname = basename + access_path_suffix;
612+
const std::string fieldname = new_ext_set.get_access_path_suffix();
613+
const std::string entryname = basename + fieldname;
626614

627615
entryt entry(
628616
basename,
629-
access_path_suffix,
617+
fieldname,
630618
external_value_set_exprt::get_precise_evs_irep_id(),
631619
new_ext_set);
632620

@@ -688,13 +676,12 @@ void local_value_sett::apply_code_rec(const codet &code, const namespacet &ns)
688676
}
689677
}
690678

691-
void local_value_sett::make_union_bookkeeping_data_structures(
679+
bool local_value_sett::make_union_bookkeeping_data_structures(
692680
const local_value_sett &other)
693681
{
694-
num_reads_of_field_of_external_object +=
695-
other.num_reads_of_field_of_external_object;
696-
num_writes_to_field_of_external_object +=
697-
other.num_writes_to_field_of_external_object;
698-
precise_evs_curtailed_because_of_loop &=
682+
bool original_value = precise_evs_curtailed_because_of_loop;
683+
precise_evs_curtailed_because_of_loop =
684+
precise_evs_curtailed_because_of_loop ||
699685
other.precise_evs_curtailed_because_of_loop;
686+
return precise_evs_curtailed_because_of_loop != original_value;
700687
}

src/pointer-analysis/local_value_set.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ class local_value_sett : public value_sett
1818
public:
1919
typedef value_sett baset;
2020

21-
mutable unsigned int num_reads_of_field_of_external_object = 0;
22-
mutable unsigned int num_writes_to_field_of_external_object = 0;
2321
mutable bool precise_evs_curtailed_because_of_loop = false;
2422

2523
/// Determines whether we should export precise or per_field external value
@@ -30,10 +28,7 @@ class local_value_sett : public value_sett
3028
#ifdef DO_NOT_USE_PRECISE_EXTERNAL_VALUE_SETS
3129
return false;
3230
#else
33-
return !precise_evs_curtailed_because_of_loop &&
34-
(num_reads_of_field_of_external_object +
35-
num_writes_to_field_of_external_object <=
36-
1);
31+
return !precise_evs_curtailed_because_of_loop;
3732
#endif
3833
}
3934

@@ -82,7 +77,9 @@ class local_value_sett : public value_sett
8277

8378
/// Union data structures in this value-set besides the actual `values`
8479
/// with those in `other`.
85-
void make_union_bookkeeping_data_structures(const local_value_sett &other);
80+
/// \param other: the local_value_sett we are unioning with *this
81+
/// \return true if anything changed
82+
bool make_union_bookkeeping_data_structures(const local_value_sett &other);
8683

8784
protected:
8885
/// Overrides `value_sett::get_value_set_rec` to (a) handle reads from

src/pointer-analysis/local_value_set_analysis.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ static const exprt get_expr_from_root_object(
216216
/// accessing a field of A then access_path_label will be
217217
/// ".@Y.@X.@W. ... [email protected]_name". For an array dereference, the access
218218
/// path will have the label "[]", and the access path entry before
219-
/// it will have the label ".data".
219+
/// it will have a label ending in ".data".
220220
DATA_INVARIANT(
221221
access_path_label.size() >= 2,
222222
"Access path label must have length at least 2");
@@ -226,14 +226,18 @@ static const exprt get_expr_from_root_object(
226226
DATA_INVARIANT(
227227
std::prev(it)->label() == ".data",
228228
"Access path entry '[]' must be preceded by access path entry '.data'");
229+
230+
const typet &array_type = to_member_expr(expr).compound().type();
231+
const typet target_type = java_reference_type(
232+
java_array_element_type(to_symbol_type(array_type)));
233+
229234
expr = dereference_exprt(
230235
plus_exprt(
231-
expr, side_effect_expr_nondett(java_int_type()), expr.type()));
236+
expr, side_effect_expr_nondett(java_int_type()), target_type));
232237
}
233238
else
234239
{
235240
expr = dereference_exprt(expr);
236-
const struct_typet &struct_type = to_struct_type(ns.follow(expr.type()));
237241

238242
/// First deal with any superclass identifiers
239243
while(access_path_label[1] == '@')
@@ -248,6 +252,8 @@ static const exprt get_expr_from_root_object(
248252
"Special fields @lock and @class_identifier should not be "
249253
"appearing in function summary");
250254

255+
const struct_typet &struct_type =
256+
to_struct_type(ns.follow(expr.type()));
251257
const auto expr_components = struct_type.components();
252258
DATA_INVARIANT(
253259
!expr_components.empty(),
@@ -268,10 +274,10 @@ static const exprt get_expr_from_root_object(
268274
access_path_label[0] == '.',
269275
"the label of an access path entry is malformed");
270276
access_path_label = access_path_label.substr(1);
277+
const struct_typet &struct_type = to_struct_type(ns.follow(expr.type()));
271278
auto &component = struct_type.get_component(access_path_label);
272279
INVARIANT(
273-
component.get_name() != ID_nil,
274-
"Could not find field from access path");
280+
component.is_not_nil(), "Could not find field from access path");
275281
expr = member_exprt(expr, component);
276282
}
277283
}
@@ -464,8 +470,9 @@ void local_value_set_analysist::transform_function_stub(
464470

465471
/// Weak write - can we do strong writes?
466472
bool add_to_sets = true;
467-
auto demoted_rhs_values=pre_call_rhs_value_sets.at(assignment.second);
468-
valuesets.demote_initializers(demoted_rhs_values);
473+
const auto &rhs_expr = assignment.second;
474+
auto demoted_rhs_values = pre_call_rhs_value_sets.at(assignment.second);
475+
valuesets.adjust_assign_rhs_values(rhs_expr, ns, demoted_rhs_values);
469476
valuesets.assign_valueset(
470477
precise_access_path_expr, demoted_rhs_values, ns, add_to_sets);
471478
}

src/pointer-analysis/local_value_set_domain.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ class local_value_set_domaint
1515
public:
1616
bool merge(const local_value_set_domaint &other, locationt to)
1717
{
18-
value_set.make_union_bookkeeping_data_structures(other.value_set);
19-
return value_set.make_union(other.value_set);
18+
bool bookkeeping_data_structures_changed =
19+
value_set.make_union_bookkeeping_data_structures(other.value_set);
20+
bool value_set_changed = value_set.make_union(other.value_set);
21+
return bookkeeping_data_structures_changed || value_set_changed;
2022
}
2123
};
2224

0 commit comments

Comments
 (0)