Skip to content

Commit 4dddeee

Browse files
authored
Merge pull request #7488 from qinheping/goto-synthesizer-enumerating
SYNTHESIZER: Enable enumerating mode for checks other than pointer checks
2 parents 8086130 + 29c9935 commit 4dddeee

File tree

9 files changed

+214
-92
lines changed

9 files changed

+214
-92
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdbool.h>
2+
#include <stdlib.h>
3+
4+
void main()
5+
{
6+
long x = 0;
7+
long y;
8+
__CPROVER_assume(y > 1);
9+
10+
while(y > 0)
11+
{
12+
x = 1;
13+
y = y - 1;
14+
}
15+
16+
assert(false);
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.assigns.\d+\] .* Check that x is assignable: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that y is assignable: SUCCESS$
9+
^\*\* 1 of \d+ failed
10+
^VERIFICATION FAILED$
11+
--
12+
--
13+
Check whether loop invariant are synthesized when there is ASSERT FALSE.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <stdlib.h>
2+
3+
void main()
4+
{
5+
long x = 0;
6+
long y;
7+
__CPROVER_assume(y > 1);
8+
9+
while(y > 0)
10+
{
11+
x = 1;
12+
y = y - 1;
13+
}
14+
assert(y == 0);
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.assigns.\d+\] .* Check that x is assignable: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that y is assignable: SUCCESS$
9+
^\[main.assertion.\d+\] .* assertion y \=\=
10+
^VERIFICATION SUCCESSFUL$
11+
--
12+
--
13+
Check whether loop invariant are synthesized for checks other than
14+
pointer checks.

src/goto-synthesizer/cegis_verifier.cpp

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ optionalt<cext> cegis_verifiert::verify()
588588
// 3. construct the formatted counterexample from the violated property and
589589
// its trace.
590590

591+
const namespacet ns(goto_model.symbol_table);
592+
591593
// Store the original functions. We will restore them after the verification.
592594
for(const auto &fun_entry : goto_model.goto_functions.function_map)
593595
{
@@ -600,11 +602,11 @@ optionalt<cext> cegis_verifiert::verify()
600602
// Annotate assigns
601603
annotate_assigns(assigns_map, goto_model);
602604

603-
// Control verbosity.
604-
// We allow non-error output message only when verbosity is set to at least 9.
605+
// Control verbosity. We allow non-error output message only when verbosity
606+
// is set to larger than messaget::M_DEBUG.
605607
const unsigned original_verbosity = log.get_message_handler().get_verbosity();
606-
if(original_verbosity < 9)
607-
log.get_message_handler().set_verbosity(1);
608+
if(original_verbosity < messaget::M_DEBUG)
609+
log.get_message_handler().set_verbosity(messaget::M_ERROR);
608610

609611
// Apply loop contracts we annotated.
610612
code_contractst cont(goto_model, log);
@@ -630,7 +632,7 @@ optionalt<cext> cegis_verifiert::verify()
630632
// Run the checker to get the result.
631633
const resultt result = (*checker)();
632634

633-
if(original_verbosity >= 9)
635+
if(original_verbosity >= messaget::M_DEBUG)
634636
checker->report();
635637

636638
// Restore the verbosity.
@@ -652,38 +654,48 @@ optionalt<cext> cegis_verifiert::verify()
652654
}
653655

654656
properties = checker->get_properties();
655-
bool target_violation_found = false;
656-
auto target_violation_info = properties.begin()->second;
657+
auto target_violation = properties.end();
657658

658659
// Find target violation---the violation we want to fix next.
659660
// A target violation is an assignable violation or the first violation that
660661
// is not assignable violation.
661-
for(const auto &property : properties)
662+
for(auto it_property = properties.begin(); it_property != properties.end();
663+
it_property++)
662664
{
663-
if(property.second.status != property_statust::FAIL)
665+
if(it_property->second.status != property_statust::FAIL)
664666
continue;
665667

666668
// assignable violation found
667-
if(property.second.description.find("assignable") != std::string::npos)
669+
if(it_property->second.description.find("assignable") != std::string::npos)
668670
{
669-
target_violation = property.first;
670-
target_violation_info = property.second;
671+
target_violation = it_property;
671672
break;
672673
}
673674

674675
// Store the violation that we want to fix with synthesized
675676
// assigns/invariant.
676-
if(!target_violation_found)
677+
// ignore ASSERT FALSE
678+
if(
679+
target_violation == properties.end() &&
680+
simplify_expr(it_property->second.pc->condition(), ns) != false_exprt())
677681
{
678-
target_violation = property.first;
679-
target_violation_info = property.second;
680-
target_violation_found = true;
682+
target_violation = it_property;
681683
}
682684
}
683685

686+
// All violations are
687+
// ASSERT FALSE
688+
if(target_violation == properties.end())
689+
{
690+
restore_functions();
691+
return optionalt<cext>();
692+
}
693+
694+
target_violation_id = target_violation->first;
695+
684696
// Decide the violation type from the description of violation
685697
cext::violation_typet violation_type =
686-
extract_violation_type(target_violation_info.description);
698+
extract_violation_type(target_violation->second.description);
687699

688700
// Compute the cause loop---the loop for which we synthesize loop contracts,
689701
// and the counterexample.
@@ -698,15 +710,17 @@ optionalt<cext> cegis_verifiert::verify()
698710
// although there can be multiple ones.
699711

700712
log.debug() << "Start to compute cause loop ids." << messaget::eom;
713+
log.debug() << "Violation description: "
714+
<< target_violation->second.description << messaget::eom;
701715

702-
const auto &trace = checker->get_traces()[target_violation];
716+
const auto &trace = checker->get_traces()[target_violation->first];
703717
// Doing assigns-synthesis or invariant-synthesis
704718
if(violation_type == cext::violation_typet::cex_assignable)
705719
{
706720
cext result(violation_type);
707721
result.cause_loop_ids = get_cause_loop_id_for_assigns(trace);
708722
result.checked_pointer = static_cast<const exprt &>(
709-
target_violation_info.pc->condition().find(ID_checked_assigns));
723+
target_violation->second.pc->condition().find(ID_checked_assigns));
710724
restore_functions();
711725
return result;
712726
}
@@ -717,7 +731,7 @@ optionalt<cext> cegis_verifiert::verify()
717731
// Although there can be multiple cause loop ids. We only synthesize
718732
// loop invariants for the first cause loop.
719733
const std::list<loop_idt> cause_loop_ids =
720-
get_cause_loop_id(trace, target_violation_info.pc);
734+
get_cause_loop_id(trace, target_violation->second.pc);
721735

722736
if(cause_loop_ids.empty())
723737
{
@@ -741,7 +755,7 @@ optionalt<cext> cegis_verifiert::verify()
741755
violation_location = get_violation_location(
742756
cause_loop_ids.front(),
743757
goto_model.get_goto_function(cause_loop_ids.front().function_id),
744-
target_violation_info.pc->location_number);
758+
target_violation->second.pc->location_number);
745759
}
746760

747761
restore_functions();
@@ -753,7 +767,7 @@ optionalt<cext> cegis_verifiert::verify()
753767
goto_model.goto_functions
754768
.function_map[cause_loop_ids.front().function_id])
755769
->source_location());
756-
return_cex.violated_predicate = target_violation_info.pc->condition();
770+
return_cex.violated_predicate = target_violation->second.pc->condition();
757771
return_cex.cause_loop_ids = cause_loop_ids;
758772
return_cex.violation_location = violation_location;
759773
return_cex.violation_type = violation_type;
@@ -762,7 +776,7 @@ optionalt<cext> cegis_verifiert::verify()
762776
if(violation_type == cext::violation_typet::cex_null_pointer)
763777
{
764778
return_cex.checked_pointer = get_checked_pointer_from_null_pointer_check(
765-
target_violation_info.pc->condition());
779+
target_violation->second.pc->condition());
766780
}
767781

768782
return return_cex;

src/goto-synthesizer/cegis_verifier.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class cegis_verifiert
117117

118118
/// Result counterexample.
119119
propertiest properties;
120-
irep_idt target_violation;
120+
irep_idt target_violation_id;
121121

122122
protected:
123123
// Get the options same as using CBMC api without any flag, and

src/goto-synthesizer/enumerative_loop_contracts_synthesizer.cpp

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ std::vector<exprt> construct_terminals(const std::set<symbol_exprt> &symbols)
7373
unary_exprt(ID_loop_entry, e, e.type()), size_type()));
7474
}
7575
}
76-
result.push_back(from_integer(1, unsigned_int_type()));
77-
result.push_back(from_integer(1, unsigned_long_int_type()));
76+
result.push_back(from_integer(1, signed_short_int_type()));
77+
result.push_back(from_integer(0, signed_short_int_type()));
7878
return result;
7979
}
8080

@@ -100,13 +100,13 @@ void enumerative_loop_contracts_synthesizert::init_candidates()
100100
// we only synthesize invariants and assigns for unannotated loops
101101
if(loop_end->condition().find(ID_C_spec_loop_invariant).is_nil())
102102
{
103-
// Store the loop guard.
104-
exprt guard =
105-
get_loop_head(
106-
loop_end->loop_number,
107-
goto_model.goto_functions.function_map[function_p.first])
108-
->condition();
109-
neg_guards[new_id] = guard;
103+
// Store the loop guard if exists.
104+
auto loop_head = get_loop_head(
105+
loop_end->loop_number,
106+
goto_model.goto_functions.function_map[function_p.first]);
107+
108+
if(loop_head->has_condition())
109+
neg_guards[new_id] = loop_head->condition();
110110

111111
// Initialize invariant clauses as `true`.
112112
in_invariant_clause_map[new_id] = true_exprt();
@@ -120,6 +120,7 @@ void enumerative_loop_contracts_synthesizert::init_candidates()
120120
}
121121
}
122122
}
123+
log.debug() << "Finished candidates initialization." << messaget::eom;
123124
}
124125

125126
void enumerative_loop_contracts_synthesizert::synthesize_assigns(
@@ -303,12 +304,17 @@ exprt enumerative_loop_contracts_synthesizert::synthesize_strengthening_clause(
303304
// generate candidate and verify
304305
for(auto strengthening_candidate : start_bool_ph.enumerate(size_bound))
305306
{
307+
log.progress() << "Verifying candidate: "
308+
<< format(strengthening_candidate) << messaget::eom;
306309
seen_terms++;
307310
invariant_mapt new_in_clauses = invariant_mapt(in_invariant_clause_map);
308311
new_in_clauses[cause_loop_id] =
309312
and_exprt(new_in_clauses[cause_loop_id], strengthening_candidate);
313+
invariant_mapt new_pos_clauses = invariant_mapt(pos_invariant_clause_map);
314+
new_pos_clauses[cause_loop_id] =
315+
and_exprt(new_pos_clauses[cause_loop_id], strengthening_candidate);
310316
const auto &combined_invariant = combine_in_and_post_invariant_clauses(
311-
new_in_clauses, pos_invariant_clause_map, neg_guards);
317+
new_in_clauses, new_pos_clauses, neg_guards);
312318

313319
// The verifier we use to check current invariant candidates.
314320
cegis_verifiert verifier(
@@ -323,7 +329,9 @@ exprt enumerative_loop_contracts_synthesizert::synthesize_strengthening_clause(
323329
(verifier.properties.at(violation_id).status !=
324330
property_statust::FAIL &&
325331
return_cex->violation_type !=
326-
cext::violation_typet::cex_not_hold_upon_entry))
332+
cext::violation_typet::cex_not_hold_upon_entry &&
333+
return_cex->violation_type !=
334+
cext::violation_typet::cex_not_preserved))
327335
{
328336
return strengthening_candidate;
329337
}
@@ -351,6 +359,7 @@ invariant_mapt enumerative_loop_contracts_synthesizert::synthesize_all()
351359
// Set of symbols we used to enumerate strengthening clauses.
352360
std::vector<exprt> terminal_symbols;
353361

362+
log.debug() << "Start the first synthesis iteration." << messaget::eom;
354363
auto return_cex = verifier.verify();
355364

356365
while(return_cex.has_value())
@@ -370,20 +379,26 @@ invariant_mapt enumerative_loop_contracts_synthesizert::synthesize_all()
370379
synthesize_same_object_predicate(return_cex->checked_pointer);
371380
break;
372381

382+
case cext::violation_typet::cex_assignable:
383+
synthesize_assigns(
384+
return_cex->checked_pointer, return_cex->cause_loop_ids);
385+
break;
386+
387+
case cext::violation_typet::cex_other:
388+
// Update the dependent symbols.
389+
dependent_symbols = compute_dependent_symbols(
390+
return_cex->cause_loop_ids.front(),
391+
new_invariant_clause,
392+
return_cex->live_variables);
373393
case cext::violation_typet::cex_not_preserved:
374394
terminal_symbols = construct_terminals(dependent_symbols);
375395
new_invariant_clause = synthesize_strengthening_clause(
376396
terminal_symbols,
377397
return_cex->cause_loop_ids.front(),
378-
verifier.target_violation);
398+
verifier.target_violation_id);
379399
break;
380400

381-
case cext::violation_typet::cex_assignable:
382-
synthesize_assigns(
383-
return_cex->checked_pointer, return_cex->cause_loop_ids);
384-
break;
385401
case cext::violation_typet::cex_not_hold_upon_entry:
386-
case cext::violation_typet::cex_other:
387402
INVARIANT(false, "unsupported violation type");
388403
break;
389404
}

0 commit comments

Comments
 (0)