Skip to content

Commit 830d519

Browse files
Merge pull request #1830 from romainbrenguier/feature/cover-basic-block-java#TG-1404
[TG-1404] Specific implementation of cover basic block for Java
2 parents 3a112af + 63beb71 commit 830d519

17 files changed

+247
-131
lines changed

regression/cbmc-java/covered1/test.desc

+10-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,16 @@ covered1.class
44
^EXIT=0$
55
^SIGNAL=0$
66
.*\"coveredLines\": \"22\",$
7-
.*\"coveredLines\": \"4,6,7,23-25,31-33,36\",$
7+
.*\"coveredLines\": \"4\",$
8+
.*\"coveredLines\": \"6\",$
9+
.*\"coveredLines\": \"7\",$
10+
.*\"coveredLines\": \"23\",$
11+
.*\"coveredLines\": \"24\",$
12+
.*\"coveredLines\": \"25\",$
13+
.*\"coveredLines\": \"31\",$
14+
.*\"coveredLines\": \"32\",$
15+
.*\"coveredLines\": \"33\",$
16+
.*\"coveredLines\": \"36\",$
817
.*\"coveredLines\": \"26\",$
918
.*\"coveredLines\": \"28\",$
1019
.*\"coveredLines\": \"28\",$

regression/goto-diff/java-properties/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ old.jar --json-ui --show-properties --cover location
55
activate-multi-line-match
66
EXIT=0
77
SIGNAL=0
8-
"deletedFunctions": \[\n {\n "name": "java::Test\.obsolete:\(\)V",\n "properties": \[\n {\n "class": "coverage",\n "coveredLines": "18",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test\.obsolete:\(\)V\.coverage\.1",\n "sourceLocation": {\n "bytecodeIndex": "0",\n "file": "Test\.java",\n "function": "java::Test\.obsolete:\(\)V",\n "line": "18"\n }\n }\n ],\n "sourceLocation": {\n "file": "Test\.java",\n "function": "java::Test\.obsolete:\(\)V",\n "line": "18"\n }\n }\n ],\n "modifiedFunctions": \[\n {\n "name": "java::Test\.<init>:\(\)V",\n "properties": \[\n {\n "class": "coverage",\n "coveredLines": "6",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test\.<init>:\(\)V\.coverage\.1",\n "sourceLocation": {\n "bytecodeIndex": "1",\n "file": "Test\.java",\n "function": "java::Test\.<init>:\(\)V",\n "line": "6"\n }\n },\n {\n "class": "coverage",\n "coveredLines": "4",\n "description": "block 2",\n "expression": "false",\n "name": "java::Test\.<init>:\(\)V\.coverage\.2",\n "sourceLocation": {\n "bytecodeIndex": "3",\n "file": "Test\.java",\n "function": "java::Test\.<init>:\(\)V",\n "line": "4"\n }\n },\n {\n "class": "coverage",\n "coveredLines": "4",\n "description": "block 3",\n "expression": "false",\n "name": "java::Test\.<init>:\(\)V\.coverage\.3",\n "sourceLocation": {\n "bytecodeIndex": "5",\n "file": "Test\.java",\n "function": "java::Test\.<init>:\(\)V",\n "line": "4"\n }\n },\n {\n "class": "coverage",\n "coveredLines": "4,7",\n "description": "block 4",\n "expression": "false",\n "name": "java::Test\.<init>:\(\)V\.coverage\.4",\n "sourceLocation": {\n "bytecodeIndex": "6",\n "file": "Test\.java",\n "function": "java::Test\.<init>:\(\)V",\n "line": "4"\n }\n }\n ],\n "sourceLocation": {\n "file": "Test\.java",\n "function": "java::Test\.<init>:\(\)V",\n "line": "6"\n }\n },\n {\n "name": "java::Test\.<clinit>:\(\)V",\n "properties": \[\n {\n "class": "coverage",\n "coveredLines": "3",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test\.<clinit>:\(\)V\.coverage\.1",\n "sourceLocation": {\n "bytecodeIndex": "1",\n "file": "Test\.java",\n "function": "java::Test\.<clinit>:\(\)V",\n "line": "3"\n }\n }\n ],\n "sourceLocation": {\n "file": "Test\.java",\n "function": "java::Test\.<clinit>:\(\)V",\n "line": "3"\n }\n }\n ],\n "newFunctions": \[\n {\n "name": "java::Test\.newfun:\(\)V",\n "properties": \[\n {\n "class": "coverage",\n "coveredLines": "18",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test\.newfun:\(\)V\.coverage\.1",\n "sourceLocation": {\n "bytecodeIndex": "0",\n "file": "Test\.java",\n "function": "java::Test\.newfun:\(\)V",\n "line": "18"\n }\n }\n ],\n "sourceLocation": {\n "file": "Test\.java",\n "function": "java::Test\.newfun:\(\)V",\n "line": "18"\n }\n }\n ],\n
8+
"deletedFunctions": \[\n \{\n "name": "java::Test.obsolete:\(\)V",\n "properties": \[\n \{\n "class": "coverage",\n "coveredLines": "18",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test.obsolete:\(\)V.coverage.1",\n "sourceLocation": \{\n "bytecodeIndex": "0",\n "file": "Test.java",\n "function": "java::Test.obsolete:\(\)V",\n "line": "18"\n }\n }\n ],\n "sourceLocation": \{\n "file": "Test.java",\n "function": "java::Test.obsolete:\(\)V",\n "line": "18"\n }\n }\n ],\n "modifiedFunctions": \[\n \{\n "name": "java::Test.<init>:\(\)V",\n "properties": \[\n \{\n "class": "coverage",\n "coveredLines": "6",\n "description": "block 2",\n "expression": "false",\n "name": "java::Test.<init>:\(\)V.coverage.1",\n "sourceLocation": \{\n "bytecodeIndex": "1",\n "file": "Test.java",\n "function": "java::Test.<init>:\(\)V",\n "line": "6"\n }\n },\n \{\n "class": "coverage",\n "coveredLines": "4",\n "description": "block 3",\n "expression": "false",\n "name": "java::Test.<init>:\(\)V.coverage.2",\n "sourceLocation": \{\n "bytecodeIndex": "3",\n "file": "Test.java",\n "function": "java::Test.<init>:\(\)V",\n "line": "4"\n }\n },\n \{\n "class": "coverage",\n "coveredLines": "4",\n "description": "block 4",\n "expression": "false",\n "name": "java::Test.<init>:\(\)V.coverage.3",\n "sourceLocation": \{\n "bytecodeIndex": "5",\n "file": "Test.java",\n "function": "java::Test.<init>:\(\)V",\n "line": "4"\n }\n },\n \{\n "class": "coverage",\n "coveredLines": "4",\n "description": "block 5",\n "expression": "false",\n "name": "java::Test.<init>:\(\)V.coverage.4",\n "sourceLocation": \{\n "bytecodeIndex": "6",\n "file": "Test.java",\n "function": "java::Test.<init>:\(\)V",\n "line": "4"\n }\n },\n \{\n "class": "coverage",\n "coveredLines": "7",\n "description": "block 6",\n "expression": "false",\n "name": "java::Test.<init>:\(\)V.coverage.5",\n "sourceLocation": \{\n "bytecodeIndex": "7",\n "file": "Test.java",\n "function": "java::Test.<init>:\(\)V",\n "line": "7"\n }\n }\n ],\n "sourceLocation": \{\n "file": "Test.java",\n "function": "java::Test.<init>:\(\)V",\n "line": "6"\n }\n },\n \{\n "name": "java::Test.<clinit>:\(\)V",\n "properties": \[\n \{\n "class": "coverage",\n "coveredLines": "3",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test.<clinit>:\(\)V.coverage.1",\n "sourceLocation": \{\n "bytecodeIndex": "1",\n "file": "Test.java",\n "function": "java::Test.<clinit>:\(\)V",\n "line": "3"\n }\n }\n ],\n "sourceLocation": \{\n "file": "Test.java",\n "function": "java::Test.<clinit>:\(\)V",\n "line": "3"\n }\n }\n ],\n "newFunctions": \[\n \{\n "name": "java::Test.newfun:\(\)V",\n "properties": \[\n \{\n "class": "coverage",\n "coveredLines": "18",\n "description": "block 1",\n "expression": "false",\n "name": "java::Test.newfun:\(\)V.coverage.1",\n "sourceLocation": \{\n "bytecodeIndex": "0",\n "file": "Test.java",\n "function": "java::Test.newfun:\(\)V",\n "line": "18"\n }\n }\n ],\n "sourceLocation": \{\n "file": "Test.java",\n "function": "java::Test.newfun:\(\)V",\n "line": "18"\n }\n }\n ],\n
99
--
1010
^warning: ignoring

src/goto-instrument/Makefile

+5-2
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ INCLUDES= -I ..
9494

9595
LIBS =
9696

97-
CLEANFILES = goto-instrument$(EXEEXT)
97+
CLEANFILES = goto-instrument$(EXEEXT) goto-instrument$(LIBEXT)
9898

9999
include ../config.inc
100100
include ../common
101101

102-
all: goto-instrument$(EXEEXT)
102+
all: goto-instrument$(EXEEXT) goto-instrument$(LIBEXT)
103103

104104
ifneq ($(LIB_GLPK),)
105105
LIBS += $(LIB_GLPK)
@@ -111,6 +111,9 @@ endif
111111
goto-instrument$(EXEEXT): $(OBJ)
112112
$(LINKBIN)
113113

114+
goto-instrument$(LIBEXT): $(OBJ)
115+
$(LINKLIB)
116+
114117
.PHONY: goto-instrument-mac-signed
115118

116119
goto-instrument-mac-signed: goto-instrument$(EXEEXT)

src/goto-instrument/cover.cpp

+18-8
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,33 @@ Date: May 2016
2424
/// Applies instrumenters to given goto program
2525
/// \param goto_program: the goto program
2626
/// \param instrumenters: the instrumenters
27+
/// \param mode: mode of the function to instrument (for instance ID_C or
28+
/// ID_java)
2729
/// \param message_handler: a message handler
2830
void instrument_cover_goals(
2931
goto_programt &goto_program,
3032
const cover_instrumenterst &instrumenters,
33+
const irep_idt &mode,
3134
message_handlert &message_handler)
3235
{
33-
cover_basic_blockst basic_blocks(goto_program);
34-
basic_blocks.select_unique_java_bytecode_indices(
35-
goto_program, message_handler);
36-
basic_blocks.report_block_anomalies(goto_program, message_handler);
37-
38-
instrumenters(goto_program, basic_blocks);
36+
const std::unique_ptr<cover_blocks_baset> basic_blocks =
37+
mode == ID_java ? std::unique_ptr<cover_blocks_baset>(
38+
new cover_basic_blocks_javat(goto_program))
39+
: std::unique_ptr<cover_blocks_baset>(
40+
new cover_basic_blockst(goto_program));
41+
42+
basic_blocks->report_block_anomalies(goto_program, message_handler);
43+
instrumenters(goto_program, *basic_blocks);
3944
}
4045

4146
/// Instruments goto program for a given coverage criterion
4247
/// \param symbol_table: the symbol table
4348
/// \param goto_program: the goto program
4449
/// \param criterion: the coverage criterion
4550
/// \param message_handler: a message handler
51+
/// \deprecated use instrument_cover_goals(goto_programt &goto_program,
52+
/// const cover_instrumenterst &instrumenters,
53+
/// message_handlert &message_handler, const irep_idt mode) instead
4654
void instrument_cover_goals(
4755
const symbol_tablet &symbol_table,
4856
goto_programt &goto_program,
@@ -55,7 +63,8 @@ void instrument_cover_goals(
5563
cover_instrumenterst instrumenters;
5664
instrumenters.add_from_criterion(criterion, symbol_table, goal_filters);
5765

58-
instrument_cover_goals(goto_program, instrumenters, message_handler);
66+
instrument_cover_goals(
67+
goto_program, instrumenters, ID_unknown, message_handler);
5968
}
6069

6170
/// Create and add an instrumenter based on the given criterion
@@ -257,7 +266,7 @@ static void instrument_cover_goals(
257266
if(config.function_filters(function_id, function))
258267
{
259268
instrument_cover_goals(
260-
function.body, config.cover_instrumenters, message_handler);
269+
function.body, config.cover_instrumenters, config.mode, message_handler);
261270
changed = true;
262271
}
263272

@@ -320,6 +329,7 @@ bool instrument_cover_goals(
320329

321330
Forall_goto_functions(f_it, goto_functions)
322331
{
332+
config->mode = symbol_table.lookup(f_it->first)->mode;
323333
instrument_cover_goals(
324334
*config, f_it->first, f_it->second, message_handler);
325335
}

src/goto-instrument/cover.h

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct cover_configt
3838
{
3939
bool keep_assertions;
4040
bool traces_must_terminate;
41+
irep_idt mode;
4142
function_filterst function_filters;
4243
goal_filterst goal_filters;
4344
cover_instrumenterst cover_instrumenters;

src/goto-instrument/cover_basic_blocks.cpp

+54-77
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Author: Peter Schrammel
1515
#include <util/message.h>
1616
#include <util/string2int.h>
1717

18-
optionalt<unsigned> cover_basic_blockst::continuation_of_block(
18+
optionalt<std::size_t> cover_basic_blockst::continuation_of_block(
1919
const goto_programt::const_targett &instruction,
2020
cover_basic_blockst::block_mapt &block_map)
2121
{
@@ -32,7 +32,7 @@ optionalt<unsigned> cover_basic_blockst::continuation_of_block(
3232
cover_basic_blockst::cover_basic_blockst(const goto_programt &_goto_program)
3333
{
3434
bool next_is_target = true;
35-
unsigned current_block = 0;
35+
std::size_t current_block = 0;
3636

3737
forall_goto_program_instructions(it, _goto_program)
3838
{
@@ -87,104 +87,36 @@ cover_basic_blockst::cover_basic_blockst(const goto_programt &_goto_program)
8787
update_covered_lines(block_info);
8888
}
8989

90-
unsigned cover_basic_blockst::block_of(goto_programt::const_targett t) const
90+
std::size_t cover_basic_blockst::block_of(goto_programt::const_targett t) const
9191
{
9292
const auto it = block_map.find(t);
9393
INVARIANT(it != block_map.end(), "instruction must be part of a block");
9494
return it->second;
9595
}
9696

9797
optionalt<goto_programt::const_targett>
98-
cover_basic_blockst::instruction_of(unsigned block_nr) const
98+
cover_basic_blockst::instruction_of(const std::size_t block_nr) const
9999
{
100100
INVARIANT(block_nr < block_infos.size(), "block number out of range");
101-
return block_infos.at(block_nr).representative_inst;
101+
return block_infos[block_nr].representative_inst;
102102
}
103103

104104
const source_locationt &
105-
cover_basic_blockst::source_location_of(unsigned block_nr) const
105+
cover_basic_blockst::source_location_of(const std::size_t block_nr) const
106106
{
107107
INVARIANT(block_nr < block_infos.size(), "block number out of range");
108-
return block_infos.at(block_nr).source_location;
109-
}
110-
111-
void cover_basic_blockst::select_unique_java_bytecode_indices(
112-
const goto_programt &goto_program,
113-
message_handlert &message_handler)
114-
{
115-
messaget msg(message_handler);
116-
std::set<unsigned> blocks_seen;
117-
std::set<irep_idt> bytecode_indices_seen;
118-
119-
forall_goto_program_instructions(it, goto_program)
120-
{
121-
const unsigned block_nr = block_of(it);
122-
if(blocks_seen.find(block_nr) != blocks_seen.end())
123-
continue;
124-
125-
INVARIANT(block_nr < block_infos.size(), "block number out of range");
126-
block_infot &block_info = block_infos.at(block_nr);
127-
if(!block_info.representative_inst)
128-
{
129-
if(!it->source_location.get_java_bytecode_index().empty())
130-
{
131-
// search for a representative
132-
if(
133-
bytecode_indices_seen
134-
.insert(it->source_location.get_java_bytecode_index())
135-
.second)
136-
{
137-
block_info.representative_inst = it;
138-
block_info.source_location = it->source_location;
139-
update_covered_lines(block_info);
140-
blocks_seen.insert(block_nr);
141-
msg.debug() << it->function << " block " << (block_nr + 1)
142-
<< ": location " << it->location_number
143-
<< ", bytecode-index "
144-
<< it->source_location.get_java_bytecode_index()
145-
<< " selected for instrumentation." << messaget::eom;
146-
}
147-
}
148-
}
149-
else if(it == *block_info.representative_inst)
150-
{
151-
// check the existing representative
152-
if(!it->source_location.get_java_bytecode_index().empty())
153-
{
154-
if(
155-
bytecode_indices_seen
156-
.insert(it->source_location.get_java_bytecode_index())
157-
.second)
158-
{
159-
blocks_seen.insert(block_nr);
160-
}
161-
else
162-
{
163-
// clash, reset to search for a new one
164-
block_info.representative_inst = {};
165-
block_info.source_location = source_locationt::nil();
166-
msg.debug() << it->function << " block " << (block_nr + 1)
167-
<< ", location " << it->location_number
168-
<< ": bytecode-index "
169-
<< it->source_location.get_java_bytecode_index()
170-
<< " already instrumented."
171-
<< " Searching for alternative instruction"
172-
<< " to instrument." << messaget::eom;
173-
}
174-
}
175-
}
176-
}
108+
return block_infos[block_nr].source_location;
177109
}
178110

179111
void cover_basic_blockst::report_block_anomalies(
180112
const goto_programt &goto_program,
181113
message_handlert &message_handler)
182114
{
183115
messaget msg(message_handler);
184-
std::set<unsigned> blocks_seen;
116+
std::set<std::size_t> blocks_seen;
185117
forall_goto_program_instructions(it, goto_program)
186118
{
187-
const unsigned block_nr = block_of(it);
119+
const std::size_t block_nr = block_of(it);
188120
const block_infot &block_info = block_infos.at(block_nr);
189121

190122
if(
@@ -228,3 +160,48 @@ void cover_basic_blockst::update_covered_lines(block_infot &block_info)
228160
std::string covered_lines = format_number_range(line_list);
229161
block_info.source_location.set_basic_block_covered_lines(covered_lines);
230162
}
163+
164+
cover_basic_blocks_javat::cover_basic_blocks_javat(
165+
const goto_programt &_goto_program)
166+
{
167+
forall_goto_program_instructions(it, _goto_program)
168+
{
169+
const auto &location = it->source_location;
170+
const auto &bytecode_index = location.get_java_bytecode_index();
171+
if(index_to_block.emplace(bytecode_index, block_infos.size()).second)
172+
{
173+
block_infos.push_back(it);
174+
block_locations.push_back(location);
175+
block_locations.back().set_basic_block_covered_lines(location.get_line());
176+
}
177+
}
178+
}
179+
180+
std::size_t
181+
cover_basic_blocks_javat::block_of(goto_programt::const_targett t) const
182+
{
183+
const auto &bytecode_index = t->source_location.get_java_bytecode_index();
184+
const auto it = index_to_block.find(bytecode_index);
185+
INVARIANT(it != index_to_block.end(), "instruction must be part of a block");
186+
return it->second;
187+
}
188+
189+
optionalt<goto_programt::const_targett>
190+
cover_basic_blocks_javat::instruction_of(const std::size_t block_nr) const
191+
{
192+
PRECONDITION(block_nr < block_infos.size());
193+
return block_infos[block_nr];
194+
}
195+
196+
const source_locationt &
197+
cover_basic_blocks_javat::source_location_of(const std::size_t block_nr) const
198+
{
199+
PRECONDITION(block_nr < block_locations.size());
200+
return block_locations[block_nr];
201+
}
202+
203+
void cover_basic_blocks_javat::output(std::ostream &out) const
204+
{
205+
for(std::size_t i = 0; i < block_locations.size(); ++i)
206+
out << block_locations[i] << " -> " << i << '\n';
207+
}

0 commit comments

Comments
 (0)