Skip to content

Commit 7ee1038

Browse files
author
owen-jones-diffblue
authored
Merge pull request diffblue#268 from diffblue/owen-jones-diffblue/refactor-external-value-set-types
Owen jones diffblue/refactor external value set types
2 parents 0f0a2f1 + b4ceea1 commit 7ee1038

File tree

7 files changed

+100
-67
lines changed

7 files changed

+100
-67
lines changed

cbmc/src/util/irep_ids.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ IREP_ID_TWO(generic_types, #generic_types)
842842
IREP_ID_TWO(type_variables, #type_variables)
843843
IREP_ID_ONE(havoc_object)
844844
IREP_ID_TWO(overflow_shl, overflow-shl)
845-
IREP_ID_ONE(lvsa_mode)
845+
IREP_ID_ONE(lvsa_evs_type)
846846
IREP_ID_ONE(is_initializer)
847847

848848
#undef IREP_ID_ONE

src/driver/sec_driver_parse_options.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ int sec_driver_parse_optionst::doit()
186186
}
187187
const auto& gf=goto_model.goto_functions.function_map.at(fname);
188188
local_value_set_analysist value_set_analysis(
189-
ns,gf.type,fname,summarydb,LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET);
189+
ns, gf.type, fname, summarydb);
190190
value_set_analysis.set_message_handler(get_message_handler());
191191
value_set_analysis(gf.body);
192192
value_set_analysis.output(gf.body, std::cout);
@@ -211,7 +211,10 @@ int sec_driver_parse_optionst::doit()
211211
if(!gf.body_available())
212212
continue;
213213
local_value_set_analysist value_set_analysis(
214-
ns,gf.type,id2string(fname),summarydb,LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET);
214+
ns,
215+
gf.type,
216+
id2string(fname),
217+
summarydb);
215218
value_set_analysis.set_message_handler(get_message_handler());
216219
value_set_analysis(gf.body);
217220
if(cmdline.isset("show-value-sets"))

src/pointer-analysis/external_value_set_expr.h

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,20 @@ inline const access_path_entry_exprt &to_access_path_entry(const exprt &e)
6464
return static_cast<const access_path_entry_exprt &>(e);
6565
}
6666

67-
enum local_value_set_analysis_modet
67+
enum class external_value_set_typet
6868
{
69-
LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET,
70-
LOCAL_VALUE_SET_ANALYSIS_EXTERNAL_SET_PER_ACCESS_PATH
69+
/// ROOT_OBJECT EVSs are what static objects and parameters point to at the
70+
/// entry point of a function
71+
ROOT_OBJECT,
72+
/// PER_FIELD EVSs are for accessing a field of an external object. They
73+
/// only keep track of the last field of the access path, and the type of
74+
/// the object that that is a field of. They are always safe, even if
75+
/// two external objects alias each other, but they can be quite imprecise.
76+
PER_FIELD,
77+
/// PRECISE EVSs are for accessing a field of an external object. They keep
78+
/// track of the whole access path. At times it is not safe to use them
79+
/// because of aliasing, and we must fall back to PER_FIELD EVSs.
80+
PRECISE
7181
};
7282

7383
// Represents an external unknown points-to set that can't be
@@ -90,21 +100,26 @@ class external_value_set_exprt:public exprt
90100
external_value_set_exprt(
91101
const typet &type,
92102
const constant_exprt &_label,
93-
const local_value_set_analysis_modet mode,
103+
const external_value_set_typet mode,
94104
bool is_initializer):
95105
exprt(ID_external_value_set, type)
96106
{
97107
operands().resize(2);
98108
op0()=_label;
99109
/// No need to initialise op1(). op1().operands() will hold the vector of
100110
/// access path entries.
101-
set(ID_lvsa_mode, std::to_string(static_cast<int>(mode)));
111+
set(ID_lvsa_evs_type, std::to_string(static_cast<int>(mode)));
102112
set(ID_is_initializer, std::to_string(is_initializer ? 1 : 0));
103113
}
104114

105-
local_value_set_analysis_modet analysis_mode() const
115+
external_value_set_typet get_external_value_set_type() const
106116
{
107-
return (local_value_set_analysis_modet)get_int(ID_lvsa_mode);
117+
return static_cast<external_value_set_typet>(get_int(ID_lvsa_evs_type));
118+
}
119+
120+
void set_external_value_set_type(external_value_set_typet evs_type)
121+
{
122+
set(ID_lvsa_evs_type, std::to_string(static_cast<int>(evs_type)));
108123
}
109124

110125
/// At the beginning of a function, the value set for EVS("A.b") is
@@ -136,13 +151,21 @@ class external_value_set_exprt:public exprt
136151

137152
std::string get_access_path_label() const
138153
{
139-
if(analysis_mode()==LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET)
154+
switch(get_external_value_set_type())
155+
{
156+
case external_value_set_typet::PER_FIELD:
140157
return "external_objects";
141-
std::ostringstream ret;
142-
ret << id2string(label().get_value());
143-
for(const access_path_entry_exprt &entry : access_path_entries())
144-
ret << id2string(entry.label());
145-
return ret.str();
158+
case external_value_set_typet::PRECISE:
159+
{
160+
std::ostringstream ret;
161+
ret << id2string(label().get_value());
162+
for(const access_path_entry_exprt &entry : access_path_entries())
163+
ret << id2string(entry.label());
164+
return ret.str();
165+
}
166+
default:
167+
UNREACHABLE;
168+
}
146169
}
147170

148171
std::string type_to_basename(const typet &type) const
@@ -158,19 +181,29 @@ class external_value_set_exprt:public exprt
158181

159182
std::string get_access_path_basename(const typet &declared_on_type) const
160183
{
161-
if(analysis_mode()==LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET)
184+
switch(get_external_value_set_type())
185+
{
186+
case external_value_set_typet::PER_FIELD:
162187
return "external_objects"+type_to_basename(declared_on_type);
163-
assert(!access_path_entries().empty());
164-
std::ostringstream ret;
165-
ret << id2string(label().get_value());
166-
for(
167-
auto it=access_path_entries().begin();
168-
it!=std::prev(access_path_entries().end());
169-
++it)
188+
case external_value_set_typet::PRECISE:
170189
{
171-
ret << id2string(it->label());
190+
DATA_INVARIANT(
191+
!access_path_entries().empty(),
192+
"Only root object EVSs can have an empty access path");
193+
std::ostringstream ret;
194+
ret << id2string(label().get_value());
195+
for(
196+
auto it=access_path_entries().begin();
197+
it!=std::prev(access_path_entries().end());
198+
++it)
199+
{
200+
ret << id2string(it->label());
201+
}
202+
return ret.str();
203+
}
204+
default:
205+
UNREACHABLE;
172206
}
173-
return ret.str();
174207
}
175208
bool access_path_loops() const
176209
{
@@ -183,9 +216,14 @@ class external_value_set_exprt:public exprt
183216
access_path_entries().push_back(access_path_entry_exprt::get_loop_tag());
184217
}
185218

186-
void extend_access_path(const access_path_entry_exprt &newentry)
219+
void extend_access_path(
220+
const access_path_entry_exprt &newentry, external_value_set_typet evs_type)
187221
{
188-
if(analysis_mode()==LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET)
222+
PRECONDITION(evs_type!=external_value_set_typet::ROOT_OBJECT);
223+
set_external_value_set_type(evs_type);
224+
switch(evs_type)
225+
{
226+
case external_value_set_typet::PER_FIELD:
189227
{
190228
// Any attempt to extend a path yields <all-externals>->fieldname
191229
label()=constant_exprt("external_objects", string_typet());
@@ -197,8 +235,9 @@ class external_value_set_exprt:public exprt
197235
access_path_entries().push_back(toadd);
198236
else
199237
access_path_entries().back()=toadd;
238+
break;
200239
}
201-
else
240+
case external_value_set_typet::PRECISE:
202241
{
203242
if(access_path_loops())
204243
{
@@ -217,6 +256,11 @@ class external_value_set_exprt:public exprt
217256
}
218257
access_path_entries().push_back(newentry);
219258
}
259+
break;
260+
}
261+
default:
262+
UNREACHABLE;
263+
break;
220264
}
221265
}
222266

src/pointer-analysis/local_value_set.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ void local_value_sett::get_value_set_rec(
203203
std::to_string(location_number),
204204
declared_on_type);
205205
external_value_set_exprt new_ext_set=extinit;
206-
new_ext_set.extend_access_path(newentry);
206+
new_ext_set.extend_access_path(
207+
newentry, external_value_set_typet::PER_FIELD);
207208
new_ext_set.type()=field_type.subtype();
208209

209210
// TODO: figure out how to do this sort of on-demand-insert
@@ -472,7 +473,8 @@ void local_value_sett::assign_rec(
472473
std::to_string(location_number),
473474
declared_on_type);
474475
external_value_set_exprt new_ext_set=evsi;
475-
new_ext_set.extend_access_path(newentry);
476+
new_ext_set.extend_access_path(
477+
newentry, external_value_set_typet::PER_FIELD);
476478

477479
const std::string basename=
478480
new_ext_set.get_access_path_basename(declared_on_type);

src/pointer-analysis/local_value_set_analysis.cpp

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ void local_value_set_analysist::initialize(const goto_programt &fun)
8383
external_value_set_exprt extsym_var(
8484
extsym.type().subtype(),
8585
constant_exprt(extsym_name, string_typet()),
86-
mode,
86+
external_value_set_typet::ROOT_OBJECT,
8787
true);
8888
initial_state.insert(extsym_entry.object_map, extsym_var);
8989
}
@@ -116,9 +116,14 @@ static void get_all_field_value_sets(
116116
}
117117
}
118118

119-
void local_value_set_analysist::transform_function_stub_single_external_set(
119+
120+
void local_value_set_analysist::transform_function_stub(
120121
const irep_idt &fname, statet &state, locationt l_call, locationt l_return)
121122
{
123+
if(!summarydb.contains(fname))
124+
return;
125+
126+
// Execute a summary description for function fname.
122127
++nstubs;
123128

124129
const symbolt &function_symbol=ns.lookup(fname);
@@ -293,25 +298,6 @@ void local_value_set_analysist::transform_function_stub_single_external_set(
293298
}
294299
}
295300

296-
void local_value_set_analysist::transform_function_stub(
297-
const irep_idt &fname,
298-
statet &state,
299-
locationt l_call,
300-
locationt l_return)
301-
{
302-
// Execute a summary description for function fname.
303-
if(!summarydb.contains(fname))
304-
return;
305-
switch(mode)
306-
{
307-
case LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET:
308-
transform_function_stub_single_external_set(fname, state, l_call, l_return);
309-
break;
310-
default:
311-
throw "summaries not implemented";
312-
}
313-
}
314-
315301
void local_value_set_analysist::save_summary(const goto_programt &goto_program)
316302
{
317303
assert(goto_program.instructions.size()!=0);

src/pointer-analysis/local_value_set_analysis.h

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,41 +69,40 @@ class local_value_set_analysist
6969
const namespacet& ns,
7070
const code_typet& ftype,
7171
const std::string& fname,
72-
dbt& summarydb,
73-
local_value_set_analysis_modet m)
72+
dbt& summarydb)
7473
: baset(ns),
7574
nstubs(0),
7675
nstub_assignments(0),
7776
function_type(ftype),
7877
function_name(fname),
79-
mode(m),
8078
summarydb(summarydb)
8179
{ }
8280

83-
virtual void initialize(const goto_programt &goto_program);
81+
virtual void initialize(const goto_programt &goto_program) override;
8482

8583
// Use summaries for all function calls (TODO: recursion and mutual recursion)
86-
virtual bool should_enter_function(const irep_idt& f) { return false; }
84+
virtual bool should_enter_function(const irep_idt& f) override
85+
{
86+
return false;
87+
}
8788

88-
void transform_function_stub_single_external_set(
89-
const irep_idt& fname, statet& state, locationt l_call, locationt l_return);
9089
virtual void transform_function_stub(
91-
const irep_idt& fname, statet& state, locationt l_call, locationt l_return);
90+
const irep_idt& fname, statet& state, locationt l_call, locationt l_return)
91+
override;
9292

9393
void save_summary(const goto_programt&);
9494

95-
bool is_singular(const std::set<exprt> &);
95+
virtual bool is_singular(const std::set<exprt> &) override;
9696

9797
size_t nstubs;
9898
size_t nstub_assignments;
9999

100100
protected:
101101
const code_typet& function_type;
102102
const irep_idt function_name;
103-
const local_value_set_analysis_modet mode;
104103
dbt &summarydb;
105104

106-
virtual bool get_ignore_recursion() { return false; }
105+
virtual bool get_ignore_recursion() override { return false; }
107106
};
108107

109108
#endif

src/taint-analysis/taint_summary.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ static exprt transform_external_objects(const exprt& e)
124124
"",
125125
"",
126126
typet());
127-
evs_copy.extend_access_path(new_entry);
127+
evs_copy.extend_access_path(new_entry, external_value_set_typet::PER_FIELD);
128128
evs_copy.label()=constant_exprt("external_objects",string_typet());
129129
evs_copy.type()=e.type();
130130
evs_copy.remove("modified");
@@ -136,7 +136,7 @@ static exprt transform_external_objects(const exprt& e)
136136
// to be an array access, and is rewritten to (any array)
137137
auto evs_copy=to_external_value_set(e);
138138
access_path_entry_exprt new_entry("[]","","",typet());
139-
evs_copy.extend_access_path(new_entry);
139+
evs_copy.extend_access_path(new_entry, external_value_set_typet::PER_FIELD);
140140
evs_copy.label()=constant_exprt("external_objects",string_typet());
141141
evs_copy.type()=e.type();
142142
evs_copy.remove("modified");
@@ -1474,8 +1474,7 @@ void taint_algorithm_computing_summary_of_functiont::
14741474
program->get_namespace(),
14751475
fn_to_summarise.type,
14761476
id2string(function_id),
1477-
lvsa_db,
1478-
LOCAL_VALUE_SET_ANALYSIS_SINGLE_EXTERNAL_SET);
1477+
lvsa_db);
14791478
lvsa.set_message_handler(log->get_message_handler());
14801479
lvsa(fn_to_summarise.body);
14811480
// Retain this summary for use analysing callers.

0 commit comments

Comments
 (0)