Skip to content

Commit dca3c7e

Browse files
hannes-steffenhagen-diffbluePetr Bauch
authored and
Petr Bauch
committed
WIP replace throws with structured throws or invariant in interpreter
1 parent e38c55a commit dca3c7e

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
@@ -639,7 +643,7 @@ exprt interpretert::get_value(
639643
error() << "interpreter: invalid pointer " << rhs[integer2size_t(offset)]
640644
<< " > object count " << memory.size() << eom;
641645

642-
throw "interpreter: reading from invalid pointer";
646+
throw interpreter_errort("interpreter: reading from invalid pointer");
643647
}
644648
else if(real_type.id()==ID_string)
645649
{
@@ -729,15 +733,15 @@ void interpretert::assign(
729733
void interpretert::execute_assume()
730734
{
731735
if(!evaluate_boolean(pc->guard))
732-
throw "assumption failed";
736+
throw interpreter_errort("assumption failed");
733737
}
734738

735739
void interpretert::execute_assert()
736740
{
737741
if(!evaluate_boolean(pc->guard))
738742
{
739743
if((target_assert==pc) || stop_on_assertion)
740-
throw "program assertion reached";
744+
throw interpreter_errort("program assertion reached");
741745
else if(show)
742746
error() << "assertion failed at " << pc->location_number
743747
<< "\n" << eom;
@@ -753,9 +757,9 @@ void interpretert::execute_function_call()
753757
mp_integer address=evaluate_address(function_call.function());
754758

755759
if(address==0)
756-
throw "function call to NULL";
760+
throw interpreter_errort("function call to NULL");
757761
else if(address>=memory.size())
758-
throw "out-of-range function call";
762+
throw interpreter_errort("out-of-range function call");
759763

760764
// Retrieve the empty last trace step struct we pushed for this step
761765
// of the interpreter run to fill it with the corresponding data
@@ -769,8 +773,8 @@ void interpretert::execute_function_call()
769773
const goto_functionst::function_mapt::const_iterator f_it=
770774
goto_functions.function_map.find(identifier);
771775

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

775779
// return value
776780
mp_integer return_value_address;
@@ -815,8 +819,8 @@ void interpretert::execute_function_call()
815819
const code_typet::parameterst &parameters=
816820
to_code_type(f_it->second.type).parameters();
817821

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

821825
for(std::size_t i=0; i<parameters.size(); i++)
822826
{
@@ -1090,3 +1094,11 @@ void interpreter(
10901094
message_handler);
10911095
interpreter();
10921096
}
1097+
1098+
interpreter_errort::interpreter_errort(std::string message)
1099+
: message(message)
1100+
{}
1101+
1102+
std::string interpreter_errort::what() const noexcept {
1103+
return message;
1104+
}

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)