Skip to content

Commit a2e3af5

Browse files
authored
Merge pull request diffblue#1744 from smowton/smowton/feature/instrument_cover_per_function
Coverage: support instrumenting one function at a time
2 parents 22ae7aa + 311af6d commit a2e3af5

File tree

5 files changed

+144
-74
lines changed

5 files changed

+144
-74
lines changed

src/goto-instrument/cover.cpp

+109-73
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ Date: May 2016
2020
#include <util/options.h>
2121

2222
#include "cover_basic_blocks.h"
23-
#include "cover_filter.h"
24-
#include "cover_instrument.h"
2523

2624
/// Applies instrumenters to given goto program
2725
/// \param goto_program: the goto program
@@ -165,91 +163,53 @@ void parse_cover_options(const cmdlinet &cmdline, optionst &options)
165163
cmdline.isset("cover-traces-must-terminate"));
166164
}
167165

168-
/// Applies instrumenters to given goto functions
169-
/// \param goto_functions: the goto functions
170-
/// \param instrumenters: the instrumenters
171-
/// \param function_filters: function filters to discard certain functions
172-
/// \param message_handler: a message handler
173-
void instrument_cover_goals(
174-
goto_functionst &goto_functions,
175-
const cover_instrumenterst &instrumenters,
176-
const function_filterst &function_filters,
177-
message_handlert &message_handler)
178-
{
179-
Forall_goto_functions(f_it, goto_functions)
180-
{
181-
if(!function_filters(f_it->first, f_it->second))
182-
continue;
183-
184-
instrument_cover_goals(f_it->second.body, instrumenters, message_handler);
185-
}
186-
}
187-
188-
/// Instruments goto functions based on given command line options
189-
/// \param options: the options
190-
/// \param symbol_table: the symbol table
191-
/// \param goto_functions: the goto functions
192-
/// \param message_handler: a message handler
193-
bool instrument_cover_goals(
166+
/// Build data structures controlling coverage from command-line options.
167+
/// \param options: command-line options
168+
/// \param symbol_table: global symbol table
169+
/// \param message_handler: used to log incorrect option specifications
170+
/// \return a cover_configt on success, or null otherwise.
171+
std::unique_ptr<cover_configt> get_cover_config(
194172
const optionst &options,
195173
const symbol_tablet &symbol_table,
196-
goto_functionst &goto_functions,
197174
message_handlert &message_handler)
198175
{
199176
messaget msg(message_handler);
177+
std::unique_ptr<cover_configt> config = util_make_unique<cover_configt>();
178+
function_filterst &function_filters = config->function_filters;
179+
goal_filterst &goal_filters = config->goal_filters;
180+
cover_instrumenterst &instrumenters = config->cover_instrumenters;
200181

201-
function_filterst function_filters;
202182
function_filters.add(
203183
util_make_unique<internal_functions_filtert>(message_handler));
204184

205-
goal_filterst goal_filters;
206185
goal_filters.add(util_make_unique<internal_goals_filtert>(message_handler));
207186

208-
cover_instrumenterst instrumenters;
209-
210187
optionst::value_listt criteria_strings = options.get_list_option("cover");
211-
bool keep_assertions=false;
212188

189+
config->keep_assertions = false;
213190
for(const auto &criterion_string : criteria_strings)
214191
{
215192
try
216193
{
217194
coverage_criteriont c = parse_coverage_criterion(criterion_string);
218195

219196
if(c == coverage_criteriont::ASSERTION)
220-
keep_assertions = true;
197+
config->keep_assertions = true;
221198

222199
instrumenters.add_from_criterion(c, symbol_table, goal_filters);
223200
}
224201
catch(const std::string &e)
225202
{
226203
msg.error() << e << messaget::eom;
227-
return true;
204+
return {};
228205
}
229206
}
230207

231-
if(keep_assertions && criteria_strings.size()>1)
208+
if(config->keep_assertions && criteria_strings.size()>1)
232209
{
233210
msg.error() << "assertion coverage cannot currently be used together with "
234211
<< "other coverage criteria" << messaget::eom;
235-
return true;
236-
}
237-
238-
msg.status() << "Rewriting existing assertions as assumptions"
239-
<< messaget::eom;
240-
241-
if(!keep_assertions)
242-
{
243-
// turn assertions (from generic checks) into assumptions
244-
Forall_goto_functions(f_it, goto_functions)
245-
{
246-
goto_programt &body=f_it->second.body;
247-
Forall_goto_program_instructions(i_it, body)
248-
{
249-
if(i_it->is_assert())
250-
i_it->type=goto_program_instruction_typet::ASSUME;
251-
}
252-
}
212+
return {};
253213
}
254214

255215
// cover entry point function only
@@ -266,32 +226,108 @@ bool instrument_cover_goals(
266226
function_filters.add(
267227
util_make_unique<trivial_functions_filtert>(message_handler));
268228

269-
msg.status() << "Instrumenting coverage goals" << messaget::eom;
270-
271-
instrument_cover_goals(
272-
goto_functions, instrumenters, function_filters, message_handler);
229+
config->traces_must_terminate =
230+
options.get_bool_option("cover-traces-must-terminate");
273231

274-
function_filters.report_anomalies();
275-
goal_filters.report_anomalies();
232+
return config;
233+
}
276234

277-
if(options.get_bool_option("cover-traces-must-terminate"))
235+
/// Instruments a single goto program based on the given configuration
236+
/// \param config: configuration, produced using get_cover_config
237+
/// \param function_id: function name
238+
/// \param function: function function to instrument
239+
/// \param message_handler: log output
240+
static void instrument_cover_goals(
241+
const cover_configt &config,
242+
const irep_idt &function_id,
243+
goto_functionst::goto_functiont &function,
244+
message_handlert &message_handler)
245+
{
246+
if(!config.keep_assertions)
278247
{
279-
// instrument an additional goal in CPROVER_START. This will rephrase
280-
// the reachability problem by asking BMC to provide a solution that
281-
// satisfies a goal while getting to the end of the program-under-test.
282-
const auto sf_it=
283-
goto_functions.function_map.find(goto_functions.entry_point());
284-
if(sf_it==goto_functions.function_map.end())
248+
Forall_goto_program_instructions(i_it, function.body)
285249
{
286-
msg.error() << "cover-traces-must-terminate: invalid entry point ["
287-
<< goto_functions.entry_point() << "]" << messaget::eom;
288-
return true;
250+
if(i_it->is_assert())
251+
i_it->type=goto_program_instruction_typet::ASSUME;
289252
}
253+
}
254+
255+
bool changed = false;
290256

291-
cover_instrument_end_of_function(sf_it->first, sf_it->second.body);
257+
if(config.function_filters(function_id, function))
258+
{
259+
instrument_cover_goals(
260+
function.body, config.cover_instrumenters, message_handler);
261+
changed = true;
262+
}
263+
264+
if(config.traces_must_terminate &&
265+
function_id == goto_functionst::entry_point())
266+
{
267+
cover_instrument_end_of_function(function_id, function.body);
268+
changed = true;
269+
}
270+
271+
if(changed)
272+
function.body.update();
273+
}
274+
275+
/// Instruments a single goto program based on the given configuration
276+
/// \param config: configuration, produced using get_cover_config
277+
/// \param function: goto program to instrument
278+
/// \param message_handler: log output
279+
void instrument_cover_goals(
280+
const cover_configt &config,
281+
goto_model_functiont &function,
282+
message_handlert &message_handler)
283+
{
284+
instrument_cover_goals(
285+
config,
286+
function.get_function_id(),
287+
function.get_goto_function(),
288+
message_handler);
289+
290+
function.compute_location_numbers();
291+
}
292+
293+
/// Instruments goto functions based on given command line options
294+
/// \param options: the options
295+
/// \param symbol_table: the symbol table
296+
/// \param goto_functions: the goto functions
297+
/// \param message_handler: a message handler
298+
bool instrument_cover_goals(
299+
const optionst &options,
300+
const symbol_tablet &symbol_table,
301+
goto_functionst &goto_functions,
302+
message_handlert &message_handler)
303+
{
304+
messaget msg(message_handler);
305+
msg.status() << "Rewriting existing assertions as assumptions"
306+
<< messaget::eom;
307+
308+
std::unique_ptr<cover_configt> config =
309+
get_cover_config(options, symbol_table, message_handler);
310+
if(!config)
311+
return true;
312+
313+
if(config->traces_must_terminate &&
314+
!goto_functions.function_map.count(goto_functions.entry_point()))
315+
{
316+
msg.error() << "cover-traces-must-terminate: invalid entry point ["
317+
<< goto_functions.entry_point() << "]" << messaget::eom;
318+
return true;
292319
}
293320

294-
goto_functions.update();
321+
Forall_goto_functions(f_it, goto_functions)
322+
{
323+
instrument_cover_goals(
324+
*config, f_it->first, f_it->second, message_handler);
325+
}
326+
goto_functions.compute_location_numbers();
327+
328+
config->function_filters.report_anomalies();
329+
config->goal_filters.report_anomalies();
330+
295331
return false;
296332
}
297333

src/goto-instrument/cover.h

+19
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Date: May 2016
1515
#define CPROVER_GOTO_INSTRUMENT_COVER_H
1616

1717
#include <goto-programs/goto_model.h>
18+
#include "cover_filter.h"
19+
#include "cover_instrument.h"
1820

1921
class message_handlert;
2022
class cmdlinet;
@@ -32,6 +34,15 @@ enum class coverage_criteriont
3234
COVER // __CPROVER_cover(x) annotations
3335
};
3436

37+
struct cover_configt
38+
{
39+
bool keep_assertions;
40+
bool traces_must_terminate;
41+
function_filterst function_filters;
42+
goal_filterst goal_filters;
43+
cover_instrumenterst cover_instrumenters;
44+
};
45+
3546
void instrument_cover_goals(
3647
const symbol_tablet &,
3748
goto_functionst &,
@@ -44,6 +55,14 @@ void instrument_cover_goals(
4455
coverage_criteriont,
4556
message_handlert &message_handler);
4657

58+
std::unique_ptr<cover_configt> get_cover_config(
59+
const optionst &, const symbol_tablet &, message_handlert &);
60+
61+
void instrument_cover_goals(
62+
const cover_configt &,
63+
goto_model_functiont &,
64+
message_handlert &);
65+
4766
void parse_cover_options(const cmdlinet &, optionst &);
4867

4968
bool instrument_cover_goals(

src/goto-programs/goto_model.h

+10
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ class goto_model_functiont
8686
goto_model_functiont(
8787
journalling_symbol_tablet &symbol_table,
8888
goto_functionst &goto_functions,
89+
const irep_idt &function_id,
8990
goto_functionst::goto_functiont &goto_function):
9091
symbol_table(symbol_table),
9192
goto_functions(goto_functions),
93+
function_id(function_id),
9294
goto_function(goto_function)
9395
{
9496
}
@@ -117,9 +119,17 @@ class goto_model_functiont
117119
return goto_function;
118120
}
119121

122+
/// Get function id
123+
/// \return `goto_function`'s name (its key in `goto_functions`)
124+
const irep_idt &get_function_id()
125+
{
126+
return function_id;
127+
}
128+
120129
private:
121130
journalling_symbol_tablet &symbol_table;
122131
goto_functionst &goto_functions;
132+
irep_idt function_id;
123133
goto_functionst::goto_functiont &goto_function;
124134
};
125135

src/goto-programs/lazy_goto_functions_map.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class lazy_goto_functions_mapt final
4949

5050
typedef
5151
std::function<void(
52+
const irep_idt &name,
5253
goto_functionst::goto_functiont &function,
5354
journalling_symbol_tablet &function_symbols)>
5455
post_process_functiont;
@@ -128,7 +129,7 @@ class lazy_goto_functions_mapt final
128129
if(processed_functions.count(name)==0)
129130
{
130131
// Run function-pass conversions
131-
post_process_function(function, journalling_table);
132+
post_process_function(name, function, journalling_table);
132133
// Assign procedure-local location numbers for now
133134
function.body.compute_location_numbers();
134135
processed_functions.insert(name);

src/goto-programs/lazy_goto_model.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ lazy_goto_modelt::lazy_goto_modelt(
2929
language_files,
3030
symbol_table,
3131
[this] (
32+
const irep_idt &function_name,
3233
goto_functionst::goto_functiont &function,
3334
journalling_symbol_tablet &journalling_symbol_table) -> void
3435
{
3536
goto_model_functiont model_function(
3637
journalling_symbol_table,
3738
goto_model->goto_functions,
39+
function_name,
3840
function);
3941
this->post_process_function(model_function, *this);
4042
},
@@ -54,12 +56,14 @@ lazy_goto_modelt::lazy_goto_modelt(lazy_goto_modelt &&other)
5456
language_files,
5557
symbol_table,
5658
[this] (
59+
const irep_idt &function_name,
5760
goto_functionst::goto_functiont &function,
5861
journalling_symbol_tablet &journalling_symbol_table) -> void
5962
{
6063
goto_model_functiont model_function(
6164
journalling_symbol_table,
6265
goto_model->goto_functions,
66+
function_name,
6367
function);
6468
this->post_process_function(model_function, *this);
6569
},

0 commit comments

Comments
 (0)