Skip to content

Commit 627faee

Browse files
Merge pull request #6733 from remi-delmas-3000/contracts-replace-unknown-fix
CONTRACTS: Error-out on unknown functions (replace/enforce).
2 parents d0c594f + 69eded9 commit 627faee

File tree

5 files changed

+89
-75
lines changed

5 files changed

+89
-75
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--enforce-contract goo
4+
^Function 'goo' was not found in the GOTO program.$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--
8+
--
9+
Checks that attempting to enforce the contract of an unknown function creates
10+
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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--replace-call-with-contract goo
4+
^Function 'goo' was not found in the GOTO program.$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--
8+
--
9+
Checks that attempting call replacement with an unknown function creates an
10+
error.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 51 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,8 @@ Date: February 2016
1313

1414
#include "contracts.h"
1515

16-
#include <algorithm>
17-
#include <map>
18-
19-
#include <analyses/local_bitvector_analysis.h>
20-
#include <analyses/local_may_alias.h>
21-
22-
#include <ansi-c/c_expr.h>
23-
24-
#include <goto-instrument/havoc_utils.h>
25-
26-
#include <goto-programs/goto_inline.h>
27-
#include <goto-programs/goto_program.h>
28-
#include <goto-programs/remove_skip.h>
29-
30-
#include <langapi/language_util.h>
31-
3216
#include <util/c_types.h>
17+
#include <util/exception_utils.h>
3318
#include <util/expr_util.h>
3419
#include <util/find_symbols.h>
3520
#include <util/format_expr.h>
@@ -43,11 +28,24 @@ Date: February 2016
4328
#include <util/replace_symbol.h>
4429
#include <util/std_code.h>
4530

31+
#include <goto-programs/goto_inline.h>
32+
#include <goto-programs/goto_program.h>
33+
#include <goto-programs/remove_skip.h>
34+
35+
#include <analyses/local_bitvector_analysis.h>
36+
#include <analyses/local_may_alias.h>
37+
#include <ansi-c/c_expr.h>
38+
#include <goto-instrument/havoc_utils.h>
39+
#include <langapi/language_util.h>
40+
4641
#include "havoc_assigns_clause_targets.h"
4742
#include "instrument_spec_assigns.h"
4843
#include "memory_predicates.h"
4944
#include "utils.h"
5045

46+
#include <algorithm>
47+
#include <map>
48+
5149
/// Decorator for \ref message_handlert that keeps track of warnings
5250
/// occuring when inlining a function.
5351
///
@@ -729,7 +727,7 @@ code_contractst::create_ensures_instruction(
729727
return std::make_pair(std::move(ensures_program), std::move(history));
730728
}
731729

732-
bool code_contractst::apply_function_contract(
730+
void code_contractst::apply_function_contract(
733731
const irep_idt &function,
734732
const source_locationt &location,
735733
goto_programt &function_body,
@@ -932,7 +930,6 @@ bool code_contractst::apply_function_contract(
932930

933931
// Add this function to the set of replaced functions.
934932
summarized.insert(target_function);
935-
return false;
936933
}
937934

938935
void code_contractst::apply_loop_contract(
@@ -1225,17 +1222,14 @@ goto_functionst &code_contractst::get_goto_functions()
12251222
return goto_functions;
12261223
}
12271224

1228-
bool code_contractst::check_frame_conditions_function(const irep_idt &function)
1225+
void code_contractst::check_frame_conditions_function(const irep_idt &function)
12291226
{
12301227
// Get the function object before instrumentation.
12311228
auto function_obj = goto_functions.function_map.find(function);
1232-
if(function_obj == goto_functions.function_map.end())
1233-
{
1234-
log.error() << "Could not find function '" << function
1235-
<< "' in goto-program; not enforcing contracts."
1236-
<< messaget::eom;
1237-
return true;
1238-
}
1229+
1230+
INVARIANT(
1231+
function_obj != goto_functions.function_map.end(),
1232+
"Function '" + id2string(function) + "'must exist in the goto program");
12391233

12401234
const auto &goto_function = function_obj->second;
12411235
auto &function_body = function_obj->second.body;
@@ -1316,11 +1310,9 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
13161310
function_body.instructions.end(),
13171311
skip_function_paramst::YES,
13181312
cfg_info_opt);
1319-
1320-
return false;
13211313
}
13221314

1323-
bool code_contractst::enforce_contract(const irep_idt &function)
1315+
void code_contractst::enforce_contract(const irep_idt &function)
13241316
{
13251317
// Add statements to the source function
13261318
// to ensure assigns clause is respected.
@@ -1333,13 +1325,9 @@ bool code_contractst::enforce_contract(const irep_idt &function)
13331325
const irep_idt original(function);
13341326

13351327
auto old_function = goto_functions.function_map.find(original);
1336-
if(old_function == goto_functions.function_map.end())
1337-
{
1338-
log.error() << "Could not find function '" << function
1339-
<< "' in goto-program; not enforcing contracts."
1340-
<< messaget::eom;
1341-
return true;
1342-
}
1328+
INVARIANT(
1329+
old_function != goto_functions.function_map.end(),
1330+
"Function to replace must exist in the program.");
13431331

13441332
std::swap(goto_functions.function_map[mangled], old_function->second);
13451333
goto_functions.function_map.erase(old_function);
@@ -1379,8 +1367,6 @@ bool code_contractst::enforce_contract(const irep_idt &function)
13791367
wrapper.parameter_identifiers = mangled_fun->second.parameter_identifiers;
13801368
wrapper.body.add(goto_programt::make_end_function(sl));
13811369
add_contract_check(original, mangled, wrapper.body);
1382-
1383-
return false;
13841370
}
13851371

13861372
void code_contractst::add_contract_check(
@@ -1536,12 +1522,29 @@ void code_contractst::add_contract_check(
15361522
dest.destructive_insert(dest.instructions.begin(), check);
15371523
}
15381524

1539-
bool code_contractst::replace_calls(const std::set<std::string> &to_replace)
1525+
void code_contractst::check_all_functions_found(
1526+
const std::set<std::string> &functions) const
1527+
{
1528+
for(const auto &function : functions)
1529+
{
1530+
if(
1531+
goto_functions.function_map.find(function) ==
1532+
goto_functions.function_map.end())
1533+
{
1534+
throw invalid_input_exceptiont(
1535+
"Function '" + function + "' was not found in the GOTO program.");
1536+
}
1537+
}
1538+
}
1539+
1540+
void code_contractst::replace_calls(const std::set<std::string> &to_replace)
15401541
{
15411542
if(to_replace.empty())
1542-
return false;
1543+
return;
15431544

1544-
bool fail = false;
1545+
log.status() << "Replacing function calls with contracts" << messaget::eom;
1546+
1547+
check_all_functions_found(to_replace);
15451548

15461549
for(auto &goto_function : goto_functions.function_map)
15471550
{
@@ -1559,7 +1562,7 @@ bool code_contractst::replace_calls(const std::set<std::string> &to_replace)
15591562
if(found == to_replace.end())
15601563
continue;
15611564

1562-
fail |= apply_function_contract(
1565+
apply_function_contract(
15631566
goto_function.first,
15641567
ins->source_location(),
15651568
goto_function.second.body,
@@ -1568,15 +1571,10 @@ bool code_contractst::replace_calls(const std::set<std::string> &to_replace)
15681571
}
15691572
}
15701573

1571-
if(fail)
1572-
return true;
1573-
15741574
for(auto &goto_function : goto_functions.function_map)
15751575
remove_skip(goto_function.second.body);
15761576

15771577
goto_functions.update();
1578-
1579-
return false;
15801578
}
15811579

15821580
void code_contractst::apply_loop_contracts()
@@ -1585,27 +1583,15 @@ void code_contractst::apply_loop_contracts()
15851583
apply_loop_contract(goto_function.first, goto_function.second);
15861584
}
15871585

1588-
bool code_contractst::enforce_contracts(const std::set<std::string> &to_enforce)
1586+
void code_contractst::enforce_contracts(const std::set<std::string> &to_enforce)
15891587
{
15901588
if(to_enforce.empty())
1591-
return false;
1589+
return;
15921590

1593-
bool fail = false;
1591+
log.status() << "Enforcing contracts" << messaget ::eom;
15941592

1595-
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-
}
1593+
check_all_functions_found(to_enforce);
16061594

1607-
if(!fail)
1608-
fail = enforce_contract(function);
1609-
}
1610-
return fail;
1595+
for(const auto &function : to_enforce)
1596+
enforce_contract(function);
16111597
}

src/goto-instrument/contracts/contracts.h

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

65-
/// \brief Replace all calls to each function in the list with that function's
66-
/// contract
65+
/// Throws an exception if some function `functions` is found in the program.
66+
void check_all_functions_found(const std::set<std::string> &functions) const;
67+
68+
/// \brief Replace all calls to each function in the `to_replace` set
69+
/// with that function's contract
70+
///
71+
/// Throws an exception if some `to_replace` functions are not found.
6772
///
6873
/// Use this function when proving code that calls into an expensive function,
6974
/// `F`. You can write a contract for F using __CPROVER_requires and
@@ -73,13 +78,13 @@ class code_contractst
7378
/// actually abides by its `ensures` and `requires` clauses, you should
7479
/// separately call `code_constractst::enforce_contracts()` on `F` and verify
7580
/// it using `cbmc --function F`.
76-
///
77-
/// \return `true` on failure, `false` otherwise
78-
bool replace_calls(const std::set<std::string> &);
81+
void replace_calls(const std::set<std::string> &to_replace);
7982

8083
/// \brief Turn requires & ensures into assumptions and assertions for each of
8184
/// the named functions
8285
///
86+
/// Throws an exception if some `to_enforce` functions are not found.
87+
///
8388
/// Use this function to prove the correctness of a function F independently
8489
/// of its calling context. If you have proved that F is correct, then you can
8590
/// soundly replace all calls to F with F's contract using the
@@ -92,8 +97,7 @@ class code_contractst
9297
/// function called `F` that assumes `CF`'s `requires` clause, calls `CF`, and
9398
/// then asserts `CF`'s `ensures` clause.
9499
///
95-
/// \return `true` on failure, `false` otherwise
96-
bool enforce_contracts(const std::set<std::string> &functions);
100+
void enforce_contracts(const std::set<std::string> &to_enforce);
97101

98102
void apply_loop_contracts();
99103

@@ -125,10 +129,10 @@ class code_contractst
125129
std::unordered_set<irep_idt> summarized;
126130

127131
/// \brief Enforce contract of a single function
128-
bool enforce_contract(const irep_idt &function);
132+
void enforce_contract(const irep_idt &function);
129133

130134
/// Instrument functions to check frame conditions.
131-
bool check_frame_conditions_function(const irep_idt &function);
135+
void check_frame_conditions_function(const irep_idt &function);
132136

133137
/// Apply loop contracts, whenever available, to all loops in `function`.
134138
/// Loop invariants, loop variants, and loop assigns clauses.
@@ -139,7 +143,7 @@ class code_contractst
139143
/// Replaces function calls with assertions based on requires clauses,
140144
/// non-deterministic assignments for the write set, and assumptions
141145
/// based on ensures clauses.
142-
bool apply_function_contract(
146+
void apply_function_contract(
143147
const irep_idt &function,
144148
const source_locationt &location,
145149
goto_programt &function_body,

0 commit comments

Comments
 (0)