Skip to content

Commit 6b91499

Browse files
committed
Refactor entry point validation towards symex-callers
We can detect the absence of an entry point much earlier and do not need to perform unnecessary work before inevitably failing. Fixes: #1847
1 parent 4fe3ade commit 6b91499

File tree

5 files changed

+37
-15
lines changed

5 files changed

+37
-15
lines changed

src/goto-checker/multi_path_symex_only_checker.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ Author: Daniel Kroening, Peter Schrammel
1111

1212
#include "multi_path_symex_only_checker.h"
1313

14+
#include <util/exception_utils.h>
1415
#include <util/ui_message.h>
1516

17+
#include <goto-programs/goto_functions.h>
18+
1619
#include <goto-symex/shadow_memory.h>
1720
#include <goto-symex/show_program.h>
1821
#include <goto-symex/show_vcc.h>
@@ -80,6 +83,11 @@ void multi_path_symex_only_checkert::generate_equation()
8083

8184
const auto symex_start = std::chrono::steady_clock::now();
8285

86+
// Validate that the entry point exists before calling symex
87+
const irep_idt entry_point_id = goto_functionst::entry_point();
88+
if(!goto_model.can_produce_function(entry_point_id))
89+
throw invalid_input_exceptiont("the program has no entry point");
90+
8391
symex_symbol_table = symex.symex_from_entry_point_of(
8492
goto_symext::get_goto_function(goto_model), fields);
8593

src/goto-checker/single_path_symex_only_checker.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ Author: Daniel Kroening, Peter Schrammel
1111

1212
#include "single_path_symex_only_checker.h"
1313

14+
#include <util/exception_utils.h>
1415
#include <util/ui_message.h>
1516

17+
#include <goto-programs/goto_functions.h>
18+
1619
#include <goto-symex/path_storage.h>
1720
#include <goto-symex/shadow_memory.h>
1821
#include <goto-symex/show_program.h>
@@ -80,6 +83,11 @@ void single_path_symex_only_checkert::initialize_worklist()
8083
const auto fields =
8184
shadow_memoryt::gather_field_declarations(goto_model, ui_message_handler);
8285

86+
// Validate that the entry point exists before calling symex
87+
const irep_idt entry_point_id = goto_functionst::entry_point();
88+
if(!goto_model.can_produce_function(entry_point_id))
89+
throw invalid_input_exceptiont("the program has no entry point");
90+
8391
symex.initialize_path_storage_from_entry_point_of(
8492
goto_symext::get_goto_function(goto_model), symex_symbol_table, fields);
8593
}

src/goto-checker/symex_bmc_incremental_one_loop.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ Author: Peter Schrammel, Daniel Kroening, [email protected]
88

99
#include "symex_bmc_incremental_one_loop.h"
1010

11+
#include <util/exception_utils.h>
1112
#include <util/structured_data.h>
1213

14+
#include <goto-programs/goto_functions.h>
1315
#include <goto-programs/unwindset.h>
1416

1517
#include <limits>
@@ -126,6 +128,11 @@ bool symex_bmc_incremental_one_loopt::from_entry_point_of(
126128
const get_goto_functiont &get_goto_function,
127129
symbol_tablet &new_symbol_table)
128130
{
131+
// Validate that the entry point exists before calling symex
132+
const irep_idt entry_point_id = goto_functionst::entry_point();
133+
if(!goto_model.can_produce_function(entry_point_id))
134+
throw invalid_input_exceptiont("the program has no entry point");
135+
129136
state = initialize_entry_point_state(get_goto_function);
130137

131138
new_symbol_table = symex_with_state(*state, get_goto_function);

src/goto-symex/goto_symex.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ class goto_symext
189189
/// the beginning of the entry point function.
190190
/// \param get_goto_function: producer for GOTO functions
191191
/// \return Initialized symex state.
192+
/// \pre The entry point function must exist in the model provided by
193+
/// get_goto_function. Callers should validate this before calling this
194+
/// method to ensure proper error reporting.
192195
std::unique_ptr<statet>
193196
initialize_entry_point_state(const get_goto_functiont &get_goto_function);
194197

src/goto-symex/symex_main.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -399,23 +399,19 @@ std::unique_ptr<goto_symext::statet> goto_symext::initialize_entry_point_state(
399399
{
400400
const irep_idt entry_point_id = goto_functionst::entry_point();
401401

402-
const goto_functionst::goto_functiont *start_function;
403-
try
404-
{
405-
start_function = &get_goto_function(entry_point_id);
406-
}
407-
catch(const std::out_of_range &)
408-
{
409-
throw unsupported_operation_exceptiont("the program has no entry point");
410-
}
402+
// Entry point existence must be validated by callers before calling
403+
// this function. If get_goto_function throws std::out_of_range, it
404+
// indicates a precondition violation.
405+
const goto_functionst::goto_functiont &start_function =
406+
get_goto_function(entry_point_id);
411407

412408
// Get our path_storage pointer because this state will live beyond
413409
// this instance of goto_symext, so we can't take the reference directly.
414410
auto *storage = &path_storage;
415411

416412
// create and prepare the state
417413
auto state = std::make_unique<statet>(
418-
symex_targett::sourcet(entry_point_id, start_function->body),
414+
symex_targett::sourcet(entry_point_id, start_function.body),
419415
symex_config.max_field_sensitivity_array_size,
420416
symex_config.simplify_opt,
421417
language_mode,
@@ -426,11 +422,11 @@ std::unique_ptr<goto_symext::statet> goto_symext::initialize_entry_point_state(
426422
CHECK_RETURN(!state->call_stack().empty());
427423

428424
goto_programt::const_targett limit =
429-
std::prev(start_function->body.instructions.end());
425+
std::prev(start_function.body.instructions.end());
430426
state->call_stack().top().end_of_function = limit;
431427
state->call_stack().top().calling_location.pc =
432428
state->call_stack().top().end_of_function;
433-
state->call_stack().top().hidden_function = start_function->is_hidden();
429+
state->call_stack().top().hidden_function = start_function.is_hidden();
434430

435431
state->symex_target = &target;
436432

@@ -440,17 +436,17 @@ std::unique_ptr<goto_symext::statet> goto_symext::initialize_entry_point_state(
440436
auto emplace_safe_pointers_result =
441437
path_storage.safe_pointers.emplace(entry_point_id, local_safe_pointerst{});
442438
if(emplace_safe_pointers_result.second)
443-
emplace_safe_pointers_result.first->second(start_function->body);
439+
emplace_safe_pointers_result.first->second(start_function.body);
444440

445441
path_storage.dirty.populate_dirty_for_function(
446-
entry_point_id, *start_function);
442+
entry_point_id, start_function);
447443
state->dirty = &path_storage.dirty;
448444

449445
// Only enable loop analysis when complexity is enabled.
450446
if(symex_config.complexity_limits_active)
451447
{
452448
// Set initial loop analysis.
453-
path_storage.add_function_loops(entry_point_id, start_function->body);
449+
path_storage.add_function_loops(entry_point_id, start_function.body);
454450
state->call_stack().top().loops_info =
455451
path_storage.get_loop_analysis(entry_point_id);
456452
}

0 commit comments

Comments
 (0)