Skip to content

Commit 0787063

Browse files
Petr BauchPetr Bauch
Petr Bauch
authored and
Petr Bauch
committed
Well-formedness check for assume and assert instructions
Check that the guard evaluates to a Boolean value.
1 parent 0bb024a commit 0787063

File tree

5 files changed

+127
-0
lines changed

5 files changed

+127
-0
lines changed

src/goto-programs/goto_program.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,16 @@ void goto_programt::instructiont::validate(
685685
case GOTO:
686686
break;
687687
case ASSUME:
688+
DATA_CHECK_WITH_DIAGNOSTICS(
689+
targets.empty(),
690+
"assume instruction should not have a target",
691+
source_location);
688692
break;
689693
case ASSERT:
694+
DATA_CHECK_WITH_DIAGNOSTICS(
695+
targets.empty(),
696+
"assert instruction should not have a target",
697+
source_location);
690698
break;
691699
case OTHER:
692700
break;

src/util/std_code.h

+10
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,11 @@ inline code_assumet &to_code_assume(codet &code)
536536
return static_cast<code_assumet &>(code);
537537
}
538538

539+
inline void validate_expr(const code_assumet &x)
540+
{
541+
validate_operands(x, 1, "assume must have one operand");
542+
}
543+
539544
/// A non-fatal assertion, which checks a condition then permits execution to
540545
/// continue.
541546
class code_assertt:public codet
@@ -583,6 +588,11 @@ inline code_assertt &to_code_assert(codet &code)
583588
return static_cast<code_assertt &>(code);
584589
}
585590

591+
inline void validate_expr(const code_assertt &x)
592+
{
593+
validate_operands(x, 1, "assert must have one operand");
594+
}
595+
586596
/// Create a fatal assertion, which checks a condition and then halts if it does
587597
/// not hold. Equivalent to `ASSERT(condition); ASSUME(condition)`.
588598
///

src/util/std_expr.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,47 @@ const exprt &object_descriptor_exprt::root_object() const
211211

212212
return *p;
213213
}
214+
215+
bool evaluates_to_boolean(const exprt &e)
216+
{
217+
if(e.type().id() != ID_bool)
218+
return false;
219+
if(e.id() == ID_typecast)
220+
return e.type().id() == ID_bool;
221+
222+
//Boolean constants
223+
if(e.id() == ID_true || e.id() == ID_false)
224+
return true;
225+
if(e.id() == ID_constant)
226+
return true;
227+
228+
//Symbols
229+
if(e.id() == ID_symbol)
230+
return true;
231+
232+
//arithmetic relations
233+
if(e.id() == ID_equal || e.id() == ID_notequal)
234+
return true;
235+
if(e.id() == ID_ieee_float_equal || e.id() == ID_ieee_float_notequal)
236+
return true;
237+
if(e.id() == ID_ge || e.id() == ID_gt)
238+
return true;
239+
if(e.id() == ID_le || e.id() == ID_lt)
240+
return true;
241+
242+
//propositional operators
243+
if(
244+
e.id() == ID_not || e.id() == ID_and || e.id() == ID_or ||
245+
e.id() == ID_implies)
246+
return true;
247+
if(e.id() == ID_exists || e.id() == ID_forall)
248+
return true;
249+
250+
//weird
251+
if(
252+
e.id() == ID_isfinite || e.id() == ID_isnormal || e.id() == ID_isinf ||
253+
e.id() == ID_isnan)
254+
return true;
255+
256+
return false;
257+
}

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SRC += analyses/ai/ai.cpp \
1717
compound_block_locations.cpp \
1818
goto-programs/goto_trace_output.cpp \
1919
goto-programs/goto_program_declaration.cpp \
20+
goto-programs/goto_program_assume.cpp \
2021
interpreter/interpreter.cpp \
2122
json/json_parser.cpp \
2223
path_strategies.cpp \
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for goto_program::validate
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <goto-programs/goto_function.h>
10+
#include <testing-utils/catch.hpp>
11+
#include <util/arith_tools.h>
12+
13+
SCENARIO(
14+
"Validation of well-formed assert/assume codes",
15+
"[core][goto-programs][validate]")
16+
{
17+
GIVEN("A program with one assumption")
18+
{
19+
symbol_tablet symbol_table;
20+
const typet type1 = signedbv_typet(32);
21+
symbolt symbol;
22+
irep_idt symbol_name = "a";
23+
symbol.name = symbol_name;
24+
symbol_exprt varx(symbol_name, type1);
25+
exprt val10 = from_integer(10, type1);
26+
binary_relation_exprt x_le_10(varx, ID_le, val10);
27+
28+
goto_functiont goto_function;
29+
auto &instructions = goto_function.body.instructions;
30+
instructions.emplace_back(goto_program_instruction_typet::ASSUME);
31+
32+
symbol.type = type1;
33+
symbol_table.insert(symbol);
34+
namespacet ns(symbol_table);
35+
instructions.back().make_assertion(x_le_10);
36+
37+
WHEN("Instruction has no targets")
38+
{
39+
THEN("The consistency check succeeds")
40+
{
41+
goto_function.body.validate(ns, validation_modet::INVARIANT);
42+
REQUIRE(true);
43+
}
44+
}
45+
46+
WHEN("Instruction has a target")
47+
{
48+
instructions.back().targets.push_back(instructions.begin());
49+
THEN("The consistency check fails")
50+
{
51+
bool caught = false;
52+
try
53+
{
54+
goto_function.body.validate(ns, validation_modet::EXCEPTION);
55+
}
56+
catch(incorrect_goto_program_exceptiont &e)
57+
{
58+
caught = true;
59+
}
60+
REQUIRE(caught);
61+
}
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)