Skip to content

Commit e839ae6

Browse files
committed
Unwindset parsing: check loop identifiers
We silently accepted unwindset specifications that included non-existent loop identifiers.
1 parent f09d5ef commit e839ae6

16 files changed

+131
-16
lines changed

regression/cbmc/unwindset1/main.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int main()
2+
{
3+
int x;
4+
for_loop:
5+
for(int i = 0; i < x; ++i)
6+
--x;
7+
for(int j = 0; j < 5; ++j)
8+
++x;
9+
__CPROVER_assert(0, "can be reached");
10+
}

regression/cbmc/unwindset1/test.desc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--unwindset main.0:2,main.2:2
4+
^Invalid User Input$
5+
^Option: unwindset$
6+
^Reason: invalid loop identifier main\.2$
7+
^EXIT=1$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring

src/goto-checker/multi_path_symex_only_checker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ multi_path_symex_only_checkert::multi_path_symex_only_checkert(
2828
goto_model(goto_model),
2929
ns(goto_model.get_symbol_table(), symex_symbol_table),
3030
equation(ui_message_handler),
31+
unwindset(goto_model),
3132
symex(
3233
ui_message_handler,
3334
goto_model.get_symbol_table(),
3435
equation,
3536
options,
3637
path_storage,
37-
guard_manager)
38+
guard_manager,
39+
unwindset)
3840
{
3941
setup_symex(symex, ns, options, ui_message_handler);
4042
}

src/goto-checker/multi_path_symex_only_checker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Author: Daniel Kroening, Peter Schrammel
1616

1717
#include <goto-symex/path_storage.h>
1818

19+
#include <goto-instrument/unwindset.h>
20+
1921
#include "symex_bmc.h"
2022

2123
class multi_path_symex_only_checkert : public incremental_goto_checkert
@@ -35,6 +37,7 @@ class multi_path_symex_only_checkert : public incremental_goto_checkert
3537
symex_target_equationt equation;
3638
guard_managert guard_manager;
3739
path_fifot path_storage; // should go away
40+
unwindsett unwindset;
3841
symex_bmct symex;
3942

4043
/// Generates the equation by running goto-symex

src/goto-checker/single_loop_incremental_symex_checker.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ single_loop_incremental_symex_checkert::single_loop_incremental_symex_checkert(
3030
goto_model(goto_model),
3131
ns(goto_model.get_symbol_table(), symex_symbol_table),
3232
equation(ui_message_handler),
33+
unwindset(goto_model),
3334
symex(
3435
ui_message_handler,
3536
goto_model.get_symbol_table(),
3637
equation,
3738
options,
3839
path_storage,
3940
guard_manager,
41+
unwindset,
4042
ui_message_handler.get_ui()),
4143
property_decider(options, ui_message_handler, equation, ns)
4244
{

src/goto-checker/single_loop_incremental_symex_checker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Author: Daniel Kroening, Peter Schrammel
1616

1717
#include <goto-symex/path_storage.h>
1818

19+
#include <goto-instrument/unwindset.h>
20+
1921
#include "goto_symex_property_decider.h"
2022
#include "goto_trace_provider.h"
2123
#include "incremental_goto_checker.h"
@@ -57,6 +59,7 @@ class single_loop_incremental_symex_checkert : public incremental_goto_checkert,
5759
symex_target_equationt equation;
5860
path_fifot path_storage; // should go away
5961
guard_managert guard_manager;
62+
unwindsett unwindset;
6063
symex_bmc_incremental_one_loopt symex;
6164
bool initial_equation_generated = false;
6265
bool full_equation_generated = false;

src/goto-checker/single_path_symex_only_checker.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ single_path_symex_only_checkert::single_path_symex_only_checkert(
3030
goto_model(goto_model),
3131
ns(goto_model.get_symbol_table(), symex_symbol_table),
3232
worklist(get_path_strategy(options.get_option("exploration-strategy"))),
33-
symex_runtime(0)
33+
symex_runtime(0),
34+
unwindset(goto_model)
3435
{
3536
}
3637

@@ -70,7 +71,8 @@ void single_path_symex_only_checkert::initialize_worklist()
7071
equation,
7172
options,
7273
*worklist,
73-
guard_manager);
74+
guard_manager,
75+
unwindset);
7476
setup_symex(symex);
7577

7678
symex.initialize_path_storage_from_entry_point_of(
@@ -95,7 +97,8 @@ bool single_path_symex_only_checkert::resume_path(path_storaget::patht &path)
9597
path.equation,
9698
options,
9799
*worklist,
98-
guard_manager);
100+
guard_manager,
101+
unwindset);
99102
setup_symex(symex);
100103

101104
symex.resume_symex_from_saved_state(

src/goto-checker/single_path_symex_only_checker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Author: Daniel Kroening, Peter Schrammel
1616

1717
#include <goto-symex/path_storage.h>
1818

19+
#include <goto-instrument/unwindset.h>
20+
1921
#include <chrono>
2022

2123
class symex_bmct;
@@ -40,6 +42,7 @@ class single_path_symex_only_checkert : public incremental_goto_checkert
4042
guard_managert guard_manager;
4143
std::unique_ptr<path_storaget> worklist;
4244
std::chrono::duration<double> symex_runtime;
45+
unwindsett unwindset;
4346

4447
void equation_output(
4548
const symex_bmct &symex,

src/goto-checker/symex_bmc.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ Author: Daniel Kroening, [email protected]
1616
#include <util/simplify_expr.h>
1717
#include <util/source_location.h>
1818

19+
#include <goto-instrument/unwindset.h>
20+
1921
symex_bmct::symex_bmct(
2022
message_handlert &mh,
2123
const symbol_tablet &outer_symbol_table,
2224
symex_target_equationt &_target,
2325
const optionst &options,
2426
path_storaget &path_storage,
25-
guard_managert &guard_manager)
27+
guard_managert &guard_manager,
28+
unwindsett &unwindset)
2629
: goto_symext(
2730
mh,
2831
outer_symbol_table,
@@ -33,6 +36,7 @@ symex_bmct::symex_bmct(
3336
record_coverage(!options.get_option("symex-coverage-report").empty()),
3437
havoc_bodyless_functions(
3538
options.get_bool_option("havoc-undefined-functions")),
39+
unwindset(unwindset),
3640
symex_coverage(ns)
3741
{
3842
}

src/goto-checker/symex_bmc.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ Author: Daniel Kroening, [email protected]
1616

1717
#include <goto-symex/goto_symex.h>
1818

19-
#include <goto-instrument/unwindset.h>
20-
2119
#include "symex_coverage.h"
2220

21+
class unwindsett;
22+
2323
class symex_bmct : public goto_symext
2424
{
2525
public:
@@ -29,7 +29,8 @@ class symex_bmct : public goto_symext
2929
symex_target_equationt &_target,
3030
const optionst &options,
3131
path_storaget &path_storage,
32-
guard_managert &guard_manager);
32+
guard_managert &guard_manager,
33+
unwindsett &unwindset);
3334

3435
// To show progress
3536
source_locationt last_source_location;
@@ -81,7 +82,7 @@ class symex_bmct : public goto_symext
8182
const bool record_coverage;
8283
const bool havoc_bodyless_functions;
8384

84-
unwindsett unwindset;
85+
unwindsett &unwindset;
8586

8687
protected:
8788
/// Callbacks that may provide an unwind/do-not-unwind decision for a loop

src/goto-checker/symex_bmc_incremental_one_loop.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,25 @@ Author: Peter Schrammel, Daniel Kroening, [email protected]
1212

1313
#include <util/structured_data.h>
1414

15+
#include <goto-instrument/unwindset.h>
16+
1517
symex_bmc_incremental_one_loopt::symex_bmc_incremental_one_loopt(
1618
message_handlert &message_handler,
1719
const symbol_tablet &outer_symbol_table,
1820
symex_target_equationt &target,
1921
const optionst &options,
2022
path_storaget &path_storage,
2123
guard_managert &guard_manager,
24+
unwindsett &unwindset,
2225
ui_message_handlert::uit output_ui)
2326
: symex_bmct(
2427
message_handler,
2528
outer_symbol_table,
2629
target,
2730
options,
2831
path_storage,
29-
guard_manager),
32+
guard_manager,
33+
unwindset),
3034
incr_loop_id(options.get_option("incremental-loop")),
3135
incr_max_unwind(
3236
options.is_set("unwind-max") ? options.get_signed_int_option("unwind-max")

src/goto-checker/symex_bmc_incremental_one_loop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class symex_bmc_incremental_one_loopt : public symex_bmct
2222
const optionst &,
2323
path_storaget &,
2424
guard_managert &,
25+
unwindsett &,
2526
ui_message_handlert::uit output_ui);
2627

2728
/// Return true if symex can be resumed

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ int goto_instrument_parse_optionst::doit()
166166

167167
if(unwind_given || unwindset_given || unwindset_file_given)
168168
{
169-
unwindsett unwindset;
169+
unwindsett unwindset{goto_model};
170170

171171
if(unwind_given)
172172
unwindset.parse_unwind(cmdline.get_value("unwind"));

src/goto-instrument/unwindset.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Author: Daniel Kroening, [email protected]
88

99
#include "unwindset.h"
1010

11+
#include <util/exception_utils.h>
1112
#include <util/string2int.h>
1213
#include <util/string_utils.h>
1314

@@ -44,6 +45,65 @@ void unwindsett::parse_unwindset_one_loop(std::string val)
4445
if(last_c_pos != std::string::npos)
4546
{
4647
std::string id = val.substr(0, last_c_pos);
48+
49+
// The loop id can take three forms:
50+
// 1) Just a function name to limit recursion.
51+
// 2) F.N where F is a function name and N is a loop number.
52+
const symbol_tablet &symbol_table = goto_model.get_symbol_table();
53+
const symbolt *maybe_fn = symbol_table.lookup(id);
54+
if(maybe_fn && maybe_fn->type.id() == ID_code)
55+
{
56+
// ok, recursion limit
57+
}
58+
else
59+
{
60+
auto last_dot_pos = val.rfind('.');
61+
if(last_dot_pos == std::string::npos)
62+
{
63+
throw invalid_command_line_argument_exceptiont{
64+
"invalid loop identifier " + id, "unwindset"};
65+
}
66+
67+
std::string function_id = id.substr(0, last_dot_pos);
68+
std::string loop_nr_label = id.substr(last_dot_pos + 1);
69+
70+
if(loop_nr_label.empty() || !goto_model.can_produce_function(function_id))
71+
{
72+
throw invalid_command_line_argument_exceptiont{
73+
"invalid loop identifier " + id, "unwindset"};
74+
}
75+
76+
const goto_functiont &goto_function =
77+
goto_model.get_goto_function(function_id);
78+
if(isdigit(loop_nr_label[0]))
79+
{
80+
auto nr = string2optional_unsigned(loop_nr_label);
81+
if(!nr.has_value())
82+
{
83+
throw invalid_command_line_argument_exceptiont{
84+
"invalid loop identifier " + id, "unwindset"};
85+
}
86+
87+
bool found = std::any_of(
88+
goto_function.body.instructions.begin(),
89+
goto_function.body.instructions.end(),
90+
[&nr](const goto_programt::instructiont &instruction) {
91+
return instruction.is_backwards_goto() &&
92+
instruction.loop_number == nr;
93+
});
94+
if(!found)
95+
{
96+
throw invalid_command_line_argument_exceptiont{
97+
"invalid loop identifier " + id, "unwindset"};
98+
}
99+
}
100+
else
101+
{
102+
throw invalid_command_line_argument_exceptiont{
103+
"invalid loop identifier " + id, "unwindset"};
104+
}
105+
}
106+
47107
std::string uw_string = val.substr(last_c_pos + 1);
48108

49109
// the below initialisation makes g++-5 happy

src/goto-instrument/unwindset.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ Author: Daniel Kroening, [email protected]
1212
#ifndef CPROVER_GOTO_INSTRUMENT_UNWINDSET_H
1313
#define CPROVER_GOTO_INSTRUMENT_UNWINDSET_H
1414

15+
#include <goto-programs/goto_model.h>
16+
1517
#include <list>
1618
#include <map>
1719
#include <string>
1820

19-
#include <util/irep.h>
20-
#include <util/optional.h>
21-
2221
class unwindsett
2322
{
2423
public:
@@ -27,6 +26,9 @@ class unwindsett
2726
// 2) a limit per loop, all threads
2827
// 3) a limit for a particular thread.
2928
// We use the most specific of the above.
29+
explicit unwindsett(abstract_goto_modelt &goto_model) : goto_model(goto_model)
30+
{
31+
}
3032

3133
// global limit for all loops
3234
void parse_unwind(const std::string &unwind);
@@ -41,6 +43,8 @@ class unwindsett
4143
void parse_unwindset_file(const std::string &file_name);
4244

4345
protected:
46+
abstract_goto_modelt &goto_model;
47+
4448
optionalt<unsigned> global_limit;
4549

4650
// Limit for all instances of a loop.

unit/path_strategies.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Author: Kareem Khazem <[email protected]>, 2018
2424

2525
#include <goto-symex/path_storage.h>
2626

27+
#include <goto-instrument/unwindset.h>
28+
2729
#include <langapi/mode.h>
2830

2931
#include <util/cmdline.h>
@@ -408,6 +410,7 @@ void _check_with_strategy(
408410
propertiest properties(initialize_properties(goto_model));
409411
std::unique_ptr<path_storaget> worklist = get_path_strategy(strategy);
410412
guard_managert guard_manager;
413+
unwindsett unwindset{goto_model};
411414

412415
{
413416
// Put initial state into the work list
@@ -418,7 +421,8 @@ void _check_with_strategy(
418421
equation,
419422
options,
420423
*worklist,
421-
guard_manager);
424+
guard_manager,
425+
unwindset);
422426
setup_symex(symex, ns, options, ui_message_handler);
423427

424428
symex.initialize_path_storage_from_entry_point_of(
@@ -438,7 +442,8 @@ void _check_with_strategy(
438442
resume.equation,
439443
options,
440444
*worklist,
441-
guard_manager);
445+
guard_manager,
446+
unwindset);
442447
setup_symex(symex, ns, options, ui_message_handler);
443448

444449
symex.resume_symex_from_saved_state(

0 commit comments

Comments
 (0)