Skip to content

Commit 7909d15

Browse files
authored
Merge pull request #8628 from tautschnig/do-not-instrument-unused-functions
DFCC instrumentation: skip unused functions
2 parents 9db5b1a + 0c5644b commit 7909d15

File tree

3 files changed

+65
-18
lines changed
  • regression/contracts-dfcc/skip_unused_instrumentation
  • src/goto-instrument/contracts/dynamic-frames

3 files changed

+65
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Using a forward declaration rather than including netdb.h to make sure we do
2+
// not have the compiled body of functions from header files available right
3+
// away.
4+
struct hostent;
5+
struct hostent *gethostbyname(const char *name);
6+
7+
int main()
8+
{
9+
(void)gethostbyname("x");
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
This test checks that functions brought in from header files when loading
10+
entries from the model library are not subject to instrumentation (when those
11+
functions are never used). Else we end up with invariant failures like:
12+
[...]
13+
Instrumenting '__bswap_16'
14+
--- begin invariant violation report ---
15+
Invariant check failed
16+
File: /src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp:329 function: instrument_function
17+
Condition: Precondition
18+
Reason: found != goto_model.goto_functions.function_map.end()
19+
Backtrace:
20+
build/bin/goto-instrument(+0xbfe182) [0x649c3d22b182]
21+
[...]
22+
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x78dc2f029d90]
23+
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x78dc2f029e40]
24+
build/bin/goto-instrument(+0x363cb5) [0x649c3c990cb5]
25+
26+
Diagnostics:
27+
<< EXTRA DIAGNOSTICS >>
28+
Function '__bswap_16' must exist in the model.
29+
<< END EXTRA DIAGNOSTICS >>
30+
31+
--- end invariant violation report ---

src/goto-instrument/contracts/dynamic-frames/dfcc.cpp

+24-18
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Author: Remi Delmas, [email protected]
3838
#include <ansi-c/goto-conversion/link_to_library.h>
3939
#include <goto-instrument/contracts/cfg_info.h>
4040
#include <goto-instrument/contracts/utils.h>
41+
#include <goto-instrument/generate_function_bodies.h>
4142
#include <goto-instrument/nondet_static.h>
4243
#include <langapi/language.h>
4344
#include <langapi/language_file.h>
@@ -257,6 +258,12 @@ void dfcct::partition_function_symbols(
257258
std::set<irep_idt> &contract_symbols,
258259
std::set<irep_idt> &other_symbols)
259260
{
261+
std::set<irep_idt> called_functions;
262+
find_used_functions(
263+
goto_functionst::entry_point(),
264+
goto_model.goto_functions,
265+
called_functions);
266+
260267
// collect contract and other symbols
261268
for(auto &entry : goto_model.symbol_table)
262269
{
@@ -272,7 +279,7 @@ void dfcct::partition_function_symbols(
272279
{
273280
contract_symbols.insert(sym_name);
274281
}
275-
else
282+
else if(called_functions.find(sym_name) != called_functions.end())
276283
{
277284
// it is not a contract
278285
other_symbols.insert(sym_name);
@@ -486,21 +493,6 @@ void dfcct::transform_goto_model()
486493

487494
library.inhibit_front_end_builtins();
488495

489-
// TODO implement a means to inhibit unreachable functions (possibly via the
490-
// code that implements drop-unused-functions followed by
491-
// generate-function-bodies):
492-
// Traverse the call tree from the given entry point to identify
493-
// functions symbols that are effectively called in the model,
494-
// Then goes over all functions of the model and turns the bodies of all
495-
// functions that are not in the used function set into:
496-
// ```c
497-
// assert(false, "function identified as unreachable");
498-
// assume(false);
499-
// ```
500-
// That way, if the analysis mistakenly pruned some functions, assertions
501-
// will be violated and the analysis will fail.
502-
// TODO: add a command line flag to tell the instrumentation to not prune
503-
// a function.
504496
goto_model.goto_functions.update();
505497

506498
remove_skip(goto_model);
@@ -510,11 +502,25 @@ void dfcct::transform_goto_model()
510502

511503
// This can prune too many functions if function pointers have not been
512504
// yet been removed or if the entry point is not defined.
513-
// Another solution would be to rewrite the bodies of functions that seem to
514-
// be unreachable into assert(false);assume(false)
505+
// TODO: add a command line flag to tell the instrumentation to not prune
506+
// a function.
515507
remove_unused_functions(goto_model, message_handler);
516508
goto_model.goto_functions.update();
517509

510+
// generate assert(0); assume(0); function bodies for all functions missing an
511+
// implementation (other than ones containing __CPROVER in their name)
512+
auto generate_implementation = generate_function_bodies_factory(
513+
"assert-false-assume-false",
514+
c_object_factory_parameterst{},
515+
goto_model.symbol_table,
516+
message_handler);
517+
generate_function_bodies(
518+
std::regex("(?!" CPROVER_PREFIX ").*"),
519+
*generate_implementation,
520+
goto_model,
521+
message_handler);
522+
goto_model.goto_functions.update();
523+
518524
reinitialize_model();
519525
}
520526

0 commit comments

Comments
 (0)