@@ -53,6 +53,34 @@ static bool contains_symbol_prefix(const exprt &expr, const std::string &prefix)
53
53
return false ;
54
54
}
55
55
56
+ static const exprt &
57
+ get_checked_pointer_from_null_pointer_check (const exprt &violation)
58
+ {
59
+ // A NULL-pointer check is the negation of an equation between the checked
60
+ // pointer and a NULL pointer.
61
+ // ! (POINTER_OBJECT(NULL) == POINTER_OBJECT(ptr))
62
+ const equal_exprt &equal_expr = to_equal_expr (to_not_expr (violation).op ());
63
+
64
+ const pointer_object_exprt &lhs_pointer_object =
65
+ to_pointer_object_expr (equal_expr.lhs ());
66
+ const pointer_object_exprt &rhs_pointer_object =
67
+ to_pointer_object_expr (equal_expr.rhs ());
68
+
69
+ const exprt &lhs_pointer = lhs_pointer_object.operands ()[0 ];
70
+ const exprt &rhs_pointer = rhs_pointer_object.operands ()[0 ];
71
+
72
+ // NULL == ptr
73
+ if (
74
+ can_cast_expr<constant_exprt>(lhs_pointer) &&
75
+ is_null_pointer (*expr_try_dynamic_cast<constant_exprt>(lhs_pointer)))
76
+ {
77
+ return rhs_pointer;
78
+ }
79
+
80
+ // Not a equation with NULL on one side.
81
+ UNREACHABLE;
82
+ }
83
+
56
84
optionst cegis_verifiert::get_options ()
57
85
{
58
86
optionst options;
@@ -94,6 +122,44 @@ optionst cegis_verifiert::get_options()
94
122
return options;
95
123
}
96
124
125
+ cext::violation_typet
126
+ cegis_verifiert::extract_violation_type (const std::string &description)
127
+ {
128
+ // The violation is a pointer OOB check.
129
+ if ((description.find (
130
+ " dereference failure: pointer outside object bounds in" ) !=
131
+ std::string::npos))
132
+ {
133
+ return cext::violation_typet::cex_out_of_boundary;
134
+ }
135
+
136
+ // The violation is a null pointer check.
137
+ if (description.find (" pointer NULL" ) != std::string::npos)
138
+ {
139
+ return cext::violation_typet::cex_null_pointer;
140
+ }
141
+
142
+ // The violation is a loop-invariant-preservation check.
143
+ if (description.find (" preserved" ) != std::string::npos)
144
+ {
145
+ return cext::violation_typet::cex_not_preserved;
146
+ }
147
+
148
+ // The violation is a loop-invariant-preservation check.
149
+ if (description.find (" invariant before entry" ) != std::string::npos)
150
+ {
151
+ return cext::violation_typet::cex_not_hold_upon_entry;
152
+ }
153
+
154
+ // The violation is an assignable check.
155
+ if (description.find (" assignable" ) != std::string::npos)
156
+ {
157
+ return cext::violation_typet::cex_assignable;
158
+ }
159
+
160
+ return cext::violation_typet::cex_other;
161
+ }
162
+
97
163
std::list<loop_idt>
98
164
cegis_verifiert::get_cause_loop_id_for_assigns (const goto_tracet &goto_trace)
99
165
{
@@ -586,143 +652,118 @@ optionalt<cext> cegis_verifiert::verify()
586
652
}
587
653
588
654
properties = checker->get_properties ();
589
- // Find the violation and construct counterexample from its trace.
590
- for (const auto &property_it : properties)
655
+ bool target_violation_found = false ;
656
+ auto target_violation_info = properties.begin ()->second ;
657
+
658
+ // Find target violation---the violation we want to fix next.
659
+ // A target violation is an assignable violation or the first violation that
660
+ // is not assignable violation.
661
+ for (const auto &property : properties)
591
662
{
592
- if (property_it .second .status != property_statust::FAIL)
663
+ if (property .second .status != property_statust::FAIL)
593
664
continue ;
594
665
595
- // Store the violation that we want to fix with synthesized
596
- // assigns/invariant.
597
- first_violation = property_it.first ;
598
-
599
- // Type of the violation
600
- cext::violation_typet violation_type = cext::violation_typet::cex_other;
601
-
602
- // Decide the violation type from the description of violation
603
-
604
- // The violation is a pointer OOB check.
605
- if ((property_it.second .description .find (
606
- " dereference failure: pointer outside object bounds in" ) !=
607
- std::string::npos))
608
- {
609
- violation_type = cext::violation_typet::cex_out_of_boundary;
610
- }
611
-
612
- // The violation is a null pointer check.
613
- if (property_it.second .description .find (" pointer NULL" ) != std::string::npos)
666
+ // assignable violation found
667
+ if (property.second .description .find (" assignable" ) != std::string::npos)
614
668
{
615
- violation_type = cext::violation_typet::cex_null_pointer;
616
- }
617
-
618
- // The violation is a loop-invariant-preservation check.
619
- if (property_it.second .description .find (" preserved" ) != std::string::npos)
620
- {
621
- violation_type = cext::violation_typet::cex_not_preserved;
622
- }
623
-
624
- // The violation is a loop-invariant-preservation check.
625
- if (
626
- property_it.second .description .find (" invariant before entry" ) !=
627
- std::string::npos)
628
- {
629
- violation_type = cext::violation_typet::cex_not_hold_upon_entry;
669
+ target_violation = property.first ;
670
+ target_violation_info = property.second ;
671
+ break ;
630
672
}
631
673
632
- // The violation is an assignable check.
633
- if (property_it.second .description .find (" assignable" ) != std::string::npos)
674
+ // Store the violation that we want to fix with synthesized
675
+ // assigns/invariant.
676
+ if (!target_violation_found)
634
677
{
635
- violation_type = cext::violation_typet::cex_assignable;
678
+ target_violation = property.first ;
679
+ target_violation_info = property.second ;
680
+ target_violation_found = true ;
636
681
}
682
+ }
637
683
638
- // Compute the cause loop---the loop for which we synthesize loop contracts,
639
- // and the counterexample.
640
-
641
- // If the violation is an assignable check, we synthesize assigns targets.
642
- // In the case, cause loops are all loops the violation is in. We keep
643
- // adding the new assigns target to the most-inner loop that does not
644
- // contain the new target until the assignable violation is resolved.
645
-
646
- // For other cases, we synthesize loop invariant clauses. We synthesize
647
- // invariants for one loop at a time. So we return only the first cause loop
648
- // although there can be multiple ones.
684
+ // Decide the violation type from the description of violation
685
+ cext::violation_typet violation_type =
686
+ extract_violation_type (target_violation_info.description );
649
687
650
- log .debug () << " Start to compute cause loop ids." << messaget::eom;
688
+ // Compute the cause loop---the loop for which we synthesize loop contracts,
689
+ // and the counterexample.
651
690
652
- const auto &trace = checker->get_traces ()[property_it.first ];
691
+ // If the violation is an assignable check, we synthesize assigns targets.
692
+ // In the case, cause loops are all loops the violation is in. We keep
693
+ // adding the new assigns target to the most-inner loop that does not
694
+ // contain the new target until the assignable violation is resolved.
653
695
654
- // Doing assigns-synthesis or invariant-synthesis
655
- if (violation_type == cext::violation_typet::cex_assignable)
656
- {
657
- cext result (violation_type);
658
- result.cause_loop_ids = get_cause_loop_id_for_assigns (trace);
659
- result.checked_pointer = static_cast <const exprt &>(
660
- property_it.second .pc ->condition ().find (ID_checked_assigns));
661
- restore_functions ();
662
- return result;
663
- }
696
+ // For other cases, we synthesize loop invariant clauses. We synthesize
697
+ // invariants for one loop at a time. So we return only the first cause loop
698
+ // although there can be multiple ones.
664
699
665
- // We construct the full counterexample only for violations other than
666
- // assignable checks.
700
+ log .debug () << " Start to compute cause loop ids." << messaget::eom;
667
701
668
- // Although there can be multiple cause loop ids. We only synthesize
669
- // loop invariants for the first cause loop.
670
- const std::list<loop_idt> cause_loop_ids =
671
- get_cause_loop_id (trace, property_it.second .pc );
702
+ const auto &trace = checker->get_traces ()[target_violation];
703
+ // Doing assigns-synthesis or invariant-synthesis
704
+ if (violation_type == cext::violation_typet::cex_assignable)
705
+ {
706
+ cext result (violation_type);
707
+ result.cause_loop_ids = get_cause_loop_id_for_assigns (trace);
708
+ result.checked_pointer = static_cast <const exprt &>(
709
+ target_violation_info.pc ->condition ().find (ID_checked_assigns));
710
+ restore_functions ();
711
+ return result;
712
+ }
672
713
673
- if (cause_loop_ids.empty ())
674
- {
675
- log .debug () << " No cause loop found!" << messaget::eom;
676
- restore_functions ();
714
+ // We construct the full counterexample only for violations other than
715
+ // assignable checks.
677
716
678
- return cext (violation_type);
679
- }
717
+ // Although there can be multiple cause loop ids. We only synthesize
718
+ // loop invariants for the first cause loop.
719
+ const std::list<loop_idt> cause_loop_ids =
720
+ get_cause_loop_id (trace, target_violation_info.pc );
680
721
681
- log . debug () << " Found cause loop with function id: "
682
- << cause_loop_ids. front (). function_id
683
- << " , and loop number: " << cause_loop_ids. front (). loop_number
684
- << messaget::eom ;
722
+ if (cause_loop_ids. empty ())
723
+ {
724
+ log . debug () << " No cause loop found! " << messaget::eom;
725
+ restore_functions () ;
685
726
686
- auto violation_location = cext::violation_locationt::in_loop;
687
- // We always strengthen in_clause if the violation is
688
- // invariant-not-preserved.
689
- if (violation_type != cext::violation_typet::cex_not_preserved)
690
- {
691
- // Get the location of the violation
692
- violation_location = get_violation_location (
693
- cause_loop_ids.front (),
694
- goto_model.get_goto_function (cause_loop_ids.front ().function_id ),
695
- property_it.second .pc ->location_number );
696
- }
727
+ return cext (violation_type);
728
+ }
697
729
698
- restore_functions ();
730
+ log .debug () << " Found cause loop with function id: "
731
+ << cause_loop_ids.front ().function_id
732
+ << " , and loop number: " << cause_loop_ids.front ().loop_number
733
+ << messaget::eom;
699
734
700
- auto return_cex = build_cex (
701
- trace,
702
- get_loop_head (
703
- cause_loop_ids.front ().loop_number ,
704
- goto_model.goto_functions
705
- .function_map [cause_loop_ids.front ().function_id ])
706
- ->source_location ());
707
- return_cex.violated_predicate = property_it.second .pc ->condition ();
708
- return_cex.cause_loop_ids = cause_loop_ids;
709
- return_cex.violation_location = violation_location;
710
- return_cex.violation_type = violation_type;
711
-
712
- // The pointer checked in the null-pointer-check violation.
713
- if (violation_type == cext::violation_typet::cex_null_pointer)
714
- {
715
- return_cex.checked_pointer = property_it.second .pc ->condition ()
716
- .operands ()[0 ]
717
- .operands ()[1 ]
718
- .operands ()[0 ];
719
- INVARIANT (
720
- return_cex.checked_pointer .id () == ID_symbol,
721
- " Checking pointer symbol" );
722
- }
735
+ auto violation_location = cext::violation_locationt::in_loop;
736
+ // We always strengthen in_clause if the violation is
737
+ // invariant-not-preserved.
738
+ if (violation_type != cext::violation_typet::cex_not_preserved)
739
+ {
740
+ // Get the location of the violation
741
+ violation_location = get_violation_location (
742
+ cause_loop_ids.front (),
743
+ goto_model.get_goto_function (cause_loop_ids.front ().function_id ),
744
+ target_violation_info.pc ->location_number );
745
+ }
723
746
724
- return return_cex;
747
+ restore_functions ();
748
+
749
+ auto return_cex = build_cex (
750
+ trace,
751
+ get_loop_head (
752
+ cause_loop_ids.front ().loop_number ,
753
+ goto_model.goto_functions
754
+ .function_map [cause_loop_ids.front ().function_id ])
755
+ ->source_location ());
756
+ return_cex.violated_predicate = target_violation_info.pc ->condition ();
757
+ return_cex.cause_loop_ids = cause_loop_ids;
758
+ return_cex.violation_location = violation_location;
759
+ return_cex.violation_type = violation_type;
760
+
761
+ // The pointer checked in the null-pointer-check violation.
762
+ if (violation_type == cext::violation_typet::cex_null_pointer)
763
+ {
764
+ return_cex.checked_pointer = get_checked_pointer_from_null_pointer_check (
765
+ target_violation_info.pc ->condition ());
725
766
}
726
767
727
- UNREACHABLE ;
768
+ return return_cex ;
728
769
}
0 commit comments