Skip to content

Commit 746c580

Browse files
committed
Add tests for CSVSA's sparse-domains mode
This checks that CSVSA using the sparse-domains optimisation has the same outcome as without it for all end-to-end tests.
1 parent 087f5ca commit 746c580

File tree

8 files changed

+152
-11
lines changed

8 files changed

+152
-11
lines changed

driver/analyser.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def run_security_analyser(
5656
data_flow_insensitive_instrumentation,
5757
results_dir,
5858
temp_root_dir,
59-
lazy_methods_context_sensitive
59+
lazy_methods_context_sensitive,
60+
verify_csvsa_sparse_domains
6061
):
6162
prof = {}
6263
prof_start_time = time.time()
@@ -80,7 +81,8 @@ def run_security_analyser(
8081
"output-dir": "./",
8182
"temp-dir": temp_root_dir,
8283
"data-flow-insensitive-instrumentation": data_flow_insensitive_instrumentation,
83-
"lazy-methods-context-sensitive": lazy_methods_context_sensitive
84+
"lazy-methods-context-sensitive": lazy_methods_context_sensitive,
85+
"verify-csvsa-sparse-domains": verify_csvsa_sparse_domains
8486
}
8587
with open(root_config_json_fname, "w") as root_config_json_file:
8688
root_config_json_file.write(json.dumps(root_config_json, sort_keys=True, indent=4))

driver/run.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ def __parse_cmd_line():
150150
"paths.")
151151
parser.add_argument("--lazy-methods-context-sensitive", action="store_true",
152152
help="Use context-sensitive method loading in the first stage")
153+
parser.add_argument("--verify-csvsa-sparse-domains", action="store_true",
154+
help="Verify CSVSA's sparse domains optimisation does not alter its output")
153155
return parser.parse_args()
154156

155157

@@ -200,7 +202,8 @@ def evaluate(cmdline, common_libraries):
200202
cmdline.data_flow_insensitive_instrumentation,
201203
cmdline.results_dir,
202204
os.path.abspath(os.path.join(cmdline.temp_dir,"GOTO-ANALYSER-TEMP")),
203-
cmdline.lazy_methods_context_sensitive
205+
cmdline.lazy_methods_context_sensitive,
206+
cmdline.verify_csvsa_sparse_domains
204207
)
205208

206209
instrumented_programs_json_path = \

regression/end_to_end/driver.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ def run_security_analyser_pipeline(
123123

124124
if "SECURITY_REGRESSION_TESTS_USE_CSVSA" in os.environ and os.environ["SECURITY_REGRESSION_TESTS_USE_CSVSA"] != "0":
125125
cmdline.append("--lazy-methods-context-sensitive")
126+
# Check that CSVSA's behaviour with and without sparse domains
127+
# optimisation matches:
128+
cmdline.append("--verify-csvsa-sparse-domains")
126129

127130
pretty_cmdline = " ".join(quote_pathnames_in_command_line(cmdline))
128131

src/driver/sec_driver_parse_options.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,72 @@ static irep_idt get_cprover_start_main_callee(const goto_modelt &goto_model)
135135
.get_identifier();
136136
}
137137

138+
class csvsa_graph_mismatcht : public std::logic_error
139+
{
140+
public:
141+
explicit csvsa_graph_mismatcht(const std::string &s) : logic_error(s)
142+
{
143+
}
144+
};
145+
146+
static void check_csvsa_graphs_equal(
147+
const context_sensitive_value_set_analysis_drivert &analysis_a,
148+
const context_sensitive_value_set_analysis_drivert &analysis_b)
149+
{
150+
const auto &graph_a = analysis_a.get_context_graph();
151+
const auto &graph_b = analysis_b.get_context_graph();
152+
153+
if(graph_a.size() != graph_b.size())
154+
{
155+
throw csvsa_graph_mismatcht(
156+
"Different function context count: " + std::to_string(graph_a.size()) +
157+
" vs. " + std::to_string(graph_b.size()));
158+
}
159+
160+
for(std::size_t node_idx = 0; node_idx < graph_a.size(); ++node_idx)
161+
{
162+
const csvsa_context_graph_nodet &node_a = graph_a[node_idx];
163+
const csvsa_context_graph_nodet &node_b = graph_b[node_idx];
164+
const irep_idt &function_a = node_a.context->function();
165+
const irep_idt &function_b = node_b.context->function();
166+
167+
if(function_a != function_b)
168+
{
169+
throw csvsa_graph_mismatcht(
170+
"Node " + std::to_string(node_idx) + " refers to functions " +
171+
id2string(function_a) + " vs. " + id2string(function_b));
172+
}
173+
174+
if(node_a.out.size() != node_b.out.size())
175+
{
176+
throw csvsa_graph_mismatcht(
177+
"Node " + std::to_string(node_idx) + " has " +
178+
std::to_string(node_a.out.size()) + " vs. " +
179+
std::to_string(node_b.out.size()) + " successors");
180+
}
181+
182+
for(auto out_iter_a = node_a.out.begin(), out_iter_b = node_b.out.begin();
183+
out_iter_a != node_a.out.end();
184+
++out_iter_a, ++out_iter_b)
185+
{
186+
if(out_iter_a->first != out_iter_b->first)
187+
{
188+
throw csvsa_graph_mismatcht(
189+
"Node " + std::to_string(node_idx) + " has differing children: " +
190+
"at least node " + std::to_string(out_iter_a->first) + " vs. " +
191+
std::to_string(out_iter_b->first));
192+
}
193+
194+
if(out_iter_a->second.is_recursive() != out_iter_b->second.is_recursive())
195+
{
196+
throw csvsa_graph_mismatcht(
197+
"Node " + std::to_string(node_idx) + " has an outgoing edge that "
198+
"disagrees regarding whether the edge is recursive");
199+
}
200+
}
201+
}
202+
}
203+
138204
/// invoke main modules
139205
int sec_driver_parse_optionst::doit()
140206
{
@@ -189,6 +255,25 @@ int sec_driver_parse_optionst::doit()
189255

190256
return CPROVER_EXIT_SUCCESS;
191257
}
258+
259+
if(cmdline.isset("verify-csvsa-sparse-domains"))
260+
{
261+
auto csvsa_without_sparse_domains =
262+
csvsa_load_and_analyze_functions_without_sparse_domains(
263+
lazy_goto_model, get_message_handler());
264+
265+
try
266+
{
267+
check_csvsa_graphs_equal(
268+
*csvsa_analysis, *csvsa_without_sparse_domains);
269+
}
270+
catch(const csvsa_graph_mismatcht &difference)
271+
{
272+
error() << "CSVSA results with and without sparse domains mismatch: "
273+
<< difference.what() << messaget::eom;
274+
return CPROVER_EXIT_INTERNAL_ERROR;
275+
}
276+
}
192277
}
193278
else
194279
lazy_goto_model.load_all_functions();
@@ -630,6 +715,9 @@ void sec_driver_parse_optionst::help()
630715
" their virtual callsites\n"
631716
" --show-csvsa-value-sets print CSVSA's value sets (possible pointer\n" // NOLINT (*)
632717
" targets) and exit.\n"
718+
" --verify-csvsa-sparse-domains after CSVSA completes, re-run it with\n"
719+
" sparse domains disabled and verify the\n"
720+
" results are the same.\n"
633721
"\n"
634722
"Java Bytecode frontend options:\n"
635723
" --classpath dir/jar set the classpath\n"

src/driver/sec_driver_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class optionst;
4949
"(rebuild-taint-cache)" \
5050
"(lazy-methods-context-sensitive)" \
5151
"(show-csvsa-value-sets)" \
52+
"(verify-csvsa-sparse-domains)" \
5253
"(java-assume-inputs-non-null)" \
5354
"(java-max-input-array-length):" \
5455
"(string-max-input-length):" \

src/pointer-analysis/context_sensitive_value_set_analysis.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -694,10 +694,11 @@ void csvsa_function_contextt::print_tree(
694694
}
695695
}
696696

697-
std::unique_ptr<context_sensitive_value_set_analysis_drivert>
697+
static std::unique_ptr<context_sensitive_value_set_analysis_drivert>
698698
csvsa_load_and_analyze_functions(
699699
lazy_goto_modelt &lazy_model,
700-
message_handlert &msg)
700+
message_handlert &msg,
701+
bool use_sparse_domains)
701702
{
702703
get_goto_programt get_function_from_lazy_model =
703704
[&lazy_model](const irep_idt &name) -> const goto_programt & {
@@ -706,14 +707,32 @@ csvsa_load_and_analyze_functions(
706707

707708
std::unique_ptr<context_sensitive_value_set_analysis_drivert> driver =
708709
util_make_unique<context_sensitive_value_set_analysis_drivert>(
709-
lazy_model.symbol_table, get_function_from_lazy_model);
710+
lazy_model.symbol_table,
711+
get_function_from_lazy_model,
712+
use_sparse_domains);
710713
driver->set_message_handler(msg);
711714

712715
(*driver)(goto_functionst::entry_point());
713716

714717
return driver;
715718
}
716719

720+
std::unique_ptr<context_sensitive_value_set_analysis_drivert>
721+
csvsa_load_and_analyze_functions(
722+
lazy_goto_modelt &lazy_model,
723+
message_handlert &msg)
724+
{
725+
return csvsa_load_and_analyze_functions(lazy_model, msg, true);
726+
}
727+
728+
std::unique_ptr<context_sensitive_value_set_analysis_drivert>
729+
csvsa_load_and_analyze_functions_without_sparse_domains(
730+
lazy_goto_modelt &lazy_model,
731+
message_handlert &msg)
732+
{
733+
return csvsa_load_and_analyze_functions(lazy_model, msg, false);
734+
}
735+
717736
bool context_sensitive_value_set_analysis_drivert
718737
::compare_working_set_entriest::operator()(
719738
const working_set_entryt &a, const working_set_entryt &b)

src/pointer-analysis/context_sensitive_value_set_analysis.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ struct recursive_tag_edget
3535
{
3636
is_recursive_backedge = true;
3737
}
38-
bool is_recursive()
38+
bool is_recursive() const
3939
{
4040
return is_recursive_backedge;
4141
}
@@ -105,10 +105,15 @@ class context_sensitive_value_set_analysis_drivert : public messaget
105105
void fixedpoint();
106106

107107
public:
108+
const bool use_sparse_domains;
109+
108110
context_sensitive_value_set_analysis_drivert(
109111
const symbol_tablet &symbol_table,
110-
get_goto_programt get_goto_program)
111-
: ns(symbol_table), get_goto_program(get_goto_program)
112+
get_goto_programt get_goto_program,
113+
bool use_sparse_domains)
114+
: ns(symbol_table),
115+
get_goto_program(get_goto_program),
116+
use_sparse_domains(use_sparse_domains)
112117
{
113118
class_hierarchy(symbol_table);
114119
}
@@ -399,6 +404,15 @@ class csvsa_function_contextt :
399404
ID_virtual_function;
400405
}
401406

407+
static std::function<bool(locationt)> get_retain_domain_predicate(
408+
const context_sensitive_value_set_analysis_drivert &driver)
409+
{
410+
if(driver.use_sparse_domains)
411+
return csvsa_must_retain_domain;
412+
else
413+
return nullptr;
414+
}
415+
402416
public:
403417
/// Function context constructor
404418
/// \param ns: global namespace
@@ -419,7 +433,7 @@ class csvsa_function_contextt :
419433
context_sensitive_value_set_analysis_drivert &driver,
420434
context_indext parent,
421435
const locationt &parent_loc)
422-
: csvsa_value_set_analysist(ns, csvsa_must_retain_domain),
436+
: csvsa_value_set_analysist(ns, get_retain_domain_predicate(driver)),
423437
get_goto_program(get_goto_program),
424438
function_name(function_name),
425439
goto_program(get_goto_program(function_name)),
@@ -442,7 +456,7 @@ class csvsa_function_contextt :
442456
get_goto_programt get_goto_program,
443457
const irep_idt &function_name,
444458
context_sensitive_value_set_analysis_drivert &driver)
445-
: csvsa_value_set_analysist(ns, csvsa_must_retain_domain),
459+
: csvsa_value_set_analysist(ns, get_retain_domain_predicate(driver)),
446460
get_goto_program(get_goto_program),
447461
function_name(function_name),
448462
goto_program(get_goto_program(function_name)),
@@ -560,4 +574,11 @@ csvsa_load_and_analyze_functions(
560574
lazy_goto_modelt &lazy_model,
561575
message_handlert &msg);
562576

577+
/// As `csvsa_load_and_analyze_functions`, except that CSVSA's sparse domains
578+
/// optimisation is disabled. Only useful for debugging purposes.
579+
std::unique_ptr<context_sensitive_value_set_analysis_drivert>
580+
csvsa_load_and_analyze_functions_without_sparse_domains(
581+
lazy_goto_modelt &lazy_model,
582+
message_handlert &msg);
583+
563584
#endif

src/taint-analysis/taint_config.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,11 @@ void taint_build_cmdline_from_config(
233233
return;
234234

235235
if(cfg.object["lazy-methods-context-sensitive"].is_true())
236+
{
236237
cmdline.set("lazy-methods-context-sensitive");
238+
if(cfg.object["verify-csvsa-sparse-domains"].is_true())
239+
cmdline.set("verify-csvsa-sparse-domains");
240+
}
237241
else
238242
cmdline.set("lazy-methods");
239243

0 commit comments

Comments
 (0)