Skip to content

Commit ae74767

Browse files
author
Daniel Kroening
authored
Merge pull request #911 from martin-cs/feature/internal-invariant
Feature/internal invariant
2 parents 9d8d81a + cbe7de3 commit ae74767

File tree

17 files changed

+827
-162
lines changed

17 files changed

+827
-162
lines changed

CODING_STANDARD

+3
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ C++ features:
158158
- Use the auto keyword if and only if one of the following
159159
- The type is explictly repeated on the RHS (e.g. a constructor call)
160160
- Adding the type will increase confusion (e.g. iterators, function pointers)
161+
- Avoid assert, if the condition is an actual invariant, use INVARIANT,
162+
PRECONDITION, POSTCONDITION, CHECK_RETURN, UNREACHABLE or DATA_INVARIANT.
163+
If there are possible reasons why it might fail, throw an exception.
161164

162165
Architecture-specific code:
163166
- Avoid if possible.
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
int main()
2+
{
3+
return 0;
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--test-invariant-failure
4+
^EXIT=(0|127|134|137)$
5+
^SIGNAL=0$
6+
Invariant check failed
7+
^(Backtrace)|(Backtraces not supported)$
8+
--
9+
^warning: ignoring
10+
^VERIFICATION SUCCESSFUL$

regression/cpp-linter/assert/main.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Author: Martin Brain, [email protected]
2+
3+
#include <cassert>
4+
#include <assert.h>
5+
6+
int main(int argc, char **argv)
7+
{
8+
assert(0);
9+
return 0;
10+
}
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
main.cpp
3+
4+
^main\.cpp:8: assert is deprecated, use INVARIANT instead \[build/deprecated\] \[4\]
5+
^Total errors found: 1$
6+
^SIGNAL=0$

regression/test.pl

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ ($$$$$)
3535
print LOG " Core: $dumped_core\n";
3636

3737
if($signal_num != 0) {
38-
$failed = 1;
3938
print "Killed by signal $signal_num";
4039
if($dumped_core) {
4140
print " (code dumped)";

scripts/cpplint.py

+22
Original file line numberDiff line numberDiff line change
@@ -4629,6 +4629,27 @@ def CheckAltTokens(filename, clean_lines, linenum, error):
46294629
_ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
46304630

46314631

4632+
def CheckAssert(filename, clean_lines, linenum, error):
4633+
"""Check for uses of assert.
4634+
4635+
Args:
4636+
filename: The name of the current file.
4637+
clean_lines: A CleansedLines instance containing the file.
4638+
linenum: The number of the line to check.
4639+
error: The function to call with any errors found.
4640+
"""
4641+
line = clean_lines.elided[linenum]
4642+
match = Match(r'.*\s+assert\(.*\).*', line)
4643+
if match:
4644+
if Match(r'.*\s+assert\((0|false)\).*', line):
4645+
error(filename, linenum, 'build/deprecated', 4,
4646+
'assert is deprecated, use UNREACHABLE instead')
4647+
else:
4648+
error(filename, linenum, 'build/deprecated', 4,
4649+
'assert is deprecated, use INVARIANT, PRECONDITION, CHECK_RETURN, etc. instead')
4650+
4651+
4652+
46324653
def GetLineWidth(line):
46334654
"""Determines the width of the line in column positions.
46344655
@@ -4853,6 +4874,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
48534874
CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
48544875
CheckCheck(filename, clean_lines, linenum, error)
48554876
CheckAltTokens(filename, clean_lines, linenum, error)
4877+
CheckAssert(filename, clean_lines, linenum, error)
48564878
classinfo = nesting_state.InnermostClass()
48574879
if classinfo:
48584880
CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)

src/cbmc/cbmc_parse_options.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Author: Daniel Kroening, [email protected]
1919
#include <util/language.h>
2020
#include <util/unicode.h>
2121
#include <util/memory_info.h>
22+
#include <util/invariant.h>
2223

2324
#include <ansi-c/c_preprocess.h>
2425

@@ -104,6 +105,27 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
104105
exit(1); // should contemplate EX_USAGE from sysexits.h
105106
}
106107

108+
// Test only; do not use for input validation
109+
if(cmdline.isset("test-invariant-failure"))
110+
{
111+
// Have to catch this as the default handling of uncaught exceptions
112+
// on windows appears to be silent termination.
113+
try
114+
{
115+
INVARIANT(0, "Test invariant failure");
116+
}
117+
catch (const invariant_failedt &e)
118+
{
119+
std::cerr << e.what();
120+
exit(0); // should contemplate EX_OK from sysexits.h
121+
}
122+
catch (...)
123+
{
124+
error() << "Unexpected exception type\n";
125+
}
126+
exit(1);
127+
}
128+
107129
if(cmdline.isset("program-only"))
108130
options.set_option("program-only", true);
109131

src/cbmc/cbmc_parse_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class optionst;
6363
"(java-cp-include-files):" \
6464
"(localize-faults)(localize-faults-method):" \
6565
"(lazy-methods)" \
66+
"(test-invariant-failure)" \
6667
"(fixedbv)(floatbv)(all-claims)(all-properties)" // legacy, and will eventually disappear // NOLINT(whitespace/line_length)
6768

6869
class cbmc_parse_optionst:

src/solvers/smt2/smt2_conv.cpp

+16-16
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Author: Daniel Kroening, [email protected]
2020
#include <util/ieee_float.h>
2121
#include <util/base_type.h>
2222
#include <util/string2int.h>
23+
#include <util/invariant.h>
2324

2425
#include <ansi-c/string_constant.h>
2526

@@ -34,7 +35,6 @@ Author: Daniel Kroening, [email protected]
3435

3536
// Mark different kinds of error condition
3637
// General
37-
#define UNREACHABLE throw "Supposidly unreachable location reached"
3838
#define PARSERERROR(S) throw S
3939

4040
// Error checking the expression type
@@ -45,7 +45,7 @@ Author: Daniel Kroening, [email protected]
4545
#define UNEXPECTEDCASE(S) throw "Unexpected case: " S
4646

4747
// General todos
48-
#define TODO(S) throw "TODO: " S
48+
#define SMT2_TODO(S) throw "TODO: " S
4949

5050
void smt2_convt::print_assignment(std::ostream &out) const
5151
{
@@ -952,7 +952,7 @@ void smt2_convt::convert_expr(const exprt &expr)
952952
out << "))"; // mk-, let
953953
}
954954
else
955-
TODO("bitnot for vectors");
955+
SMT2_TODO("bitnot for vectors");
956956
}
957957
else
958958
{
@@ -1017,7 +1017,7 @@ void smt2_convt::convert_expr(const exprt &expr)
10171017
out << "))"; // mk-, let
10181018
}
10191019
else
1020-
TODO("unary minus for vector");
1020+
SMT2_TODO("unary minus for vector");
10211021
}
10221022
else
10231023
{
@@ -1363,7 +1363,7 @@ void smt2_convt::convert_expr(const exprt &expr)
13631363
assert(expr.operands().size()==1);
13641364

13651365
out << "false"; // TODO
1366-
TODO("pointer_object_has_type not implemented");
1366+
SMT2_TODO("pointer_object_has_type not implemented");
13671367
}
13681368
else if(expr.id()==ID_string_constant)
13691369
{
@@ -1432,7 +1432,7 @@ void smt2_convt::convert_expr(const exprt &expr)
14321432
convert_expr(tmp);
14331433
out << ")) bin1)"; // bvlshr, extract, =
14341434
#endif
1435-
TODO("smt2: extractbits with non-constant index");
1435+
SMT2_TODO("smt2: extractbits with non-constant index");
14361436
}
14371437
}
14381438
else if(expr.id()==ID_replication)
@@ -1944,7 +1944,7 @@ void smt2_convt::convert_typecast(const typecast_exprt &expr)
19441944
// This conversion is non-trivial as it requires creating a
19451945
// new bit-vector variable and then asserting that it converts
19461946
// to the required floating-point number.
1947-
TODO("bit-wise floatbv to bv");
1947+
SMT2_TODO("bit-wise floatbv to bv");
19481948
}
19491949
else
19501950
{
@@ -2017,7 +2017,7 @@ void smt2_convt::convert_typecast(const typecast_exprt &expr)
20172017
out << "(_ bv" << i << " " << to_width << ")";
20182018
}
20192019
else
2020-
TODO("can't convert non-constant integer to bitvector");
2020+
SMT2_TODO("can't convert non-constant integer to bitvector");
20212021
}
20222022
else if(src_type.id()==ID_struct) // flatten a struct to a bit-vector
20232023
{
@@ -2207,7 +2207,7 @@ void smt2_convt::convert_typecast(const typecast_exprt &expr)
22072207
}
22082208
else if(dest_type.id()==ID_range)
22092209
{
2210-
TODO("range typecast");
2210+
SMT2_TODO("range typecast");
22112211
}
22122212
else if(dest_type.id()==ID_floatbv)
22132213
{
@@ -3031,11 +3031,11 @@ void smt2_convt::convert_floatbv_plus(const ieee_float_op_exprt &expr)
30313031
}
30323032
else if(type.id()==ID_complex)
30333033
{
3034-
TODO("+ for floatbv complex");
3034+
SMT2_TODO("+ for floatbv complex");
30353035
}
30363036
else if(type.id()==ID_vector)
30373037
{
3038-
TODO("+ for floatbv vector");
3038+
SMT2_TODO("+ for floatbv vector");
30393039
}
30403040
else
30413041
UNEXPECTEDCASE("unsupported type for +: "+type.id_string());
@@ -3093,7 +3093,7 @@ void smt2_convt::convert_minus(const minus_exprt &expr)
30933093
}
30943094
else if(expr.type().id()==ID_pointer)
30953095
{
3096-
TODO("pointer subtraction");
3096+
SMT2_TODO("pointer subtraction");
30973097
}
30983098
else if(expr.type().id()==ID_vector)
30993099
{
@@ -3527,7 +3527,7 @@ void smt2_convt::convert_with(const with_exprt &expr)
35273527
typecast_exprt index_tc(index, expr_type);
35283528

35293529
// TODO: SMT2-ify
3530-
TODO("SMT2-ify");
3530+
SMT2_TODO("SMT2-ify");
35313531
out << "(bvor ";
35323532
out << "(band ";
35333533

@@ -3565,7 +3565,7 @@ void smt2_convt::convert_update(const exprt &expr)
35653565
{
35663566
assert(expr.operands().size()==3);
35673567

3568-
TODO("smt2_convt::convert_update to be implemented");
3568+
SMT2_TODO("smt2_convt::convert_update to be implemented");
35693569
}
35703570

35713571
void smt2_convt::convert_index(const index_exprt &expr)
@@ -3651,7 +3651,7 @@ void smt2_convt::convert_index(const index_exprt &expr)
36513651
mp_integer index_int;
36523652
if(to_integer(expr.index(), index_int))
36533653
{
3654-
TODO("non-constant index on vectors");
3654+
SMT2_TODO("non-constant index on vectors");
36553655
}
36563656
else
36573657
{
@@ -3662,7 +3662,7 @@ void smt2_convt::convert_index(const index_exprt &expr)
36623662
}
36633663
else
36643664
{
3665-
TODO("index on vectors");
3665+
SMT2_TODO("index on vectors");
36663666
}
36673667
}
36683668
else

src/util/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ SRC = arith_tools.cpp \
2424
guard.cpp \
2525
identifier.cpp \
2626
ieee_float.cpp \
27+
invariant.cpp \
2728
irep.cpp \
2829
irep_hash.cpp \
2930
irep_hash_container.cpp \

src/util/expr.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ Author: Daniel Kroening, [email protected]
99
/// \file
1010
/// Expression Representation
1111

12-
#include <cassert>
13-
1412
#include <stack>
1513

1614
#include "string2int.h"
1715
#include "mp_arith.h"
1816
#include "fixedbv.h"
1917
#include "ieee_float.h"
18+
#include "invariant.h"
2019
#include "expr.h"
2120
#include "rational.h"
2221
#include "rational_tools.h"
@@ -203,15 +202,16 @@ void exprt::negate()
203202
else
204203
{
205204
make_nil();
206-
assert(false);
205+
UNREACHABLE;
207206
}
208207
}
209208
else
210209
{
211210
if(id()==ID_unary_minus)
212211
{
213212
exprt tmp;
214-
assert(operands().size()==1);
213+
DATA_INVARIANT(operands().size()==1,
214+
"Unary minus must have one operand");
215215
tmp.swap(op0());
216216
swap(tmp);
217217
}
@@ -245,7 +245,7 @@ bool exprt::is_zero() const
245245
{
246246
rationalt rat_value;
247247
if(to_rational(*this, rat_value))
248-
assert(false);
248+
CHECK_RETURN(false);
249249
return rat_value.is_zero();
250250
}
251251
else if(type_id==ID_unsignedbv ||
@@ -291,7 +291,7 @@ bool exprt::is_one() const
291291
{
292292
rationalt rat_value;
293293
if(to_rational(*this, rat_value))
294-
assert(false);
294+
CHECK_RETURN(false);
295295
return rat_value.is_one();
296296
}
297297
else if(type_id==ID_unsignedbv || type_id==ID_signedbv)

src/util/expr_util.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ exprt make_binary(const exprt &expr)
3636
const typet &type=expr.type();
3737

3838
exprt previous=operands.front();
39-
assert(previous.type()==type);
39+
PRECONDITION(previous.type()==type);
4040

4141
for(exprt::operandst::const_iterator
4242
it=++operands.begin();
4343
it!=operands.end();
4444
++it)
4545
{
46-
assert(it->type()==type);
46+
PRECONDITION(it->type()==type);
4747

4848
exprt tmp=expr;
4949
tmp.operands().clear();
@@ -59,7 +59,7 @@ exprt make_binary(const exprt &expr)
5959
with_exprt make_with_expr(const update_exprt &src)
6060
{
6161
const exprt::operandst &designator=src.designator();
62-
assert(!designator.empty());
62+
PRECONDITION(!designator.empty());
6363

6464
with_exprt result;
6565
exprt *dest=&result;
@@ -78,7 +78,7 @@ with_exprt make_with_expr(const update_exprt &src)
7878
// to_member_designator(*it).get_component_name();
7979
}
8080
else
81-
assert(false);
81+
UNREACHABLE;
8282

8383
*dest=tmp;
8484
dest=&to_with_expr(*dest).new_value();
@@ -108,7 +108,7 @@ exprt is_not_zero(
108108
src_type.id()==ID_floatbv?ID_ieee_float_notequal:ID_notequal;
109109

110110
exprt zero=from_integer(0, src_type);
111-
assert(zero.is_not_nil());
111+
CHECK_RETURN(zero.is_not_nil());
112112

113113
binary_exprt comparison(src, id, zero, bool_typet());
114114
comparison.add_source_location()=src.source_location();
@@ -142,8 +142,8 @@ bool has_subexpr(const exprt &src, const irep_idt &id)
142142

143143
if_exprt lift_if(const exprt &src, std::size_t operand_number)
144144
{
145-
assert(operand_number<src.operands().size());
146-
assert(src.operands()[operand_number].id()==ID_if);
145+
PRECONDITION(operand_number<src.operands().size());
146+
PRECONDITION(src.operands()[operand_number].id()==ID_if);
147147

148148
const if_exprt if_expr=to_if_expr(src.operands()[operand_number]);
149149
const exprt true_case=if_expr.true_case();

0 commit comments

Comments
 (0)