Skip to content

Commit c842c01

Browse files
Replace throws with structured throws or invariant in interpreter
1 parent 4ff7318 commit c842c01

File tree

2 files changed

+37
-27
lines changed

2 files changed

+37
-27
lines changed

src/goto-programs/interpreter.cpp

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ void interpretert::initialize(bool init)
6969
main_it=goto_functions.function_map.find(goto_functionst::entry_point());
7070

7171
if(main_it==goto_functions.function_map.end())
72-
throw "main not found";
72+
throw analysis_exceptiont("main not found");
7373

7474
const goto_functionst::goto_functiont &goto_function=main_it->second;
7575

7676
if(!goto_function.body_available())
77-
throw "main has no body";
77+
throw analysis_exceptiont("main has no body");
7878

7979
pc=goto_function.body.instructions.begin();
8080
function=main_it;
@@ -292,7 +292,10 @@ void interpretert::step()
292292
case RETURN:
293293
trace_step.type=goto_trace_stept::typet::FUNCTION_RETURN;
294294
if(call_stack.empty())
295-
throw "RETURN without call"; // NOLINT(readability/throw)
295+
{
296+
throw analysis_exceptiont(
297+
"RETURN without call"); // NOLINT(readability/throw)
298+
}
296299

297300
if(pc->code.operands().size()==1 &&
298301
call_stack.top().return_value_address!=0)
@@ -317,19 +320,23 @@ void interpretert::step()
317320

318321
case START_THREAD:
319322
trace_step.type=goto_trace_stept::typet::SPAWN;
320-
throw "START_THREAD not yet implemented"; // NOLINT(readability/throw)
323+
throw analysis_exceptiont(
324+
"START_THREAD not yet implemented"); // NOLINT(readability/throw)
321325

322326
case END_THREAD:
323-
throw "END_THREAD not yet implemented"; // NOLINT(readability/throw)
327+
throw analysis_exceptiont(
328+
"END_THREAD not yet implemented"); // NOLINT(readability/throw)
324329
break;
325330

326331
case ATOMIC_BEGIN:
327332
trace_step.type=goto_trace_stept::typet::ATOMIC_BEGIN;
328-
throw "ATOMIC_BEGIN not yet implemented"; // NOLINT(readability/throw)
333+
throw analysis_exceptiont(
334+
"ATOMIC_BEGIN not yet implemented"); // NOLINT(readability/throw)
329335

330336
case ATOMIC_END:
331337
trace_step.type=goto_trace_stept::typet::ATOMIC_END;
332-
throw "ATOMIC_END not yet implemented"; // NOLINT(readability/throw)
338+
throw analysis_exceptiont(
339+
"ATOMIC_END not yet implemented"); // NOLINT(readability/throw)
333340

334341
case DEAD:
335342
trace_step.type=goto_trace_stept::typet::DEAD;
@@ -359,7 +366,7 @@ void interpretert::step()
359366
case CATCH:
360367
break;
361368
default:
362-
throw "encountered instruction with undefined instruction type";
369+
UNREACHABLE; // I'm assuming we'd catch such a thing before this point
363370
}
364371
pc=next_pc;
365372
}
@@ -369,11 +376,9 @@ void interpretert::execute_goto()
369376
{
370377
if(evaluate_boolean(pc->guard))
371378
{
372-
if(pc->targets.empty())
373-
throw "taken goto without target";
374-
375-
if(pc->targets.size()>=2)
376-
throw "non-deterministic goto encountered";
379+
DATA_INVARIANT(
380+
pc->targets.size() == 1,
381+
"a goto should have exactly one target location");
377382

378383
next_pc=pc->targets.front();
379384
}
@@ -383,6 +388,10 @@ void interpretert::execute_goto()
383388
void interpretert::execute_other()
384389
{
385390
const irep_idt &statement=pc->code.get_statement();
391+
PRECONDITION(
392+
statement == ID_expression || statement == ID_array_set ||
393+
statement == ID_output);
394+
386395
if(statement==ID_expression)
387396
{
388397
DATA_INVARIANT(
@@ -410,8 +419,6 @@ void interpretert::execute_other()
410419
{
411420
return;
412421
}
413-
else
414-
throw "unexpected OTHER statement: "+id2string(statement);
415422
}
416423

417424
void interpretert::execute_decl()
@@ -427,8 +434,7 @@ struct_typet::componentt interpretert::get_component(
427434
{
428435
const symbolt &symbol=ns.lookup(object);
429436
const typet real_type=ns.follow(symbol.type);
430-
if(real_type.id()!=ID_struct)
431-
throw "request for member of non-struct";
437+
PRECONDITION(real_type.id() == ID_struct);
432438

433439
const struct_typet &struct_type=to_struct_type(real_type);
434440
const struct_typet::componentst &components=struct_type.components();
@@ -443,7 +449,7 @@ struct_typet::componentt interpretert::get_component(
443449
tmp_offset-=get_size(c.type());
444450
}
445451

446-
throw "access out of struct bounds";
452+
throw analysis_exceptiont("access out of struct bounds");
447453
}
448454

449455
/// returns the type object corresponding to id
@@ -634,7 +640,7 @@ exprt interpretert::get_value(
634640
error() << "interpreter: invalid pointer " << rhs[integer2size_t(offset)]
635641
<< " > object count " << memory.size() << eom;
636642

637-
throw "interpreter: reading from invalid pointer";
643+
throw analysis_exceptiont("interpreter: reading from invalid pointer");
638644
}
639645
else if(real_type.id()==ID_string)
640646
{
@@ -724,15 +730,15 @@ void interpretert::assign(
724730
void interpretert::execute_assume()
725731
{
726732
if(!evaluate_boolean(pc->guard))
727-
throw "assumption failed";
733+
throw analysis_exceptiont("assumption failed");
728734
}
729735

730736
void interpretert::execute_assert()
731737
{
732738
if(!evaluate_boolean(pc->guard))
733739
{
734740
if((target_assert==pc) || stop_on_assertion)
735-
throw "program assertion reached";
741+
throw analysis_exceptiont("program assertion reached");
736742
else if(show)
737743
error() << "assertion failed at " << pc->location_number
738744
<< "\n" << eom;
@@ -748,9 +754,9 @@ void interpretert::execute_function_call()
748754
mp_integer address=evaluate_address(function_call.function());
749755

750756
if(address==0)
751-
throw "function call to NULL";
757+
throw analysis_exceptiont("function call to NULL");
752758
else if(address>=memory.size())
753-
throw "out-of-range function call";
759+
throw analysis_exceptiont("out-of-range function call");
754760

755761
// Retrieve the empty last trace step struct we pushed for this step
756762
// of the interpreter run to fill it with the corresponding data
@@ -764,8 +770,9 @@ void interpretert::execute_function_call()
764770
const goto_functionst::function_mapt::const_iterator f_it=
765771
goto_functions.function_map.find(identifier);
766772

767-
if(f_it==goto_functions.function_map.end())
768-
throw "failed to find function "+id2string(identifier);
773+
INVARIANT(
774+
f_it != goto_functions.function_map.end(),
775+
"calls to missing functions should be caught during typechecking");
769776

770777
// return value
771778
mp_integer return_value_address;
@@ -810,8 +817,10 @@ void interpretert::execute_function_call()
810817
const code_typet::parameterst &parameters=
811818
to_code_type(f_it->second.type).parameters();
812819

813-
if(argument_values.size()<parameters.size())
814-
throw "not enough arguments";
820+
INVARIANT(
821+
argument_values.size() != parameters.size(),
822+
"function calls not matching function signatures should be caught during "
823+
"typechecking");
815824

816825
for(std::size_t i=0; i<parameters.size(); i++)
817826
{

src/goto-programs/interpreter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#ifndef CPROVER_GOTO_PROGRAMS_INTERPRETER_H
1313
#define CPROVER_GOTO_PROGRAMS_INTERPRETER_H
1414

15+
#include <util/exception_utils.h>
1516
#include <util/message.h>
1617

1718
#include "goto_model.h"

0 commit comments

Comments
 (0)