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