Skip to content

Commit 7c52fe4

Browse files
author
owen-jones-diffblue
authored
Merge pull request diffblue#373 from diffblue/owen-jones-diffblue/precise-evs-function-arguments-alias
SEC-202: Enable strong writes to precise EVSs even when function arguments alias
2 parents 3a4788c + d3e03ed commit 7c52fe4

File tree

8 files changed

+202
-143
lines changed

8 files changed

+202
-143
lines changed

cbmc/src/pointer-analysis/value_set.cpp

+4-12
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,10 @@ bool value_sett::field_sensitive(
5353

5454
value_sett::entryt &value_sett::get_entry(
5555
const entryt &e,
56-
const typet &type,
5756
const namespacet &ns)
5857
{
59-
irep_idt index;
60-
61-
if(field_sensitive(e.identifier, type, ns))
62-
index=id2string(e.identifier)+e.suffix;
63-
else
64-
index=e.identifier;
65-
66-
std::pair<valuest::iterator, bool> r=
67-
values.insert(std::pair<idt, entryt>(index, e));
58+
std::pair<valuest::iterator, bool> r =
59+
values.insert(std::pair<idt, entryt>(e.get_key(ns), e));
6860

6961
return r.first->second;
7062
}
@@ -1410,7 +1402,7 @@ void value_sett::assign_rec(
14101402
if(lhs.id()==ID_symbol)
14111403
{
14121404
const irep_idt &identifier=to_symbol_expr(lhs).get_identifier();
1413-
entryt &e = get_entry(entryt(identifier, suffix, lhs), lhs.type(), ns);
1405+
entryt &e = get_entry(entryt(identifier, suffix, lhs), ns);
14141406

14151407
if(add_to_sets)
14161408
make_union(e.object_map, values_rhs);
@@ -1423,7 +1415,7 @@ void value_sett::assign_rec(
14231415
to_dynamic_object_expr(lhs);
14241416
std::string name=get_dynamic_object_name(dynamic_object);
14251417

1426-
entryt &e = get_entry(entryt(name, suffix, lhs), lhs.type(), ns);
1418+
entryt &e = get_entry(entryt(name, suffix, lhs), ns);
14271419

14281420
make_union(e.object_map, values_rhs);
14291421
}

cbmc/src/pointer-analysis/value_set.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,14 @@ class value_sett
298298
{
299299
return !(*this==other);
300300
}
301+
302+
const irep_idt get_key(const namespacet &ns) const
303+
{
304+
if(field_sensitive(identifier, structured_lhs.type(), ns))
305+
return id2string(identifier) + suffix;
306+
307+
return identifier;
308+
}
301309
};
302310

303311
/// Set of expressions; only used for the `get` API, not for internal
@@ -365,13 +373,8 @@ class value_sett
365373
/// `object_map` (RHS value set) will be copied; otherwise it will be
366374
/// ignored. Therefore it should probably be left blank and any RHS updates
367375
/// conducted against the returned reference.
368-
/// \param type: type of `e.identifier`, used to determine whether `e`'s
369-
/// suffix should be used to find a field-sensitive value-set or whether
370-
/// a single entry should be shared by all of symbol `e.identifier`.
371376
/// \param ns: global namespace
372-
entryt &get_entry(
373-
const entryt &e, const typet &type,
374-
const namespacet &ns);
377+
entryt &get_entry(const entryt &e, const namespacet &ns);
375378

376379
/// Pretty-print this value-set
377380
/// \param ns: global namespace

regression/LVSA/TestEVS/test_evs.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,9 @@ def test_write_to_field_of_B_through_A(tmpdir):
9494

9595
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('static_node')
9696

97-
value_set_expectation.check_number_of_values(3)
97+
value_set_expectation.check_number_of_values(2)
9898
value_set_expectation.check_contains_root_object_evs(label_suffix='node_parameter')
9999
value_set_expectation.check_contains_per_field_evs(access_path=['.node'])
100-
value_set_expectation.check_contains_precise_evs(label_suffix='b', access_path=['.node'],
101-
decl_on_types=['LVSA.TestEVS.Test$A'])
102100

103101

104102
def test_apply_call_overridden_method_on_A_with_A(tmpdir):
630 Bytes
Binary file not shown.

regression/LVSA/TestPreciseAccessPaths/Test.java

+21
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,25 @@ 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+
// Helper function for check_aliasing_function_arguments()
143+
public void write_to_fields_of_two_parameters(A param_a_1, A param_a_2) {
144+
param_a_1.object = new Object();
145+
param_a_2.object = new Object();
146+
}
147+
148+
public void check_strong_writes_for_precise_evs(Object param_object) {
149+
A a_1 = new A();
150+
a_1.object = param_object;
151+
A a_2 = new A();
152+
a_2.object = param_object;
153+
write_to_fields_of_two_parameters(a_1, a_2);
154+
output = a_1.object;
155+
}
156+
157+
public void check_aliasing_function_arguments() {
158+
A a = new A();
159+
write_to_fields_of_two_parameters(a, a);
160+
output = a.object;
161+
}
141162
}

regression/LVSA/TestPreciseAccessPaths/test_precise_access_paths.py

+23-10
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,8 @@ def test_apply_set_field_of_external_object(tmpdir):
6969
value_set_expectation = lvsa_expectation.get_value_set_for_precise_evs(
7070
parameter_name='parameter_a', suffix='.object')
7171

72-
value_set_expectation.check_number_of_values(2)
72+
value_set_expectation.check_number_of_values(1)
7373
value_set_expectation.check_contains_root_object_evs(label_suffix='parameter_object')
74-
value_set_expectation.check_contains_precise_evs(label_suffix='parameter_a', access_path=['.object'],
75-
is_initializer=True)
7674

7775

7876
def test_conditionally_set_field_of_external_object(tmpdir):
@@ -95,15 +93,11 @@ def test_apply_conditionally_set_field_of_external_object(tmpdir):
9593
value_set_expectation = lvsa_expectation.get_value_set_for_precise_evs(
9694
parameter_name='parameter_a', suffix='.object')
9795

98-
value_set_expectation.check_number_of_values(4)
99-
# Two values that existed before the function call
96+
value_set_expectation.check_number_of_values(3)
10097
value_set_expectation.check_contains_per_field_evs(access_path=['.object'])
10198
value_set_expectation.check_contains_precise_evs(label_suffix='parameter_a', access_path=['.object'],
10299
is_initializer=False)
103-
# Two values that came from the function call
104100
value_set_expectation.check_contains_root_object_evs(label_suffix='parameter_object')
105-
value_set_expectation.check_contains_precise_evs(label_suffix='parameter_a', access_path=['.object'],
106-
is_initializer=True)
107101

108102

109103
def test_read_field_before_writing_to_aliasable_field(tmpdir):
@@ -176,9 +170,8 @@ def test_call_function_to_allocate_new_object(tmpdir):
176170

177171
value_set_expectation = lvsa_expectation.get_value_set_for_output()
178172

179-
value_set_expectation.check_number_of_values(3)
173+
value_set_expectation.check_number_of_values(2)
180174
value_set_expectation.check_contains_per_field_evs(access_path=['.object'])
181-
value_set_expectation.check_contains_precise_evs(label_suffix='param_A', access_path=['.object'])
182175
value_set_expectation.check_contains_dynamic_object()
183176

184177

@@ -266,3 +259,23 @@ def test_apply_array_deref(tmpdir):
266259
value_set_expectation.check_number_of_values(1)
267260
value_set_expectation.check_contains_precise_evs(label_suffix='object_array', access_path=['.data', '[]'])
268261
# value_set_expectation.check_contains_per_field_evs(access_path=['.object'], is_initializer=True)
262+
263+
264+
def test_check_strong_writes_for_precise_evs(tmpdir):
265+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('check_strong_writes_for_precise_evs')
266+
lvsa_expectation = lvsa_driver.run()
267+
268+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('output')
269+
270+
value_set_expectation.check_number_of_values(1)
271+
value_set_expectation.check_contains_dynamic_object(1)
272+
273+
274+
def test_check_aliasing_function_arguments(tmpdir):
275+
lvsa_driver = LvsaDriver(tmpdir, folder_name).with_test_function('check_aliasing_function_arguments')
276+
lvsa_expectation = lvsa_driver.run()
277+
278+
value_set_expectation = lvsa_expectation.get_value_set_for_public_static('output')
279+
280+
value_set_expectation.check_number_of_values(2)
281+
value_set_expectation.check_contains_dynamic_object(2)

src/pointer-analysis/local_value_set.cpp

+7-9
Original file line numberDiff line numberDiff line change
@@ -535,13 +535,12 @@ void local_value_sett::demote_most_recent_dynamic_objects(
535535
to_dynamic_object_expr(entry.structured_lhs);
536536
expr_any_allocation.set_recency(false);
537537

538-
// The second and third arguments to get_entry() are only used for
539-
// field_sensitive(), and that will always returns true without using
540-
// them because name_any_allocation starts with the prefix for a
541-
// dynamic object, so we can use an empty type and namespace.
538+
// The second argument to get_entry() is only used for field_sensitive(),
539+
// and that will always returns true without using it because
540+
// name_any_allocation starts with the prefix for a dynamic object, so
541+
// we can use an empty namespace.
542542
entryt &entry_any_allocation = get_entry(
543543
entryt(name_any_allocation, entry.suffix, expr_any_allocation),
544-
nil_typet(),
545544
namespacet(symbol_tablet()));
546545

547546
// Add into the any-allocation dynamic-object's object_map
@@ -618,8 +617,8 @@ void local_value_sett::assign_rec(
618617
ns,
619618
declared_on_type,
620619
suffix_without_supertypes_ignored);
621-
entryt &e = get_entry(
622-
entryt(identifier, suffix, declared_on_type, lhs), lhs.type(), ns);
620+
entryt &e =
621+
get_entry(entryt(identifier, suffix, declared_on_type, lhs), ns);
623622

624623
if(add_to_sets)
625624
make_union(e.object_map, values_rhs);
@@ -641,8 +640,7 @@ void local_value_sett::assign_rec(
641640
declared_on_type,
642641
suffix_without_supertypes_ignored);
643642

644-
entryt &entry =
645-
get_entry(entryt(name, suffix, declared_on_type, lhs), lhs.type(), ns);
643+
entryt &entry = get_entry(entryt(name, suffix, declared_on_type, lhs), ns);
646644

647645
if(
648646
dynamic_object.get_recency() ==

0 commit comments

Comments
 (0)