@@ -888,18 +888,24 @@ void code_contractst::apply_loop_contract(
888888
889889 std::list<size_t > to_check_contracts_on_children;
890890
891+ std::map<
892+ goto_programt::targett,
893+ std::pair<goto_programt::targett, natural_loops_mutablet::loopt>,
894+ goto_programt::target_less_than>
895+ loop_head_ends;
896+
891897 for (const auto &loop_head_and_content : natural_loops.loop_map)
892898 {
893- const auto &loop_content = loop_head_and_content.second ;
899+ const auto &loop_body = loop_head_and_content.second ;
894900 // Skip empty loops and self-looped node.
895- if (loop_content .size () <= 1 )
901+ if (loop_body .size () <= 1 )
896902 continue ;
897903
898904 auto loop_head = loop_head_and_content.first ;
899905 auto loop_end = loop_head;
900906
901907 // Find the last back edge to `loop_head`
902- for (const auto &t : loop_content )
908+ for (const auto &t : loop_body )
903909 {
904910 if (
905911 t->is_goto () && t->get_target () == loop_head &&
@@ -914,6 +920,41 @@ void code_contractst::apply_loop_contract(
914920 throw 0 ;
915921 }
916922
923+ // By definition the `loop_body` is a set of instructions computed
924+ // by `natural_loops` based on the CFG.
925+ // Since we perform assigns clause instrumentation by sequentially
926+ // traversing instructions from `loop_head` to `loop_end`,
927+ // here we ensure that all instructions in `loop_body` belong within
928+ // the [loop_head, loop_end] target range.
929+
930+ // Check 1. (i \in loop_body) ==> loop_head <= i <= loop_end
931+ for (const auto &i : loop_body)
932+ {
933+ if (
934+ loop_head->location_number > i->location_number ||
935+ i->location_number > loop_end->location_number )
936+ {
937+ log.conditional_output (
938+ log.error (), [&i, &loop_head](messaget::mstreamt &mstream) {
939+ mstream << " Computed loop at " << loop_head->source_location ()
940+ << " contains an instruction beyond [loop_head, loop_end]:"
941+ << messaget::eom;
942+ i->output (mstream);
943+ mstream << messaget::eom;
944+ });
945+ throw 0 ;
946+ }
947+ }
948+
949+ if (!loop_head_ends.emplace (loop_head, std::make_pair (loop_end, loop_body))
950+ .second )
951+ UNREACHABLE;
952+ }
953+
954+ for (auto &loop_head_end : loop_head_ends)
955+ {
956+ auto loop_head = loop_head_end.first ;
957+ auto loop_end = loop_head_end.second .first ;
917958 // After loop-contract instrumentation, jumps to the `loop_head` will skip
918959 // some instrumented instructions. So we want to make sure that there is
919960 // only one jump targeting `loop_head` from `loop_end` before loop-contract
@@ -961,7 +1002,7 @@ void code_contractst::apply_loop_contract(
9611002 }
9621003
9631004 const auto idx = loop_nesting_graph.add_node (
964- loop_content ,
1005+ loop_head_end. second . second ,
9651006 loop_head,
9661007 loop_end,
9671008 assigns_clause,
@@ -974,30 +1015,6 @@ void code_contractst::apply_loop_contract(
9741015 continue ;
9751016
9761017 to_check_contracts_on_children.push_back (idx);
977-
978- // By definition the `loop_content` is a set of instructions computed
979- // by `natural_loops` based on the CFG.
980- // Since we perform assigns clause instrumentation by sequentially
981- // traversing instructions from `loop_head` to `loop_end`,
982- // here we ensure that all instructions in `loop_content` belong within
983- // the [loop_head, loop_end] target range
984-
985- // Check 1. (i \in loop_content) ==> loop_head <= i <= loop_end
986- for (const auto &i : loop_content)
987- {
988- if (std::distance (loop_head, i) < 0 || std::distance (i, loop_end) < 0 )
989- {
990- log.conditional_output (
991- log.error (), [&i, &loop_head](messaget::mstreamt &mstream) {
992- mstream << " Computed loop at " << loop_head->source_location ()
993- << " contains an instruction beyond [loop_head, loop_end]:"
994- << messaget::eom;
995- i->output (mstream);
996- mstream << messaget::eom;
997- });
998- throw 0 ;
999- }
1000- }
10011018 }
10021019
10031020 for (size_t outer = 0 ; outer < loop_nesting_graph.size(); ++outer)
0 commit comments