Skip to content

Commit 6747d24

Browse files
author
Daniel Kroening
authored
Merge pull request #3215 from diffblue/show-ai-on-source
Show abstract states in program source code
2 parents d15c08a + 3658167 commit 6747d24

File tree

7 files changed

+202
-3
lines changed

7 files changed

+202
-3
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
int i = 1;
2+
3+
int main()
4+
{
5+
int j;
6+
_Bool nondet;
7+
8+
if(j >= 1 && j <= 10)
9+
{
10+
i++;
11+
}
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--intervals --show-on-source
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^ if\(j >= 1 && j <= 10\)$
7+
^ 1 <= i <= 1$
8+
^ 1 <= main::1::j <= 10$
9+
--
10+
^warning: ignoring

src/goto-analyzer/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ SRC = goto_analyzer_main.cpp \
33
taint_analysis.cpp \
44
taint_parser.cpp \
55
unreachable_instructions.cpp \
6+
show_on_source.cpp \
67
static_show_domain.cpp \
78
static_simplifier.cpp \
89
static_verifier.cpp \

src/goto-analyzer/goto_analyzer_parse_options.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ Author: Daniel Kroening, [email protected]
5757
#include <util/unicode.h>
5858
#include <util/version.h>
5959

60-
#include "taint_analysis.h"
61-
#include "unreachable_instructions.h"
60+
#include "show_on_source.h"
6261
#include "static_show_domain.h"
6362
#include "static_simplifier.h"
6463
#include "static_verifier.h"
64+
#include "taint_analysis.h"
65+
#include "unreachable_instructions.h"
6566

6667
goto_analyzer_parse_optionst::goto_analyzer_parse_optionst(
6768
int argc,
@@ -191,6 +192,11 @@ void goto_analyzer_parse_optionst::get_command_line_options(optionst &options)
191192
options.set_option("show", true);
192193
options.set_option("general-analysis", true);
193194
}
195+
else if(cmdline.isset("show-on-source"))
196+
{
197+
options.set_option("show-on-source", true);
198+
options.set_option("general-analysis", true);
199+
}
194200
else if(cmdline.isset("verify"))
195201
{
196202
options.set_option("verify", true);
@@ -634,6 +640,11 @@ int goto_analyzer_parse_optionst::perform_analysis(const optionst &options)
634640
static_show_domain(goto_model, *analyzer, options, out);
635641
return CPROVER_EXIT_SUCCESS;
636642
}
643+
else if(options.get_bool_option("show-on-source"))
644+
{
645+
show_on_source(goto_model, *analyzer, get_message_handler());
646+
return CPROVER_EXIT_SUCCESS;
647+
}
637648
else if(options.get_bool_option("verify"))
638649
{
639650
result = static_verifier(goto_model,
@@ -807,7 +818,8 @@ void goto_analyzer_parse_optionst::help()
807818
" goto-analyzer file.c ... source file names\n"
808819
"\n"
809820
"Task options:\n"
810-
" --show display the abstract domains\n"
821+
" --show display the abstract states on the goto program\n" // NOLINT(*)
822+
" --show-on-source display the abstract states on the source\n"
811823
// NOLINTNEXTLINE(whitespace/line_length)
812824
" --verify use the abstract domains to check assertions\n"
813825
// NOLINTNEXTLINE(whitespace/line_length)

src/goto-analyzer/goto_analyzer_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class optionst;
147147
"(constants)" \
148148
"(dependence-graph)" \
149149
"(show)(verify)(simplify):" \
150+
"(show-on-source)" \
150151
"(location-sensitive)(concurrent)" \
151152
"(no-simplify-slicing)" \
152153
OPT_VALIDATE \

src/goto-analyzer/show_on_source.cpp

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*******************************************************************\
2+
3+
Module: goto-analyzer
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "show_on_source.h"
10+
11+
#include <util/file_util.h>
12+
#include <util/message.h>
13+
#include <util/unicode.h>
14+
15+
#include <analyses/ai.h>
16+
17+
#include <fstream>
18+
19+
/// get the name of the file referred to at a location loc,
20+
/// if any
21+
static optionalt<std::string>
22+
show_location(const ai_baset &ai, ai_baset::locationt loc)
23+
{
24+
const auto abstract_state = ai.abstract_state_before(loc);
25+
if(abstract_state->is_top())
26+
return {};
27+
28+
if(loc->source_location.get_line().empty())
29+
return {};
30+
31+
return loc->source_location.full_path();
32+
}
33+
34+
/// get the source files with non-top abstract states
35+
static std::set<std::string>
36+
get_source_files(const goto_modelt &goto_model, const ai_baset &ai)
37+
{
38+
std::set<std::string> files;
39+
40+
for(const auto &f : goto_model.goto_functions.function_map)
41+
{
42+
forall_goto_program_instructions(i_it, f.second.body)
43+
{
44+
const auto file = show_location(ai, i_it);
45+
if(file.has_value())
46+
files.insert(file.value());
47+
}
48+
}
49+
50+
return files;
51+
}
52+
53+
/// print a string with indent to match given sample line
54+
static void print_with_indent(
55+
const std::string &src,
56+
const std::string &indent_line,
57+
std::ostream &out)
58+
{
59+
const std::size_t p = indent_line.find_first_not_of(" \t");
60+
const std::string indent =
61+
p == std::string::npos ? std::string("") : std::string(indent_line, 0, p);
62+
std::istringstream in(src);
63+
std::string src_line;
64+
while(std::getline(in, src_line))
65+
out << indent << src_line << '\n';
66+
}
67+
68+
/// output source code annotated with abstract states for given file
69+
void show_on_source(
70+
const std::string &source_file,
71+
const goto_modelt &goto_model,
72+
const ai_baset &ai,
73+
message_handlert &message_handler)
74+
{
75+
#ifdef _MSC_VER
76+
std::ifstream in(widen(source_file));
77+
#else
78+
std::ifstream in(source_file);
79+
#endif
80+
81+
messaget message(message_handler);
82+
83+
if(!in)
84+
{
85+
message.warning() << "Failed to open `" << source_file << "'"
86+
<< messaget::eom;
87+
return;
88+
}
89+
90+
std::map<std::size_t, ai_baset::locationt> line_map;
91+
92+
// Collect line numbers with non-top abstract states.
93+
// We pick the _first_ state for each line.
94+
for(const auto &f : goto_model.goto_functions.function_map)
95+
{
96+
forall_goto_program_instructions(i_it, f.second.body)
97+
{
98+
const auto file = show_location(ai, i_it);
99+
if(file.has_value() && file.value() == source_file)
100+
{
101+
const std::size_t line_no =
102+
stoull(id2string(i_it->source_location.get_line()));
103+
if(line_map.find(line_no) == line_map.end())
104+
line_map[line_no] = i_it;
105+
}
106+
}
107+
}
108+
109+
// now print file to message handler
110+
const namespacet ns(goto_model.symbol_table);
111+
112+
std::string line;
113+
for(std::size_t line_no = 1; std::getline(in, line); line_no++)
114+
{
115+
const auto map_it = line_map.find(line_no);
116+
if(map_it != line_map.end())
117+
{
118+
auto abstract_state = ai.abstract_state_before(map_it->second);
119+
std::ostringstream state_str;
120+
abstract_state->output(state_str, ai, ns);
121+
if(!state_str.str().empty())
122+
{
123+
message.result() << messaget::blue;
124+
print_with_indent(state_str.str(), line, message.result());
125+
message.result() << messaget::reset;
126+
}
127+
}
128+
129+
message.result() << line << messaget::eom;
130+
}
131+
}
132+
133+
/// output source code annotated with abstract states
134+
void show_on_source(
135+
const goto_modelt &goto_model,
136+
const ai_baset &ai,
137+
message_handlert &message_handler)
138+
{
139+
// first gather the source files that have something to show
140+
const auto source_files = get_source_files(goto_model, ai);
141+
142+
// now show file-by-file
143+
for(const auto &source_file : source_files)
144+
show_on_source(source_file, goto_model, ai, message_handler);
145+
}

src/goto-analyzer/show_on_source.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*******************************************************************\
2+
3+
Module: goto-analyzer
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_GOTO_ANALYZER_SHOW_ON_SOURCE_H
10+
#define CPROVER_GOTO_ANALYZER_SHOW_ON_SOURCE_H
11+
12+
class ai_baset;
13+
class goto_modelt;
14+
class message_handlert;
15+
16+
void show_on_source(const goto_modelt &, const ai_baset &, message_handlert &);
17+
18+
#endif // CPROVER_GOTO_ANALYZER_SHOW_ON_SOURCE_H

0 commit comments

Comments
 (0)