44
44
struct sieve_interpreter {
47
47
/* Runtime data for extensions */
48
ARRAY_DEFINE(extensions, struct sieve_interpreter_extension_reg);
50
sieve_size_t reset_vector;
48
ARRAY(struct sieve_interpreter_extension_reg) extensions;
50
sieve_size_t reset_vector;
52
52
/* Execution status */
54
54
sieve_size_t pc; /* Program counter */
55
55
bool interrupted; /* Interpreter interrupt requested */
56
56
bool test_result; /* Result of previous test command */
58
58
/* Runtime environment */
59
59
struct sieve_runtime_env runenv;
60
60
struct sieve_runtime_trace trace;
62
62
/* Current operation */
63
struct sieve_operation oprtn;
63
struct sieve_operation oprtn;
65
65
/* Location information */
66
66
struct sieve_binary_debug_reader *dreader;
70
70
static struct sieve_interpreter *_sieve_interpreter_create
71
(struct sieve_binary *sbin, struct sieve_binary_block *sblock,
71
(struct sieve_binary *sbin, struct sieve_binary_block *sblock,
72
72
struct sieve_script *script, const struct sieve_message_data *msgdata,
73
73
const struct sieve_script_env *senv, struct sieve_error_handler *ehandler,
74
enum sieve_runtime_flags flags)
74
enum sieve_runtime_flags flags)
76
76
unsigned int i, ext_count;
77
77
struct sieve_interpreter *interp;
81
81
unsigned int debug_block_id;
82
82
sieve_size_t *address;
83
83
bool success = TRUE;
85
pool = pool_alloconly_create("sieve_interpreter", 4096);
85
pool = pool_alloconly_create("sieve_interpreter", 4096);
86
86
interp = p_new(pool, struct sieve_interpreter, 1);
87
87
interp->pool = pool;
109
109
interp->runenv.trace = &interp->trace;
112
if ( senv->exec_status == NULL )
112
if ( senv->exec_status == NULL )
113
113
interp->runenv.exec_status = p_new(interp->pool, struct sieve_exec_status, 1);
115
115
interp->runenv.exec_status = senv->exec_status;
117
if ( script == NULL )
117
if ( script == NULL )
118
118
interp->runenv.script = sieve_binary_script(sbin);
120
120
interp->runenv.script = script;
122
122
interp->runenv.pc = 0;
123
123
address = &(interp->runenv.pc);
127
127
p_array_init(&interp->extensions, pool, sieve_extensions_get_count(svinst));
129
129
/* Pre-load core language features implemented as 'extensions' */
130
ext_preloaded = sieve_extensions_get_preloaded(svinst, &ext_count);
130
ext_preloaded = sieve_extensions_get_preloaded(svinst, &ext_count);
131
131
for ( i = 0; i < ext_count; i++ ) {
132
132
const struct sieve_extension_def *ext_def = ext_preloaded[i]->def;
134
134
if ( ext_def != NULL && ext_def->interpreter_load != NULL )
135
135
(void)ext_def->interpreter_load
136
(ext_preloaded[i], &interp->runenv, address);
136
(ext_preloaded[i], &interp->runenv, address);
139
139
/* Load debug block */
153
153
/* Load other extensions listed in code */
155
155
sieve_binary_read_unsigned(sblock, address, &ext_count) ) {
157
157
for ( i = 0; i < ext_count; i++ ) {
158
158
unsigned int code = 0;
159
159
const struct sieve_extension *ext;
161
161
if ( !sieve_binary_read_extension(sblock, address, &code, &ext) ) {
166
166
if ( ext->def != NULL ) {
167
167
if ( ext->global && (flags & SIEVE_RUNTIME_FLAG_NOGLOBAL) != 0 ) {
168
168
sieve_runtime_error(&interp->runenv, NULL,
186
186
if ( !success ) {
187
187
sieve_interpreter_free(&interp);
190
190
interp->reset_vector = *address;
196
196
struct sieve_interpreter *sieve_interpreter_create
197
197
(struct sieve_binary *sbin, const struct sieve_message_data *msgdata,
198
198
const struct sieve_script_env *senv, struct sieve_error_handler *ehandler,
199
enum sieve_runtime_flags flags)
199
enum sieve_runtime_flags flags)
201
201
struct sieve_binary_block *sblock;
203
if ( (sblock=sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM))
203
if ( (sblock=sieve_binary_block_get(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM))
211
211
struct sieve_interpreter *sieve_interpreter_create_for_block
212
212
(struct sieve_binary_block *sblock, struct sieve_script *script,
213
const struct sieve_message_data *msgdata, const struct sieve_script_env *senv,
214
struct sieve_error_handler *ehandler, enum sieve_runtime_flags flags)
213
const struct sieve_message_data *msgdata, const struct sieve_script_env *senv,
214
struct sieve_error_handler *ehandler, enum sieve_runtime_flags flags)
216
216
if ( sblock == NULL ) return NULL;
293
293
if ( location == NULL )
294
294
location = sieve_runtime_get_full_command_location(renv);
296
msg_func(renv->ehandler, location, fmt, args);
296
msg_func(renv->ehandler, location, fmt, args);
343
343
location = sieve_runtime_get_full_command_location(renv);
346
(renv->svinst, renv->ehandler, location, user_prefix, fmt, args);
346
(renv->svinst, renv->ehandler, location, user_prefix, fmt, args);
404
404
if ( ext->id < 0 ) return;
406
reg = array_idx_modifiable(&interp->extensions, (unsigned int) ext->id);
406
reg = array_idx_modifiable(&interp->extensions, (unsigned int) ext->id);
407
407
reg->intext = intext;
409
409
reg->context = context;
412
412
void sieve_interpreter_extension_set_context
413
(struct sieve_interpreter *interp, const struct sieve_extension *ext,
413
(struct sieve_interpreter *interp, const struct sieve_extension *ext,
416
416
struct sieve_interpreter_extension_reg *reg;
418
418
if ( ext->id < 0 ) return;
420
reg = array_idx_modifiable(&interp->extensions, (unsigned int) ext->id);
420
reg = array_idx_modifiable(&interp->extensions, (unsigned int) ext->id);
421
421
reg->context = context;
424
424
void *sieve_interpreter_extension_get_context
425
(struct sieve_interpreter *interp, const struct sieve_extension *ext)
425
(struct sieve_interpreter *interp, const struct sieve_extension *ext)
427
427
const struct sieve_interpreter_extension_reg *reg;
429
429
if ( ext->id < 0 || ext->id >= (int) array_count(&interp->extensions) )
432
reg = array_idx(&interp->extensions, (unsigned int) ext->id);
432
reg = array_idx(&interp->extensions, (unsigned int) ext->id);
434
434
return reg->context;
441
void sieve_interpreter_reset(struct sieve_interpreter *interp)
441
void sieve_interpreter_reset(struct sieve_interpreter *interp)
443
443
interp->runenv.pc = interp->reset_vector;
444
444
interp->interrupted = FALSE;
463
463
sieve_size_t *address = &(interp->runenv.pc);
464
464
sieve_size_t jmp_start = *address;
465
465
sieve_offset_t jmp_offset;
467
467
if ( !sieve_binary_read_offset(renv->sblock, address, &jmp_offset) )
469
sieve_runtime_trace_error(renv, "invalid jump offset");
469
sieve_runtime_trace_error(renv, "invalid jump offset");
470
470
return SIEVE_EXEC_BIN_CORRUPT;
473
if ( jmp_start + jmp_offset <= sieve_binary_block_get_size(renv->sblock) &&
474
jmp_start + jmp_offset > 0 )
473
if ( jmp_start + jmp_offset <= sieve_binary_block_get_size(renv->sblock) &&
474
jmp_start + jmp_offset > 0 )
477
477
sieve_size_t jmp_addr = jmp_start + jmp_offset;
479
479
if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) {
480
unsigned int jmp_line =
480
unsigned int jmp_line =
481
481
sieve_runtime_get_source_location(renv, jmp_addr);
483
483
if ( sieve_runtime_trace_hasflag(renv, SIEVE_TRFLG_ADDRESSES) ) {
484
sieve_runtime_trace(renv, 0, "jumping to line %d [%08llx]",
484
sieve_runtime_trace(renv, 0, "jumping to line %d [%08llx]",
485
485
jmp_line, (long long unsigned int) jmp_addr);
487
487
sieve_runtime_trace(renv, 0, "jumping to line %d", jmp_line);
491
491
*address = jmp_addr;
493
sieve_runtime_trace(renv, 0, "not jumping");
493
sieve_runtime_trace(renv, 0, "not jumping");
496
496
return SIEVE_EXEC_OK;
499
499
sieve_runtime_trace_error(renv, "jump offset out of range");
500
500
return SIEVE_EXEC_BIN_CORRUPT;
516
516
return interp->test_result;
523
523
static int sieve_interpreter_operation_execute
524
(struct sieve_interpreter *interp)
524
(struct sieve_interpreter *interp)
526
526
struct sieve_operation *oprtn = &(interp->oprtn);
527
527
sieve_size_t *address = &(interp->runenv.pc);
545
545
sieve_runtime_trace
546
(&interp->runenv, SIEVE_TRLVL_COMMANDS, "OP: %s (NOOP)",
546
(&interp->runenv, SIEVE_TRLVL_COMMANDS, "OP: %s (NOOP)",
547
547
sieve_operation_mnemonic(oprtn));
553
553
/* Binary corrupt */
554
sieve_runtime_trace_error(&interp->runenv, "Encountered invalid operation");
554
sieve_runtime_trace_error(&interp->runenv, "Encountered invalid operation");
555
555
return SIEVE_EXEC_BIN_CORRUPT;
558
558
int sieve_interpreter_continue
559
(struct sieve_interpreter *interp, bool *interrupted)
559
(struct sieve_interpreter *interp, bool *interrupted)
561
561
sieve_size_t *address = &(interp->runenv.pc);
562
562
int ret = SIEVE_EXEC_OK;
564
564
sieve_result_ref(interp->runenv.result);
565
565
interp->interrupted = FALSE;
567
567
if ( interrupted != NULL )
568
568
*interrupted = FALSE;
570
while ( ret == SIEVE_EXEC_OK && !interp->interrupted &&
570
while ( ret == SIEVE_EXEC_OK && !interp->interrupted &&
571
571
*address < sieve_binary_block_get_size(interp->runenv.sblock) ) {
573
573
ret = sieve_interpreter_operation_execute(interp);
575
575
if ( ret != SIEVE_EXEC_OK ) {
576
sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE,
576
sieve_runtime_trace(&interp->runenv, SIEVE_TRLVL_NONE,
577
577
"[[EXECUTION ABORTED]]");
581
581
if ( interrupted != NULL )
582
582
*interrupted = interp->interrupted;
584
584
sieve_result_unref(&interp->runenv.result);
588
588
int sieve_interpreter_start
589
(struct sieve_interpreter *interp, struct sieve_result *result, bool *interrupted)
589
(struct sieve_interpreter *interp, struct sieve_result *result, bool *interrupted)
591
591
const struct sieve_interpreter_extension_reg *eregs;
592
592
unsigned int ext_count, i;
594
594
interp->runenv.result = result;
595
interp->runenv.msgctx = sieve_result_get_message_context(result);
595
interp->runenv.msgctx = sieve_result_get_message_context(result);
597
597
/* Signal registered extensions that the interpreter is being run */
598
598
eregs = array_get(&interp->extensions, &ext_count);
599
599
for ( i = 0; i < ext_count; i++ ) {
601
601
eregs[i].intext->run(eregs[i].ext, &interp->runenv, eregs[i].context);
604
return sieve_interpreter_continue(interp, interrupted);
604
return sieve_interpreter_continue(interp, interrupted);
607
607
int sieve_interpreter_run
608
608
(struct sieve_interpreter *interp, struct sieve_result *result)
612
612
sieve_interpreter_reset(interp);
613
613
sieve_result_ref(result);
615
615
ret = sieve_interpreter_start(interp, result, NULL);
617
617
sieve_result_unref(&result);