Skip to content

Commit 73fc478

Browse files
author
Remi Delmas
committed
CONTRACTS: Error-out on unknown functions (replace/enforce).
goto-instrument now errors out when attempting to enforce or replace the contract of an unknown function. Added missing error checking in `goto_instrument_parse_optionst::doit()` on return of `replace_calls` and `enforce_contracts`.
1 parent 6ca79bf commit 73fc478

File tree

7 files changed

+83
-19
lines changed

7 files changed

+83
-19
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
int main()
3+
{
4+
return 0;
5+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--enforce-contract goo
4+
^Invariant check failed$
5+
^Condition: Precondition$
6+
^Reason: all_functions_found\(to_enforce\)$
7+
^EXIT=(127|134)$
8+
^SIGNAL=0$
9+
--
10+
--
11+
Checks that attempting to enforce the contract of an unknown function creates
12+
an error.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
int main()
2+
{
3+
return 0;
4+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--replace-call-with-contract goo
4+
^Invariant check failed$
5+
^Condition: Precondition$
6+
^Reason: all_functions_found\(to_replace\)$
7+
^EXIT=(127|134)$
8+
^SIGNAL=0$
9+
--
10+
--
11+
Checks that attempting call replacement with an unknown function creates an
12+
error.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,8 +1536,29 @@ void code_contractst::add_contract_check(
15361536
dest.destructive_insert(dest.instructions.begin(), check);
15371537
}
15381538

1539+
bool code_contractst::all_functions_found(
1540+
const std::set<std::string> &functions) const
1541+
{
1542+
bool all_found = true;
1543+
for(const auto &function : functions)
1544+
{
1545+
if(
1546+
goto_functions.function_map.find(function) ==
1547+
goto_functions.function_map.end())
1548+
{
1549+
all_found = false;
1550+
log.error() << "Function '" << function << "' not found" << messaget::eom;
1551+
}
1552+
}
1553+
return all_found;
1554+
}
1555+
15391556
bool code_contractst::replace_calls(const std::set<std::string> &to_replace)
15401557
{
1558+
PRECONDITION_WITH_DIAGNOSTICS(
1559+
all_functions_found(to_replace),
1560+
"Functions to replace with contracts must exist in the GOTO program");
1561+
15411562
if(to_replace.empty())
15421563
return false;
15431564

@@ -1587,25 +1608,17 @@ void code_contractst::apply_loop_contracts()
15871608

15881609
bool code_contractst::enforce_contracts(const std::set<std::string> &to_enforce)
15891610
{
1611+
PRECONDITION_WITH_DIAGNOSTICS(
1612+
all_functions_found(to_enforce),
1613+
"Functions to enforce contracts for must exist in the GOTO program");
1614+
15901615
if(to_enforce.empty())
15911616
return false;
15921617

15931618
bool fail = false;
15941619

15951620
for(const auto &function : to_enforce)
1596-
{
1597-
auto goto_function = goto_functions.function_map.find(function);
1598-
if(goto_function == goto_functions.function_map.end())
1599-
{
1600-
fail = true;
1601-
log.error() << "Could not find function '" << function
1602-
<< "' in goto-program; not enforcing contracts."
1603-
<< messaget::eom;
1604-
continue;
1605-
}
1621+
fail |= enforce_contract(function);
16061622

1607-
if(!fail)
1608-
fail = enforce_contract(function);
1609-
}
16101623
return fail;
16111624
}

src/goto-instrument/contracts/contracts.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,14 @@ class code_contractst
6262
{
6363
}
6464

65-
/// \brief Replace all calls to each function in the list with that function's
66-
/// contract
65+
/// True iff all functions in `functions` are found in the GOTO program or
66+
// `functions` is empty.
67+
bool all_functions_found(const std::set<std::string> &functions) const;
68+
69+
/// \brief Replace all calls to each function in the `to_replace` set
70+
/// with that function's contract
71+
///
72+
/// All functions in `to_replace` must be found in the GOTO programs.
6773
///
6874
/// Use this function when proving code that calls into an expensive function,
6975
/// `F`. You can write a contract for F using __CPROVER_requires and
@@ -75,11 +81,13 @@ class code_contractst
7581
/// it using `cbmc --function F`.
7682
///
7783
/// \return `true` on failure, `false` otherwise
78-
bool replace_calls(const std::set<std::string> &);
84+
bool replace_calls(const std::set<std::string> &to_replace);
7985

8086
/// \brief Turn requires & ensures into assumptions and assertions for each of
8187
/// the named functions
8288
///
89+
/// All functions in `to_enforce` must be found in the GOTO programs.
90+
///
8391
/// Use this function to prove the correctness of a function F independently
8492
/// of its calling context. If you have proved that F is correct, then you can
8593
/// soundly replace all calls to F with F's contract using the
@@ -93,7 +101,7 @@ class code_contractst
93101
/// then asserts `CF`'s `ensures` clause.
94102
///
95103
/// \return `true` on failure, `false` otherwise
96-
bool enforce_contracts(const std::set<std::string> &functions);
104+
bool enforce_contracts(const std::set<std::string> &to_enforce);
97105

98106
void apply_loop_contracts();
99107

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,8 +1150,18 @@ void goto_instrument_parse_optionst::instrument_goto_program()
11501150
// first replacement then enforcement. We rely on contract replacement
11511151
// and inlining of sub-function calls to properly annotate all
11521152
// assignments.
1153-
contracts.replace_calls(to_replace);
1154-
contracts.enforce_contracts(to_enforce);
1153+
if(contracts.replace_calls(to_replace))
1154+
{
1155+
log.error() << FLAG_REPLACE_CALL << " failed, aborting." << messaget::eom;
1156+
throw 0;
1157+
}
1158+
1159+
if(contracts.enforce_contracts(to_enforce))
1160+
{
1161+
log.error() << FLAG_ENFORCE_CONTRACT << " failed, aborting."
1162+
<< messaget::eom;
1163+
throw 0;
1164+
}
11551165

11561166
if(cmdline.isset(FLAG_LOOP_CONTRACTS))
11571167
contracts.apply_loop_contracts();

0 commit comments

Comments
 (0)