Skip to content

Commit c864b32

Browse files
WIP replace throws with structured throws or invariant in interpreter
1 parent fbca787 commit c864b32

File tree

2 files changed

+52
-28
lines changed

2 files changed

+52
-28
lines changed

src/goto-programs/interpreter.cpp

Lines changed: 40 additions & 28 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 interpreter_errort("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 interpreter_errort("main has no body");
7878

7979
pc=goto_function.body.instructions.begin();
8080
function=main_it;
@@ -291,8 +291,11 @@ void interpretert::step()
291291

292292
case RETURN:
293293
trace_step.type=goto_trace_stept::typet::FUNCTION_RETURN;
294-
if(call_stack.empty())
295-
throw "RETURN without call"; // NOLINT(readability/throw)
294+
if(call_stack.empty()) {
295+
// FIXME I left this as an exception because I think this
296+
// could happen if fed with a broken goto program?
297+
throw interpreter_errort("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,20 @@ 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+
// Could be triggered by wrong input, therefore throw?
324+
throw interpreter_errort("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 interpreter_errort("END_THREAD not yet implemented"); // NOLINT(readability/throw)
324328
break;
325329

326330
case ATOMIC_BEGIN:
327331
trace_step.type=goto_trace_stept::typet::ATOMIC_BEGIN;
328-
throw "ATOMIC_BEGIN not yet implemented"; // NOLINT(readability/throw)
332+
throw interpreter_errort("ATOMIC_BEGIN not yet implemented"); // NOLINT(readability/throw)
329333

330334
case ATOMIC_END:
331335
trace_step.type=goto_trace_stept::typet::ATOMIC_END;
332-
throw "ATOMIC_END not yet implemented"; // NOLINT(readability/throw)
336+
throw interpreter_errort("ATOMIC_END not yet implemented"); // NOLINT(readability/throw)
333337

334338
case DEAD:
335339
trace_step.type=goto_trace_stept::typet::DEAD;
@@ -359,7 +363,7 @@ void interpretert::step()
359363
case CATCH:
360364
break;
361365
default:
362-
throw "encountered instruction with undefined instruction type";
366+
UNREACHABLE; // I'm assuming we'd catch such a thing before this point
363367
}
364368
pc=next_pc;
365369
}
@@ -369,11 +373,8 @@ void interpretert::execute_goto()
369373
{
370374
if(evaluate_boolean(pc->guard))
371375
{
372-
if(pc->targets.empty())
373-
throw "taken goto without target";
374-
375-
if(pc->targets.size()>=2)
376-
throw "non-deterministic goto encountered";
376+
DATA_INVARIANT(pc->targets.size() == 1,
377+
"a goto should have exactly one target location");
377378

378379
next_pc=pc->targets.front();
379380
}
@@ -383,6 +384,10 @@ void interpretert::execute_goto()
383384
void interpretert::execute_other()
384385
{
385386
const irep_idt &statement=pc->code.get_statement();
387+
PRECONDITION(statement == ID_expression
388+
|| statement == ID_array_set
389+
|| statement == ID_output);
390+
386391
if(statement==ID_expression)
387392
{
388393
DATA_INVARIANT(
@@ -410,8 +415,6 @@ void interpretert::execute_other()
410415
{
411416
return;
412417
}
413-
else
414-
throw "unexpected OTHER statement: "+id2string(statement);
415418
}
416419

417420
void interpretert::execute_decl()
@@ -427,8 +430,7 @@ struct_typet::componentt interpretert::get_component(
427430
{
428431
const symbolt &symbol=ns.lookup(object);
429432
const typet real_type=ns.follow(symbol.type);
430-
if(real_type.id()!=ID_struct)
431-
throw "request for member of non-struct";
433+
PRECONDITION(real_type.id() == ID_struct);
432434

433435
const struct_typet &struct_type=to_struct_type(real_type);
434436
const struct_typet::componentst &components=struct_type.components();
@@ -443,7 +445,9 @@ struct_typet::componentt interpretert::get_component(
443445
tmp_offset-=get_size(c.type());
444446
}
445447

446-
throw "access out of struct bounds";
448+
// FIXME not sure if its possible to catch this in advance
449+
// so I've left it as an exception for now
450+
throw interpreter_errort("access out of struct bounds");
447451
}
448452

449453
/// returns the type object corresponding to id
@@ -634,7 +638,7 @@ exprt interpretert::get_value(
634638
error() << "interpreter: invalid pointer " << rhs[integer2size_t(offset)]
635639
<< " > object count " << memory.size() << eom;
636640

637-
throw "interpreter: reading from invalid pointer";
641+
throw interpreter_errort("interpreter: reading from invalid pointer");
638642
}
639643
else if(real_type.id()==ID_string)
640644
{
@@ -724,15 +728,15 @@ void interpretert::assign(
724728
void interpretert::execute_assume()
725729
{
726730
if(!evaluate_boolean(pc->guard))
727-
throw "assumption failed";
731+
throw interpreter_errort("assumption failed");
728732
}
729733

730734
void interpretert::execute_assert()
731735
{
732736
if(!evaluate_boolean(pc->guard))
733737
{
734738
if((target_assert==pc) || stop_on_assertion)
735-
throw "program assertion reached";
739+
throw interpreter_errort("program assertion reached");
736740
else if(show)
737741
error() << "assertion failed at " << pc->location_number
738742
<< "\n" << eom;
@@ -748,9 +752,9 @@ void interpretert::execute_function_call()
748752
mp_integer address=evaluate_address(function_call.function());
749753

750754
if(address==0)
751-
throw "function call to NULL";
755+
throw interpreter_errort("function call to NULL");
752756
else if(address>=memory.size())
753-
throw "out-of-range function call";
757+
throw interpreter_errort("out-of-range function call");
754758

755759
// Retrieve the empty last trace step struct we pushed for this step
756760
// of the interpreter run to fill it with the corresponding data
@@ -764,8 +768,8 @@ void interpretert::execute_function_call()
764768
const goto_functionst::function_mapt::const_iterator f_it=
765769
goto_functions.function_map.find(identifier);
766770

767-
if(f_it==goto_functions.function_map.end())
768-
throw "failed to find function "+id2string(identifier);
771+
INVARIANT(f_it != goto_functions.function_map.end(),
772+
"FIXME I don't think this can happen if we have a typechecking phase before this?");
769773

770774
// return value
771775
mp_integer return_value_address;
@@ -810,8 +814,8 @@ void interpretert::execute_function_call()
810814
const code_typet::parameterst &parameters=
811815
to_code_type(f_it->second.type).parameters();
812816

813-
if(argument_values.size()<parameters.size())
814-
throw "not enough arguments";
817+
INVARIANT(argument_values.size() != parameters.size(),
818+
"FIXME I don't think this can happen if we have a typechecking phase before this?");
815819

816820
for(std::size_t i=0; i<parameters.size(); i++)
817821
{
@@ -1085,3 +1089,11 @@ void interpreter(
10851089
message_handler);
10861090
interpreter();
10871091
}
1092+
1093+
interpreter_errort::interpreter_errort(std::string message)
1094+
: message(message)
1095+
{}
1096+
1097+
std::string interpreter_errort::what() const noexcept {
1098+
return message;
1099+
}

src/goto-programs/interpreter.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,21 @@ Author: Daniel Kroening, [email protected]
1313
#define CPROVER_GOTO_PROGRAMS_INTERPRETER_H
1414

1515
#include <util/message.h>
16+
#include <util/exception_utils.h>
17+
18+
#include <string>
1619

1720
#include "goto_model.h"
1821

22+
class interpreter_errort : public cprover_exceptiont
23+
{
24+
public:
25+
explicit interpreter_errort(std::string message);
26+
std::string what() const noexcept override;
27+
private:
28+
std::string message;
29+
};
30+
1931
void interpreter(
2032
const goto_modelt &,
2133
message_handlert &);

0 commit comments

Comments
 (0)