Skip to content

Commit c3d7235

Browse files
authored
Merge pull request #6363 from feliperodri/handle-mangled-names
Handle functions with mangled names in contract replacement
2 parents 98bbe74 + ec9ac5f commit c3d7235

File tree

4 files changed

+66
-30
lines changed

4 files changed

+66
-30
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdlib.h>
2+
3+
int x;
4+
int *z = &x;
5+
6+
void bar() __CPROVER_assigns(*z)
7+
{
8+
}
9+
10+
static void foo() __CPROVER_assigns(*z)
11+
{
12+
bar();
13+
}
14+
15+
int main()
16+
{
17+
foo();
18+
return 0;
19+
}
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 bar
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[\d+\] file main.c line \d+ Check that bar\'s assigns clause is a subset of foo\'s assigns clause: SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
^Condition: \!not\_found$
10+
--
11+
Checks whether CBMC properly evaluates subset relationship on assigns
12+
during replacement with static functions.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -473,18 +473,21 @@ code_contractst::create_ensures_instruction(
473473
}
474474

475475
bool code_contractst::apply_function_contract(
476-
goto_programt &goto_program,
477-
goto_programt::targett target)
476+
const irep_idt &function,
477+
goto_programt &function_body,
478+
goto_programt::targett &target)
478479
{
480+
const auto &const_target =
481+
static_cast<const goto_programt::targett &>(target);
479482
// Return if the function is not named in the call; currently we don't handle
480483
// function pointers.
481-
PRECONDITION(as_const(*target).call_function().id() == ID_symbol);
484+
PRECONDITION(const_target->call_function().id() == ID_symbol);
482485

483486
// Retrieve the function type, which is needed to extract the contract
484487
// components.
485-
const irep_idt &function =
486-
to_symbol_expr(as_const(*target).call_function()).get_identifier();
487-
const symbolt &function_symbol = ns.lookup(function);
488+
const irep_idt &target_function =
489+
to_symbol_expr(const_target->call_function()).get_identifier();
490+
const symbolt &function_symbol = ns.lookup(target_function);
488491
const auto &type = to_code_with_contract_type(function_symbol.type);
489492

490493
// Isolate each component of the contract.
@@ -499,15 +502,15 @@ bool code_contractst::apply_function_contract(
499502
if(type.return_type() != empty_typet())
500503
{
501504
// Check whether the function's return value is not disregarded.
502-
if(as_const(*target).call_lhs().is_not_nil())
505+
if(target->call_lhs().is_not_nil())
503506
{
504507
// If so, have it replaced appropriately.
505508
// For example, if foo() ensures that its return value is > 5, then
506509
// rewrite calls to foo as follows:
507510
// x = foo() -> assume(__CPROVER_return_value > 5) -> assume(x > 5)
508511
symbol_exprt ret_val(
509-
CPROVER_PREFIX "return_value", as_const(*target).call_lhs().type());
510-
common_replace.insert(ret_val, as_const(*target).call_lhs());
512+
CPROVER_PREFIX "return_value", const_target->call_lhs().type());
513+
common_replace.insert(ret_val, const_target->call_lhs());
511514
}
512515
else
513516
{
@@ -521,10 +524,10 @@ bool code_contractst::apply_function_contract(
521524
// fresh variable to replace __CPROVER_return_value with.
522525
const symbolt &fresh = get_fresh_aux_symbol(
523526
type.return_type(),
524-
id2string(function),
527+
id2string(target_function),
525528
"ignored_return_value",
526-
target->source_location,
527-
symbol_table.lookup_ref(function).mode,
529+
const_target->source_location,
530+
symbol_table.lookup_ref(target_function).mode,
528531
ns,
529532
symbol_table);
530533
symbol_exprt ret_val(CPROVER_PREFIX "return_value", type.return_type());
@@ -534,7 +537,7 @@ bool code_contractst::apply_function_contract(
534537
}
535538

536539
// Replace formal parameters
537-
const auto &arguments = target->call_arguments();
540+
const auto &arguments = const_target->call_arguments();
538541
auto a_it = arguments.begin();
539542
for(auto p_it = type.parameters().begin();
540543
p_it != type.parameters().end() && a_it != arguments.end();
@@ -551,9 +554,9 @@ bool code_contractst::apply_function_contract(
551554
// and only refer to the common symbols to be replaced.
552555
common_replace(assigns);
553556

554-
const auto &mode = symbol_table.lookup_ref(function).mode;
557+
const auto &mode = symbol_table.lookup_ref(target_function).mode;
555558

556-
is_fresh_replacet is_fresh(*this, log, function);
559+
is_fresh_replacet is_fresh(*this, log, target_function);
557560
is_fresh.create_declarations();
558561

559562
// Insert assertion of the precondition immediately before the call site.
@@ -567,14 +570,14 @@ bool code_contractst::apply_function_contract(
567570
converter.goto_convert(
568571
code_assertt(requires),
569572
assertion,
570-
symbol_table.lookup_ref(function).mode);
573+
symbol_table.lookup_ref(target_function).mode);
571574
assertion.instructions.back().source_location = requires.source_location();
572575
assertion.instructions.back().source_location.set_comment(
573576
"Check requires clause");
574577
assertion.instructions.back().source_location.set_property_class(
575578
ID_precondition);
576579
is_fresh.update_requires(assertion);
577-
insert_before_swap_and_advance(goto_program, target, assertion);
580+
insert_before_swap_and_advance(function_body, target, assertion);
578581
}
579582

580583
// Gather all the instructions required to handle history variables
@@ -590,11 +593,11 @@ bool code_contractst::apply_function_contract(
590593
ensures_pair = create_ensures_instruction(
591594
assumption,
592595
ensures.source_location(),
593-
symbol_table.lookup_ref(function).mode);
596+
symbol_table.lookup_ref(target_function).mode);
594597

595598
// add all the history variable initialization instructions
596599
// to the goto program
597-
insert_before_swap_and_advance(goto_program, target, ensures_pair.second);
600+
insert_before_swap_and_advance(function_body, target, ensures_pair.second);
598601
}
599602

600603
// Create a series of non-deterministic assignments to havoc the variables
@@ -604,9 +607,8 @@ bool code_contractst::apply_function_contract(
604607
assigns_clauset assigns_clause(assigns, log, ns);
605608

606609
// Retrieve assigns clause of the caller function if exists.
607-
const irep_idt &caller_function = target->source_location.get_function();
608610
auto caller_assigns =
609-
to_code_with_contract_type(ns.lookup(caller_function).type).assigns();
611+
to_code_with_contract_type(ns.lookup(function).type).assigns();
610612

611613
if(caller_assigns.is_not_nil())
612614
{
@@ -617,31 +619,32 @@ bool code_contractst::apply_function_contract(
617619
caller_assigns_clause.generate_subset_check(assigns_clause),
618620
assigns_clause.location));
619621
subset_check_assertion.instructions.back().source_location.set_comment(
620-
"Check that " + id2string(function) +
621-
"'s assigns clause is a subset of " + id2string(caller_function) +
622+
"Check that " + id2string(target_function) +
623+
"'s assigns clause is a subset of " +
624+
id2string(const_target->source_location.get_function()) +
622625
"'s assigns clause");
623626
insert_before_swap_and_advance(
624-
goto_program, target, subset_check_assertion);
627+
function_body, target, subset_check_assertion);
625628
}
626629

627630
// Havoc all targets in global write set
628631
auto assigns_havoc = assigns_clause.generate_havoc_code();
629632

630633
// Insert the non-deterministic assignment immediately before the call site.
631-
insert_before_swap_and_advance(goto_program, target, assigns_havoc);
634+
insert_before_swap_and_advance(function_body, target, assigns_havoc);
632635
}
633636

634637
// To remove the function call, insert statements related to the assumption.
635638
// Then, replace the function call with a SKIP statement.
636639
if(!ensures.is_false())
637640
{
638641
is_fresh.update_ensures(ensures_pair.first);
639-
insert_before_swap_and_advance(goto_program, target, ensures_pair.first);
642+
insert_before_swap_and_advance(function_body, target, ensures_pair.first);
640643
}
641644
*target = goto_programt::make_skip();
642645

643646
// Add this function to the set of replaced functions.
644-
summarized.insert(function);
647+
summarized.insert(target_function);
645648
return false;
646649
}
647650

@@ -1223,7 +1226,8 @@ bool code_contractst::replace_calls(const std::set<std::string> &functions)
12231226
if(found == functions.end())
12241227
continue;
12251228

1226-
fail |= apply_function_contract(goto_function.second.body, ins);
1229+
fail |= apply_function_contract(
1230+
goto_function.first, goto_function.second.body, ins);
12271231
}
12281232
}
12291233
}

src/goto-instrument/contracts/contracts.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,9 @@ class code_contractst
195195
/// non-deterministic assignments for the write set, and assumptions
196196
/// based on ensures clauses.
197197
bool apply_function_contract(
198-
goto_programt &goto_program,
199-
goto_programt::targett target);
198+
const irep_idt &,
199+
goto_programt &,
200+
goto_programt::targett &);
200201

201202
/// Instruments `wrapper_function` adding assumptions based on requires
202203
/// clauses and assertions based on ensures clauses.

0 commit comments

Comments
 (0)