Skip to content

Commit dc01f24

Browse files
committed
Check some assumptions about goto programs before starting an analysis
The current set of checks is certainly very incomplete, but at least provides some entry points for adding further tests.
1 parent 064f648 commit dc01f24

12 files changed

+159
-0
lines changed

src/cbmc/cbmc_parse_options.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,12 @@ int cbmc_parse_optionst::get_goto_program(
728728

729729
goto_convert(symbol_table, goto_functions, ui_message_handler);
730730

731+
if(goto_functions.check_internal_invariants())
732+
{
733+
error() << "GOTO program violates internal invariants" << eom;
734+
return 6;
735+
}
736+
731737
if(process_goto_program(options, goto_functions))
732738
return 6;
733739

src/clobber/clobber_parse_options.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ int clobber_parse_optionst::doit()
170170
if(get_goto_program(options, goto_functions))
171171
return 6;
172172

173+
if(goto_functions.check_internal_invariants())
174+
{
175+
error() << "GOTO program violates internal invariants" << eom;
176+
return 6;
177+
}
178+
173179
label_properties(goto_functions);
174180

175181
if(cmdline.isset("show-properties"))

src/goto-cc/compile.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ bool compilet::doit()
133133
return true;
134134
}
135135

136+
if(compiled_functions.check_internal_invariants())
137+
{
138+
error() << "GOTO program violates internal invariants" << eom;
139+
return true;
140+
}
141+
136142
return false;
137143
}
138144

src/goto-diff/goto_diff_parse_options.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,18 @@ int goto_diff_parse_optionst::doit()
333333
if(get_goto_program_ret!=-1)
334334
return get_goto_program_ret;
335335

336+
if(goto_model1.goto_functions.check_internal_invariants())
337+
{
338+
error() << "GOTO program violates internal invariants" << eom;
339+
return 6;
340+
}
341+
342+
if(goto_model2.goto_functions.check_internal_invariants())
343+
{
344+
error() << "GOTO program violates internal invariants" << eom;
345+
return 6;
346+
}
347+
336348
if(cmdline.isset("show-goto-functions"))
337349
{
338350
show_goto_functions(goto_model1, get_ui());

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,12 @@ void goto_instrument_parse_optionst::get_goto_program()
952952

953953
config.set(cmdline);
954954
config.set_from_symbol_table(symbol_table);
955+
956+
if(goto_functions.check_internal_invariants())
957+
{
958+
error() << "GOTO program violates internal invariants" << eom;
959+
throw 0;
960+
}
955961
}
956962

957963
/*******************************************************************\

src/goto-programs/goto_functions.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,25 @@ void get_local_identifiers(
3939
dest.insert(identifier);
4040
}
4141
}
42+
43+
/*******************************************************************\
44+
45+
Function: goto_functionst::check_internal_invariants
46+
47+
Inputs:
48+
49+
Outputs: Returns true iff an invariant is violated
50+
51+
Purpose: Ensure that all functions satisfy all assumptions
52+
about consistent goto programs.
53+
54+
\*******************************************************************/
55+
56+
bool goto_functionst::check_internal_invariants() const
57+
{
58+
forall_goto_functions(it, *this)
59+
if(it->second.body.check_internal_invariants())
60+
return true;
61+
62+
return false;
63+
}

src/goto-programs/goto_functions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Date: June 2003
1717
class goto_functionst:public goto_functions_templatet<goto_programt>
1818
{
1919
public:
20+
bool check_internal_invariants() const;
2021
};
2122

2223
#define Forall_goto_functions(it, functions) \

src/goto-programs/goto_program.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,3 +609,32 @@ std::string as_string(
609609

610610
return "";
611611
}
612+
613+
/*******************************************************************\
614+
615+
Function: goto_programt::check_internal_invariants
616+
617+
Inputs:
618+
619+
Outputs: Returns true iff an invariant is violated
620+
621+
Purpose: Ensure the current goto_programt satisfies all assumptions
622+
about consistent goto programs.
623+
624+
\*******************************************************************/
625+
626+
bool goto_programt::check_internal_invariants() const
627+
{
628+
if(empty())
629+
return false;
630+
631+
forall_goto_program_instructions(it, *this)
632+
if(it->check_internal_invariants())
633+
return true;
634+
635+
// the last instruction must be END_FUNCTION
636+
if(!get_end_function()->is_end_function())
637+
return true;
638+
639+
return false;
640+
}

src/goto-programs/goto_program.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class goto_programt:public goto_program_templatet<codet, exprt>
3939
// get the variables in decl statements
4040
typedef std::set<irep_idt> decl_identifierst;
4141
void get_decl_identifiers(decl_identifierst &decl_identifiers) const;
42+
43+
bool check_internal_invariants() const;
4244
};
4345

4446
#define forall_goto_program_instructions(it, program) \

src/goto-programs/goto_program_template.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,55 @@ class goto_program_templatet
250250
instruction_id_builder << type;
251251
return instruction_id_builder.str();
252252
}
253+
254+
bool check_internal_invariants() const
255+
{
256+
if(function.empty())
257+
return true;
258+
259+
switch(type)
260+
{
261+
case GOTO:
262+
case ASSUME:
263+
case ASSERT:
264+
if(code.is_not_nil() ||
265+
guard.is_nil())
266+
return true;
267+
return false;
268+
case OTHER:
269+
return false;
270+
case SKIP:
271+
case LOCATION:
272+
case END_FUNCTION:
273+
return code.is_not_nil();
274+
case START_THREAD:
275+
return false;
276+
case END_THREAD:
277+
return false;
278+
case ATOMIC_BEGIN:
279+
return false;
280+
case ATOMIC_END:
281+
return false;
282+
case RETURN:
283+
return false;
284+
case ASSIGN:
285+
if(code.get_statement()!=ID_assign)
286+
return true;
287+
return false;
288+
case DECL:
289+
return code.is_nil();
290+
case DEAD:
291+
return code.is_nil();
292+
case FUNCTION_CALL:
293+
return code.is_nil();
294+
case THROW:
295+
return false;
296+
case CATCH:
297+
return false;
298+
default:
299+
return true;
300+
}
301+
}
253302
};
254303

255304
typedef std::list<instructiont> instructionst;
@@ -460,6 +509,14 @@ class goto_program_templatet
460509
return end_function;
461510
}
462511

512+
const_targett get_end_function() const
513+
{
514+
assert(!instructions.empty());
515+
const auto end_function=std::prev(instructions.end());
516+
assert(end_function->is_end_function());
517+
return end_function;
518+
}
519+
463520
//! Copy a full goto program, preserving targets
464521
void copy_from(const goto_program_templatet<codeT, guardT> &src);
465522

0 commit comments

Comments
 (0)