CBMC
cover_basic_blocks.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Coverage Instrumentation
4 
5 Author: Peter Schrammel
6 
7 \*******************************************************************/
8 
11 
12 #include "cover_basic_blocks.h"
13 
14 #include <util/message.h>
15 
16 std::optional<std::size_t> cover_basic_blockst::continuation_of_block(
17  const goto_programt::const_targett &instruction,
19 {
20  if(instruction->incoming_edges.size() != 1)
21  return {};
22 
23  const goto_programt::targett in_t = *instruction->incoming_edges.cbegin();
24  if(
25  in_t->is_goto() && !in_t->is_backwards_goto() &&
26  in_t->condition().is_true())
27  return block_map[in_t];
28 
29  return {};
30 }
31 
32 static bool
34 {
35  return a.get_file() == b.get_file() && a.get_line() == b.get_line();
36 }
37 
39 {
40  bool next_is_target = true;
41  const goto_programt::instructiont *preceding_assume = nullptr;
42  std::size_t current_block = 0;
43 
44  forall_goto_program_instructions(it, goto_program)
45  {
46  // For the purposes of coverage blocks, multiple consecutive assume
47  // instructions with the same source location are considered to be part of
48  // the same block. Assumptions should terminate a block, as subsequent
49  // instructions may be unreachable. However check instrumentation passes
50  // may insert multiple assertions in the same program location. Therefore
51  // these are combined for reasons of readability of the coverage output.
52  bool end_of_assume_group =
53  preceding_assume &&
54  !(it->is_assume() &&
56  preceding_assume->source_location(), it->source_location()));
57 
58  // Is it a potential beginning of a block?
59  if(next_is_target || it->is_target() || end_of_assume_group)
60  {
61  if(auto block_number = continuation_of_block(it, block_map))
62  {
63  current_block = *block_number;
64  }
65  else
66  {
67  block_infos.emplace_back();
68  block_infos.back().representative_inst = it;
69  block_infos.back().source_location = source_locationt::nil();
70  current_block = block_infos.size() - 1;
71  }
72  }
73 
74  INVARIANT(
75  current_block < block_infos.size(), "current block number out of range");
76  block_infot &block_info = block_infos.at(current_block);
77 
78  block_map[it] = current_block;
79 
80  add_block_lines(block_info, *it);
81 
82  // set representative program location to instrument
83  if(
84  !it->source_location().is_nil() &&
85  !it->source_location().get_file().empty() &&
86  !it->source_location().get_line().empty() &&
87  !it->source_location().is_built_in() &&
88  block_info.source_location.is_nil())
89  {
90  block_info.representative_inst = it; // update
91  block_info.source_location = it->source_location();
92  }
93 
94  next_is_target = it->is_goto() || it->is_function_call();
95  preceding_assume = it->is_assume() ? &*it : nullptr;
96  }
97 }
98 
100 {
101  const auto it = block_map.find(t);
102  INVARIANT(it != block_map.end(), "instruction must be part of a block");
103  return it->second;
104 }
105 
106 std::optional<goto_programt::const_targett>
107 cover_basic_blockst::instruction_of(const std::size_t block_nr) const
108 {
109  INVARIANT(block_nr < block_infos.size(), "block number out of range");
110  return block_infos[block_nr].representative_inst;
111 }
112 
113 const source_locationt &
114 cover_basic_blockst::source_location_of(const std::size_t block_nr) const
115 {
116  INVARIANT(block_nr < block_infos.size(), "block number out of range");
117  return block_infos[block_nr].source_location;
118 }
119 
120 const source_linest &
121 cover_basic_blockst::source_lines_of(const std::size_t block_nr) const
122 {
123  INVARIANT(block_nr < block_infos.size(), "block number out of range");
124  return block_infos[block_nr].source_lines;
125 }
126 
128  const irep_idt &function_id,
129  const goto_programt &goto_program,
130  message_handlert &message_handler)
131 {
132  messaget msg(message_handler);
133  std::set<std::size_t> blocks_seen;
134  forall_goto_program_instructions(it, goto_program)
135  {
136  const std::size_t block_nr = block_of(it);
137  const block_infot &block_info = block_infos.at(block_nr);
138 
139  if(
140  blocks_seen.insert(block_nr).second &&
141  block_info.representative_inst == goto_program.instructions.end())
142  {
143  msg.warning() << "Ignoring block " << (block_nr + 1) << " location "
144  << it->location_number << " " << it->source_location()
145  << " (bytecode-index already instrumented)"
146  << messaget::eom;
147  }
148  else if(
149  block_info.representative_inst == it &&
150  block_info.source_location.is_nil())
151  {
152  msg.warning() << "Ignoring block " << (block_nr + 1) << " location "
153  << it->location_number << " " << function_id
154  << " (missing source location)" << messaget::eom;
155  }
156  // The location numbers printed here are those
157  // before the coverage instrumentation.
158  }
159 }
160 
161 void cover_basic_blockst::output(std::ostream &out) const
162 {
163  for(const auto &block_pair : block_map)
164  out << block_pair.first->source_location() << " -> " << block_pair.second
165  << '\n';
166 }
167 
170  const goto_programt::instructiont &instruction)
171 {
172  const auto &add_location = [&](const source_locationt &location) {
173  const irep_idt &line = location.get_line();
174  if(!line.empty())
175  {
176  block.source_lines.insert(location);
177  }
178  };
179  add_location(instruction.source_location());
180  instruction.code().visit_pre([&](const exprt &expr) {
181  const auto &location = expr.source_location();
182  if(!location.get_function().empty())
183  add_location(location);
184  });
185 }
186 
188  const goto_programt &_goto_program)
189 {
190  forall_goto_program_instructions(it, _goto_program)
191  {
192  const auto &location = it->source_location();
193  const auto &bytecode_index = location.get_java_bytecode_index();
194  auto entry = index_to_block.emplace(bytecode_index, block_infos.size());
195  if(entry.second)
196  {
197  block_infos.push_back(it);
198  block_locations.push_back(location);
199  block_source_lines.emplace_back(location);
200  }
201  else
202  {
203  block_source_lines[entry.first->second].insert(location);
204  }
205  }
206 }
207 
208 std::size_t
210 {
211  const auto &bytecode_index = t->source_location().get_java_bytecode_index();
212  const auto it = index_to_block.find(bytecode_index);
213  INVARIANT(it != index_to_block.end(), "instruction must be part of a block");
214  return it->second;
215 }
216 
217 std::optional<goto_programt::const_targett>
218 cover_basic_blocks_javat::instruction_of(const std::size_t block_nr) const
219 {
220  PRECONDITION(block_nr < block_infos.size());
221  return block_infos[block_nr];
222 }
223 
224 const source_locationt &
225 cover_basic_blocks_javat::source_location_of(const std::size_t block_nr) const
226 {
227  PRECONDITION(block_nr < block_locations.size());
228  return block_locations[block_nr];
229 }
230 
231 const source_linest &
232 cover_basic_blocks_javat::source_lines_of(const std::size_t block_nr) const
233 {
234  PRECONDITION(block_nr < block_locations.size());
235  return block_source_lines[block_nr];
236 }
237 
238 void cover_basic_blocks_javat::output(std::ostream &out) const
239 {
240  for(std::size_t i = 0; i < block_locations.size(); ++i)
241  out << block_locations[i] << " -> " << i << '\n';
242 }
cover_basic_blocks_javat(const goto_programt &_goto_program)
std::vector< goto_programt::const_targett > block_infos
const source_locationt & source_location_of(std::size_t block_number) const override
std::vector< source_locationt > block_locations
void output(std::ostream &out) const override
Outputs the list of blocks.
std::size_t block_of(goto_programt::const_targett t) const override
const source_linest & source_lines_of(std::size_t block_number) const override
std::vector< source_linest > block_source_lines
std::optional< goto_programt::const_targett > instruction_of(std::size_t block_number) const override
std::unordered_map< irep_idt, std::size_t > index_to_block
void output(std::ostream &out) const override
Outputs the list of blocks.
std::optional< goto_programt::const_targett > instruction_of(std::size_t block_nr) const override
static std::optional< std::size_t > continuation_of_block(const goto_programt::const_targett &instruction, block_mapt &block_map)
If this block is a continuation of a previous block through unconditional forward gotos,...
cover_basic_blockst(const goto_programt &goto_program)
std::map< goto_programt::const_targett, std::size_t, goto_programt::target_less_than > block_mapt
std::vector< block_infot > block_infos
map block numbers to block information
void report_block_anomalies(const irep_idt &function_id, const goto_programt &goto_program, message_handlert &message_handler) override
Output warnings about ignored blocks.
const source_linest & source_lines_of(std::size_t block_nr) const override
std::size_t block_of(goto_programt::const_targett t) const override
static void add_block_lines(cover_basic_blockst::block_infot &block, const goto_programt::instructiont &instruction)
Adds the lines which instruction spans to block.
const source_locationt & source_location_of(std::size_t block_nr) const override
block_mapt block_map
map program locations to block numbers
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
Base class for all expressions.
Definition: expr.h:56
const source_locationt & source_location() const
Definition: expr.h:231
void visit_pre(std::function< void(exprt &)>)
Definition: expr.cpp:227
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
const goto_instruction_codet & code() const
Get the code represented by this instruction.
Definition: goto_program.h:188
const source_locationt & source_location() const
Definition: goto_program.h:333
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
instructionst::iterator targett
Definition: goto_program.h:614
instructionst::const_iterator const_targett
Definition: goto_program.h:615
bool is_nil() const
Definition: irep.h:364
source_locationt source_location
Definition: message.h:247
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
mstreamt & warning() const
Definition: message.h:404
static eomt eom
Definition: message.h:297
void insert(const source_locationt &loc)
Insert a line (a source location) into the set of lines.
static const source_locationt & nil()
const irep_idt & get_line() const
const irep_idt & get_file() const
static bool same_source_line(const source_locationt &a, const source_locationt &b)
Basic blocks detection for Coverage Instrumentation.
#define forall_goto_program_instructions(it, program)
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
std::optional< goto_programt::const_targett > representative_inst
the program location to instrument for this block
source_locationt source_location
the source location representative for this block (we need a separate copy of source locations becaus...
source_linest source_lines
the set of source code lines belonging to this block