@@ -32,6 +32,7 @@ Author: Qinheping Hu
32
32
#include < goto-checker/all_properties_verifier_with_trace_storage.h>
33
33
#include < goto-checker/multi_path_symex_checker.h>
34
34
#include < goto-instrument/contracts/contracts.h>
35
+ #include < goto-instrument/contracts/instrument_spec_assigns.h>
35
36
#include < goto-instrument/contracts/utils.h>
36
37
#include < goto-instrument/havoc_utils.h>
37
38
#include < langapi/language_util.h>
@@ -93,11 +94,45 @@ optionst cegis_verifiert::get_options()
93
94
return options;
94
95
}
95
96
96
- optionalt<loop_idt> cegis_verifiert::get_cause_loop_id (
97
+ std::list<loop_idt>
98
+ cegis_verifiert::get_cause_loop_id_for_assigns (const goto_tracet &goto_trace)
99
+ {
100
+ std::list<loop_idt> result;
101
+
102
+ // We say a loop is the cause loop of an assignable-violation if the inclusion
103
+ // check is in the loop.
104
+
105
+ // So we check what loops the last step of the trace is in.
106
+ // Transformed loop head:
107
+ // ASSIGN entered_loop = false
108
+ // Transformed loop end:
109
+ // ASSIGN entered_loop = true
110
+ for (const auto &step : goto_trace.steps )
111
+ {
112
+ if (is_transformed_loop_head (step.pc ))
113
+ {
114
+ result.push_front (
115
+ loop_idt (step.function_id , original_loop_number_map[step.pc ]));
116
+ continue ;
117
+ }
118
+
119
+ if (is_transformed_loop_end (step.pc ))
120
+ {
121
+ const loop_idt loop_id (
122
+ step.function_id , original_loop_number_map[step.pc ]);
123
+ INVARIANT (result.front () == loop_id, " Leaving a loop we havn't entered." );
124
+ result.pop_front ();
125
+ }
126
+ }
127
+ INVARIANT (!result.empty (), " The assignable violation is not in a loop." );
128
+ return result;
129
+ }
130
+
131
+ std::list<loop_idt> cegis_verifiert::get_cause_loop_id (
97
132
const goto_tracet &goto_trace,
98
133
const goto_programt::const_targett violation)
99
134
{
100
- optionalt <loop_idt> result;
135
+ std::list <loop_idt> result;
101
136
102
137
// build the dependence graph
103
138
const namespacet ns (goto_model.symbol_table );
@@ -165,7 +200,8 @@ optionalt<loop_idt> cegis_verifiert::get_cause_loop_id(
165
200
// if it is dependent on the loop havoc.
166
201
if (reachable_set.count (dependence_graph[from].get_node_id ()))
167
202
{
168
- result = loop_idt (step.function_id , original_loop_number_map[step.pc ]);
203
+ result.push_back (
204
+ loop_idt (step.function_id , original_loop_number_map[step.pc ]));
169
205
return result;
170
206
}
171
207
}
@@ -434,9 +470,12 @@ optionalt<cext> cegis_verifiert::verify()
434
470
original_functions[fun_entry.first ].copy_from (fun_entry.second .body );
435
471
}
436
472
437
- // Annotate the candidates tot the goto_model for checking.
473
+ // Annotate the candidates to the goto_model for checking.
438
474
annotate_invariants (invariant_candidates, goto_model);
439
475
476
+ // Annotate assigns
477
+ annotate_assigns (assigns_map, goto_model);
478
+
440
479
// Control verbosity.
441
480
// We allow non-error output message only when verbosity is set to at least 9.
442
481
const unsigned original_verbosity = log .get_message_handler ().get_verbosity ();
@@ -496,14 +535,18 @@ optionalt<cext> cegis_verifiert::verify()
496
535
continue ;
497
536
498
537
first_violation = property_it.first ;
499
- exprt violated_predicate = property_it.second .pc ->condition ();
538
+ const auto &trace = checker->get_traces ()[property_it.first ];
539
+ const exprt &violated_predicate = property_it.second .pc ->condition ();
500
540
501
- // The pointer checked in the null-pointer-check violation.
541
+ // The pointer checked in the null-pointer-check violation and assignable
542
+ // violation.
502
543
exprt checked_pointer = true_exprt ();
503
544
504
545
// Type of the violation
505
546
cext::violation_typet violation_type = cext::violation_typet::cex_other;
506
547
548
+ // Decide the violation type from the description of violation
549
+
507
550
// The violation is a pointer OOB check.
508
551
if ((property_it.second .description .find (
509
552
" dereference failure: pointer outside object bounds in" ) !=
@@ -537,49 +580,89 @@ optionalt<cext> cegis_verifiert::verify()
537
580
violation_type = cext::violation_typet::cex_not_hold_upon_entry;
538
581
}
539
582
583
+ // The violation is an assignable check.
584
+ if (property_it.second .description .find (" assignable" ) != std::string::npos)
585
+ {
586
+ violation_type = cext::violation_typet::cex_assignable;
587
+ }
588
+
589
+ // Compute the cause loop---the loop for which we synthesize loop contracts,
590
+ // and the counterexample.
591
+
592
+ // If the violation is an assignable check, we synthesize assigns targets.
593
+ // In the case, cause loops are all loops the violation is in. We keep
594
+ // adding the new assigns target to the most-inner loop that does not
595
+ // contain the new target until the assignable violation is resolved.
596
+
597
+ // For other cases, we synthesize loop invariant clauses. We synthesize
598
+ // invariants for one loop at a time. So we return only the first cause loop
599
+ // although there can be multiple ones.
600
+
601
+ log .debug () << " Start to compute cause loop ids." << messaget::eom;
602
+
540
603
// The loop which could be the cause of the violation.
541
- // We say a loop is the cause loop if the violated predicate is dependent
542
- // upon the write set of the loop.
543
- optionalt<loop_idt> cause_loop_id = get_cause_loop_id (
544
- checker->get_traces ()[property_it.first ], property_it.second .pc );
604
+ std::list<loop_idt> cause_loop_ids;
605
+ // Decide whether the violation is in the cause loop.
606
+ bool is_violation_in_loop;
607
+
608
+ // Doing assigns-synthesis or invariant-synthesis
609
+ if (violation_type == cext::violation_typet::cex_assignable)
610
+ {
611
+ is_violation_in_loop = true ;
612
+
613
+ checked_pointer = static_cast <const exprt &>(
614
+ property_it.second .pc ->condition ().find (ID_checked_assigns));
615
+ cause_loop_ids = get_cause_loop_id_for_assigns (trace);
616
+ cext result (violation_type);
617
+ result.cause_loop_ids = cause_loop_ids;
618
+ result.checked_pointer = checked_pointer;
619
+ restore_functions ();
620
+ return result;
621
+ }
622
+
623
+ // We construct the full counterexample only for violations other than
624
+ // assignable checks.
545
625
546
- if (!cause_loop_id.has_value ())
626
+ // Although there can be multiple cause loop ids. We only synthesize
627
+ // loop invariants for the first cause loop.
628
+ cause_loop_ids = get_cause_loop_id (trace, property_it.second .pc );
629
+
630
+ if (cause_loop_ids.empty ())
547
631
{
548
- log .debug () << " No cause loop found!\n " ;
632
+ log .debug () << " No cause loop found!" << messaget::eom ;
549
633
restore_functions ();
550
634
551
635
return cext (violation_type);
552
636
}
553
637
554
- log .debug () << " Found cause loop with function id: "
555
- << cause_loop_id.value ().function_id
556
- << " , and loop number: " << cause_loop_id.value ().loop_number
557
- << " \n " ;
558
-
559
- // Decide whether the violation is in the cause loop.
560
- bool violation_in_loop = is_instruction_in_transfomed_loop (
561
- cause_loop_id.value (),
562
- goto_model.get_goto_function (cause_loop_id.value ().function_id ),
638
+ is_violation_in_loop = is_instruction_in_transfomed_loop (
639
+ cause_loop_ids.front (),
640
+ goto_model.get_goto_function (cause_loop_ids.front ().function_id ),
563
641
property_it.second .pc ->location_number );
564
642
643
+ log .debug () << " Found cause loop with function id: "
644
+ << cause_loop_ids.front ().function_id
645
+ << " , and loop number: " << cause_loop_ids.front ().loop_number
646
+ << messaget::eom;
647
+
565
648
// We always strengthen in_clause if the violation is
566
649
// invariant-not-preserved.
567
650
if (violation_type == cext::violation_typet::cex_not_preserved)
568
- violation_in_loop = true ;
651
+ is_violation_in_loop = true ;
569
652
570
653
restore_functions ();
571
654
572
655
auto return_cex = build_cex (
573
- checker-> get_traces ()[property_it. first ] ,
656
+ trace ,
574
657
get_loop_head (
575
- cause_loop_id. value ().loop_number ,
658
+ cause_loop_ids. front ().loop_number ,
576
659
goto_model.goto_functions
577
- .function_map [cause_loop_id. value ().function_id ])
660
+ .function_map [cause_loop_ids. front ().function_id ])
578
661
->source_location ());
579
662
return_cex.violated_predicate = violated_predicate;
580
- return_cex.cause_loop_id = cause_loop_id ;
663
+ return_cex.cause_loop_ids = cause_loop_ids ;
581
664
return_cex.checked_pointer = checked_pointer;
582
- return_cex.is_violation_in_loop = violation_in_loop ;
665
+ return_cex.is_violation_in_loop = is_violation_in_loop ;
583
666
return_cex.violation_type = violation_type;
584
667
585
668
return return_cex;
0 commit comments