@@ -13,15 +13,17 @@ Author: CBMC Contributors
1313
1414#include " periodic_incremental_symex_checker.h"
1515
16+ #include < util/std_expr.h>
1617#include < util/ui_message.h>
1718
1819#include < goto-symex/slice.h>
20+ #include < solvers/prop/prop_conv_solver.h>
1921
2022#include " bmc_util.h"
23+ #include " counterexample_beautification.h"
2124#include " solver_factory.h"
25+
2226#include < sstream>
23- #include < solvers/prop/prop_conv_solver.h>
24- #include " counterexample_beautification.h"
2527
2628// --- symex_bmc_periodic_stept implementation ---
2729
@@ -119,6 +121,7 @@ periodic_incremental_symex_checkert::periodic_incremental_symex_checkert(
119121 unwindset,
120122 static_cast<unsigned>(
121123 options.get_signed_int_option(" incremental-check-interval" ))),
124+ speculative_checking_enabled(options.get_bool_option(" speculative-check" )),
122125 property_decider(options, ui_message_handler, equation, ns)
123126{
124127 unwindset.parse_unwind (options.get_option (" unwind" ));
@@ -147,7 +150,6 @@ periodic_incremental_symex_checkert::operator()(propertiest &properties)
147150 full_equation_generated = !symex.from_entry_point_of (
148151 goto_symext::get_goto_function (goto_model), symex_symbol_table);
149152
150- // This might add new properties such as unwinding assertions.
151153 update_properties_status_from_symex_target_equation (
152154 properties, result.updated_properties , equation);
153155
@@ -181,8 +183,7 @@ periodic_incremental_symex_checkert::operator()(propertiest &properties)
181183 ++solver_calls;
182184 log.status ()
183185 << " Periodic check #" << solver_calls << " : running "
184- << property_decider.get_decision_procedure ()
185- .decision_procedure_text ()
186+ << property_decider.get_decision_procedure ().decision_procedure_text ()
186187 << messaget::eom;
187188
188189 decision_proceduret::resultt dec_result = property_decider.solve ();
@@ -193,8 +194,8 @@ periodic_incremental_symex_checkert::operator()(propertiest &properties)
193194 const auto solver_stop = std::chrono::steady_clock::now ();
194195 solver_runtime +=
195196 std::chrono::duration<double >(solver_stop - solver_start);
196- log.status () << " Runtime decision procedure: "
197- << solver_runtime. count () << " s" << messaget::eom;
197+ log.status () << " Runtime decision procedure: " << solver_runtime. count ()
198+ << " s" << messaget::eom;
198199
199200 result.progress =
200201 dec_result == decision_proceduret::resultt::D_SATISFIABLE
@@ -206,74 +207,80 @@ periodic_incremental_symex_checkert::operator()(propertiest &properties)
206207
207208 property_decider.pop_incremental_assumptions ();
208209 }
209- else
210+ else if (speculative_checking_enabled)
210211 {
211- // Partial equation: launch speculative check in a thread .
212- // Save equation state before the speculative check modifies it.
213- saved_step_state. clear ();
214- saved_step_state. reserve ( equation.SSA_steps . size () );
215- for ( const auto &step : equation. SSA_steps )
216- saved_step_state. push_back (
217- {step. converted , step. cond_handle , step. guard_handle }) ;
212+ // Speculative cone-of-influence check on partial equation .
213+ // Only check the most recently discovered assertion to
214+ // minimize overhead.
215+ const std:: size_t current_assertions = equation.count_assertions ( );
216+ if (current_assertions > last_speculative_assertion_count )
217+ {
218+ last_speculative_assertion_count = current_assertions ;
218219
219- ++solver_calls;
220- log.status () << " Speculative check #" << solver_calls
221- << " on partial equation (" << equation.SSA_steps .size ()
222- << " steps)" << messaget::eom;
223-
224- speculative_sat = false ;
225- // Snapshot the current equation size. The speculative thread
226- // will only process steps up to this point. Symex may append
227- // new steps concurrently, but the thread won't see them.
228- const std::size_t snapshot_size = equation.SSA_steps .size ();
229- speculative_thread = std::make_unique<std::thread>(
230- [this , snapshot_size]()
231- {
232- std::ostringstream spec_log_stream;
233- stream_message_handlert spec_mh (spec_log_stream);
234- spec_mh.set_verbosity (
235- ui_message_handler.get_verbosity ());
236-
237- solver_factoryt solvers (
238- options, ns, spec_mh, false );
239- auto spec_solver = solvers.get_solver ();
240- auto &spec_dp = spec_solver->decision_procedure ();
241-
242- auto *prop_conv =
243- dynamic_cast <prop_conv_solvert *>(&spec_dp);
244- if (prop_conv)
245- prop_conv->set_all_frozen ();
246-
247- // Only convert the snapshot (existing steps).
248- // New steps appended by symex are not touched.
249- std::size_t count = 0 ;
250- for (auto &step : equation.SSA_steps )
220+ ++solver_calls;
221+ log.status () << " Speculative check #" << solver_calls
222+ << " on partial equation (" << equation.SSA_steps .size ()
223+ << " steps)" << messaget::eom;
224+
225+ speculative_sat = false ;
226+ const std::size_t snapshot_size = equation.SSA_steps .size ();
227+ speculative_thread = std::make_unique<std::thread>(
228+ [this , snapshot_size]()
251229 {
252- if (count >= snapshot_size)
253- break ;
254- if (!step.ignore )
230+ std::ostringstream spec_log_stream;
231+ stream_message_handlert spec_mh (spec_log_stream);
232+ spec_mh.set_verbosity (ui_message_handler.get_verbosity ());
233+
234+ // Find the last assertion in the snapshot.
235+ symex_target_equationt::SSA_stepst::const_iterator last_assert;
236+ bool found = false ;
237+ std::size_t count = 0 ;
238+ for (auto it = equation.SSA_steps .begin ();
239+ it != equation.SSA_steps .end () && count < snapshot_size;
240+ ++it, ++count)
241+ {
242+ if (it->is_assert () && !it->ignore )
243+ {
244+ last_assert = it;
245+ found = true ;
246+ }
247+ }
248+
249+ if (!found)
250+ {
251+ speculative_log_output = spec_log_stream.str ();
252+ return ;
253+ }
254+
255+ auto cone = cone_of_influence (
256+ equation.SSA_steps , last_assert, snapshot_size);
257+
258+ solver_factoryt solvers (options, ns, spec_mh, false );
259+ auto spec_solver = solvers.get_solver ();
260+ auto &dp = spec_solver->decision_procedure ();
261+
262+ for (const auto *step : cone)
255263 {
256- step.guard_handle = spec_dp.handle (step.guard );
257- if (step.is_assume ())
258- step.cond_handle = spec_dp.handle (step.cond_expr );
259- else if (step.is_assignment () || step.is_constraint ())
260- spec_dp.set_to_true (step.cond_expr );
261- else if (step.is_assert ())
264+ if (step->is_assignment () || step->is_constraint ())
265+ dp.set_to_true (step->cond_expr );
266+ else if (step->is_assume ())
267+ {
268+ exprt g = dp.handle (step->guard );
269+ dp.set_to_true (implies_exprt (g, step->cond_expr ));
270+ }
271+ else if (step->is_assert ())
262272 {
263- step. cond_handle = spec_dp .handle (step. cond_expr );
264- spec_dp. set_to_false ( step. cond_expr );
273+ exprt g = dp .handle (step-> guard );
274+ dp. set_to_true ( implies_exprt (g, not_exprt ( step-> cond_expr )) );
265275 }
266276 }
267- ++count;
268- }
269277
270- auto r = spec_solver->decision_procedure ()();
271- speculative_sat =
272- (r == decision_proceduret::resultt::D_SATISFIABLE);
278+ if (dp () == decision_proceduret::resultt::D_SATISFIABLE)
279+ speculative_sat = true ;
273280
274- speculative_log_output = spec_log_stream.str ();
275- });
276- // Symex continues immediately — speculative thread runs concurrently.
281+ speculative_log_output = spec_log_stream.str ();
282+ });
283+ }
277284 }
278285 }
279286
@@ -288,56 +295,44 @@ periodic_incremental_symex_checkert::operator()(propertiest &properties)
288295 break ;
289296 }
290297
291- // We continue symbolic execution
298+ // Resume symbolic execution
292299 if (!full_equation_generated)
293300 {
294- // Give symex a fresh merge_irep so new steps don't share
295- // the hash table with existing steps. This allows the
296- // speculative thread to safely read existing steps' ireps
297- // while symex appends new ones.
298- merge_irept saved_merge_irep =
299- equation.swap_merge_irep (merge_irept{});
300-
301- // Resume symex concurrently with the speculative thread.
302- full_equation_generated =
303- !symex.resume (goto_symext::get_goto_function (goto_model));
304-
305- // Join speculative thread after symex pauses.
306- if (speculative_thread)
301+ if (speculative_checking_enabled)
307302 {
308- speculative_thread->join ();
309- speculative_thread.reset ();
303+ // Swap merge_irep so speculative thread can safely read
304+ // existing steps while symex appends new ones.
305+ merge_irept saved = equation.swap_merge_irep (merge_irept{});
310306
311- auto sit = saved_step_state.begin ();
312- for (auto &step : equation.SSA_steps )
313- {
314- if (sit == saved_step_state.end ())
315- break ;
316- step.converted = sit->converted ;
317- step.cond_handle = sit->cond_handle ;
318- step.guard_handle = sit->guard_handle ;
319- ++sit;
320- }
307+ full_equation_generated =
308+ !symex.resume (goto_symext::get_goto_function (goto_model));
321309
322- if (speculative_sat )
310+ if (speculative_thread )
323311 {
324- log.status () << " Speculative check found potential failure"
325- << messaget::eom;
326- }
312+ speculative_thread->join ();
313+ speculative_thread.reset ();
327314
328- equation.set_message_handler (ui_message_handler);
329- if (!speculative_log_output.empty ())
330- {
331- log.debug () << speculative_log_output << messaget::eom;
315+ if (speculative_sat)
316+ {
317+ log.status () << " Speculative check found potential failure"
318+ << messaget::eom;
319+ }
320+
321+ equation.set_message_handler (ui_message_handler);
322+ if (!speculative_log_output.empty ())
323+ log.debug () << speculative_log_output << messaget::eom;
332324 }
333- }
334325
335- // Restore the original merge_irep (merges both pools).
336- equation.swap_merge_irep (std::move (saved_merge_irep));
326+ equation.swap_merge_irep (std::move (saved));
327+ }
328+ else
329+ {
330+ full_equation_generated =
331+ !symex.resume (goto_symext::get_goto_function (goto_model));
332+ }
337333
338334 revert_slice (equation);
339335
340- // This might add new properties such as unwinding assertions.
341336 update_properties_status_from_symex_target_equation (
342337 properties, result.updated_properties , equation);
343338
0 commit comments