@@ -110,27 +110,49 @@ bool symex_bmct::get_unwind(
110110{
111111 const irep_idt id=goto_programt::loop_id (*source.pc );
112112
113- // We use the most specific limit we have,
114- // and 'infinity' when we have none.
115-
113+ tvt abort_unwind_decision;
116114 unsigned this_loop_limit=std::numeric_limits<unsigned >::max ();
117115
118- loop_limitst &this_thread_limits=
119- thread_loop_limits[source.thread_nr ];
116+ for (auto handler : loop_unwind_handlers)
117+ {
118+ abort_unwind_decision =
119+ handler (
120+ source.pc ->function ,
121+ source.pc ->loop_number ,
122+ unwind,
123+ this_loop_limit);
124+ if (abort_unwind_decision.is_known ())
125+ break ;
126+ }
120127
121- loop_limitst::const_iterator l_it=this_thread_limits.find (id);
122- if (l_it!=this_thread_limits.end ())
123- this_loop_limit=l_it->second ;
124- else
128+ // If no handler gave an opinion, use standard command-line --unwindset
129+ // / --unwind options to decide:
130+ if (abort_unwind_decision.is_unknown ())
125131 {
126- l_it=loop_limits.find (id);
127- if (l_it!=loop_limits.end ())
132+ // We use the most specific limit we have,
133+ // and 'infinity' when we have none.
134+
135+ loop_limitst &this_thread_limits=
136+ thread_loop_limits[source.thread_nr ];
137+
138+ loop_limitst::const_iterator l_it=this_thread_limits.find (id);
139+ if (l_it!=this_thread_limits.end ())
128140 this_loop_limit=l_it->second ;
129- else if (max_unwind_is_set)
130- this_loop_limit=max_unwind;
141+ else
142+ {
143+ l_it=loop_limits.find (id);
144+ if (l_it!=loop_limits.end ())
145+ this_loop_limit=l_it->second ;
146+ else if (max_unwind_is_set)
147+ this_loop_limit=max_unwind;
148+ }
149+
150+ abort_unwind_decision = tvt (unwind >= this_loop_limit);
131151 }
132152
133- bool abort=unwind>=this_loop_limit;
153+ INVARIANT (
154+ abort_unwind_decision.is_known (), " unwind decision should be taken by now" );
155+ bool abort = abort_unwind_decision.is_true ();
134156
135157 log.statistics () << (abort ? " Not unwinding" : " Unwinding" ) << " loop " << id
136158 << " iteration " << unwind;
@@ -149,27 +171,44 @@ bool symex_bmct::get_unwind_recursion(
149171 const unsigned thread_nr,
150172 unsigned unwind)
151173{
152- // We use the most specific limit we have,
153- // and 'infinity' when we have none.
154-
174+ tvt abort_unwind_decision;
155175 unsigned this_loop_limit=std::numeric_limits<unsigned >::max ();
156176
157- loop_limitst &this_thread_limits=
158- thread_loop_limits[thread_nr];
177+ for (auto handler : recursion_unwind_handlers)
178+ {
179+ abort_unwind_decision = handler (id, unwind, this_loop_limit);
180+ if (abort_unwind_decision.is_known ())
181+ break ;
182+ }
159183
160- loop_limitst::const_iterator l_it=this_thread_limits.find (id);
161- if (l_it!=this_thread_limits.end ())
162- this_loop_limit=l_it->second ;
163- else
184+ // If no handler gave an opinion, use standard command-line --unwindset
185+ // / --unwind options to decide:
186+ if (abort_unwind_decision.is_unknown ())
164187 {
165- l_it=loop_limits.find (id);
166- if (l_it!=loop_limits.end ())
188+ // We use the most specific limit we have,
189+ // and 'infinity' when we have none.
190+
191+ loop_limitst &this_thread_limits=
192+ thread_loop_limits[thread_nr];
193+
194+ loop_limitst::const_iterator l_it=this_thread_limits.find (id);
195+ if (l_it!=this_thread_limits.end ())
167196 this_loop_limit=l_it->second ;
168- else if (max_unwind_is_set)
169- this_loop_limit=max_unwind;
197+ else
198+ {
199+ l_it=loop_limits.find (id);
200+ if (l_it!=loop_limits.end ())
201+ this_loop_limit=l_it->second ;
202+ else if (max_unwind_is_set)
203+ this_loop_limit=max_unwind;
204+ }
205+
206+ abort_unwind_decision = tvt (unwind>this_loop_limit);
170207 }
171208
172- bool abort=unwind>this_loop_limit;
209+ INVARIANT (
210+ abort_unwind_decision.is_known (), " unwind decision should be taken by now" );
211+ bool abort = abort_unwind_decision.is_true ();
173212
174213 if (unwind>0 || abort)
175214 {
0 commit comments