From acf33c8b3f31ac6ca7cb9e65da9006ab63f7952f Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 31 Aug 2008 22:07:20 +0200
Subject: [PATCH] Added the concept of a script code header to list the
 extensions actually used by a script (was using all extensions listed in the
 binary).

---
 .../plugins/include/ext-include-binary.c      |  4 ++
 .../plugins/include/ext-include-common.c      | 71 +++++++++++--------
 src/lib-sieve/sieve-ast.c                     | 12 +++-
 src/lib-sieve/sieve-binary-dumper.c           |  6 +-
 src/lib-sieve/sieve-code-dumper.c             | 42 ++++++++++-
 src/lib-sieve/sieve-generator.c               |  6 +-
 src/lib-sieve/sieve-interpreter.c             | 42 +++++++----
 src/lib-sieve/sieve.c                         |  8 ++-
 src/testsuite/testsuite-common.c              |  3 +
 src/testsuite/testsuite.c                     | 13 ++--
 10 files changed, 155 insertions(+), 52 deletions(-)

diff --git a/src/lib-sieve/plugins/include/ext-include-binary.c b/src/lib-sieve/plugins/include/ext-include-binary.c
index 530243ac6..cf1b4bc52 100644
--- a/src/lib-sieve/plugins/include/ext-include-binary.c
+++ b/src/lib-sieve/plugins/include/ext-include-binary.c
@@ -395,6 +395,10 @@ bool ext_include_binary_dump(struct sieve_dumptime_env *denv)
 		}
 				
 		denv->cdumper = sieve_code_dumper_create(denv);
+
+		if ( denv->cdumper == NULL )
+			return FALSE;
+
 		sieve_code_dumper_run(denv->cdumper);
 		sieve_code_dumper_free(&(denv->cdumper));
 	}
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index 19538aad7..a35b31ead 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -478,7 +478,7 @@ bool ext_include_execute_include
 		include_id, sieve_script_name(included->script), block_id);
 
 	if ( ctx->parent == NULL ) {
-		struct ext_include_interpreter_context *curctx;
+		struct ext_include_interpreter_context *curctx = NULL;
 		struct sieve_error_handler *ehandler = 
 			sieve_interpreter_get_error_handler(renv->interp);
 		struct sieve_interpreter *subinterp;
@@ -487,22 +487,29 @@ bool ext_include_execute_include
 
 		/* We are the top-level interpreter instance */	
 
-		/* Create interpreter for top-level included script (first sub-interpreter) 
-		 */
-		subinterp = sieve_interpreter_create
-			(renv->sbin, ehandler, renv->trace_stream);			
-		curctx = ext_include_interpreter_context_init_child
-			(subinterp, ctx, NULL, block_id);
-				
-		/* Activate and start the top-level included script */
-		if ( sieve_binary_block_set_active(renv->sbin, block_id, &this_block_id) ) 			
-			result = ( sieve_interpreter_start
-				(subinterp, renv->msgdata, renv->scriptenv, renv->msgctx, renv->result, 
-					&interrupted) == 1 );
-		else {
+		/* Activate block for included script */
+		if ( !sieve_binary_block_set_active(renv->sbin, block_id, &this_block_id) ) {			
 			sieve_runtime_trace_error(renv, "invalid block id: %d", block_id);
 			result = SIEVE_EXEC_BIN_CORRUPT;
 		}
+
+		if ( result > 0 ) {
+			/* Create interpreter for top-level included script (first sub-interpreter) 
+			 */
+			subinterp = sieve_interpreter_create
+				(renv->sbin, ehandler, renv->trace_stream);
+
+			if ( subinterp != NULL ) {			
+				curctx = ext_include_interpreter_context_init_child
+					(subinterp, ctx, NULL, block_id);
+
+				/* Activate and start the top-level included script */
+				result = ( sieve_interpreter_start
+					(subinterp, renv->msgdata, renv->scriptenv, renv->msgctx, renv->result, 
+						&interrupted) == 1 );
+			} else
+				result = SIEVE_EXEC_BIN_CORRUPT;
+		}
 		
 		/* Included scripts can have includes of their own. This is not implemented
 		 * recursively. Rather, the sub-interpreter interrupts and defers the 
@@ -538,25 +545,31 @@ bool ext_include_execute_include
 						/* FIXME: Check circular include during interpretation as well. 
 						 * Let's not trust user-owned binaries.
 						 */
-						
-						/* Create sub-interpreter */
-						subinterp = sieve_interpreter_create
-							(renv->sbin, ehandler, renv->trace_stream);			
-						curctx = ext_include_interpreter_context_init_child
-							(subinterp, curctx, NULL, curctx->inc_block_id);
 													
 						/* Activate the sub-include's block */
-						if ( sieve_binary_block_set_active
+						if ( !sieve_binary_block_set_active
 							(renv->sbin, curctx->block_id, NULL) ) {
-							/* Start the sub-include's interpreter */
-							curctx->inc_block_id = 0;
-							curctx->returned = FALSE;
-							result = ( sieve_interpreter_start
-								(subinterp, renv->msgdata, renv->scriptenv, renv->msgctx,
-									renv->result, &interrupted) == 1 );		 	
-						} else {
 							sieve_runtime_trace_error(renv, "invalid block id: %d", curctx->block_id);
-					        result = SIEVE_EXEC_BIN_CORRUPT;
+							result = SIEVE_EXEC_BIN_CORRUPT;
+						}
+						
+						if ( result > 0 ) {
+							/* Create sub-interpreter */
+							subinterp = sieve_interpreter_create
+								(renv->sbin, ehandler, renv->trace_stream);			
+
+							if ( subinterp != NULL ) {
+								curctx = ext_include_interpreter_context_init_child
+									(subinterp, curctx, NULL, curctx->inc_block_id);
+
+								/* Start the sub-include's interpreter */
+								curctx->inc_block_id = 0;
+								curctx->returned = FALSE;
+								result = ( sieve_interpreter_start
+									(subinterp, renv->msgdata, renv->scriptenv, renv->msgctx,
+										renv->result, &interrupted) == 1 );		 	
+							} else
+								result = SIEVE_EXEC_BIN_CORRUPT;
 						}
 					} else {
 						/* Sub-interpreter was interrupted outside this extension, probably
diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c
index 082c57db2..ea271fe63 100644
--- a/src/lib-sieve/sieve-ast.c
+++ b/src/lib-sieve/sieve-ast.c
@@ -126,9 +126,19 @@ void sieve_ast_extension_link
 (struct sieve_ast *ast, const struct sieve_extension *ext)
 {
 	int ext_id = *ext->id;
-
+	unsigned int i, ext_count;
+	const struct sieve_extension *const *extensions;
+	
 	if ( ext_id < 0 ) return;
+	 
+	/* Prevent duplicates */
+	extensions = array_get(&ast->linked_extensions, &ext_count);
+	for ( i = 0; i < ext_count; i++ ) {
+		if ( extensions[i] == ext )
+			return;
+	}
 
+	/* Add extension */
 	array_append(&ast->linked_extensions, &ext, 1);	
 }
 
diff --git a/src/lib-sieve/sieve-binary-dumper.c b/src/lib-sieve/sieve-binary-dumper.c
index f5ae28729..43caa79bc 100644
--- a/src/lib-sieve/sieve-binary-dumper.c
+++ b/src/lib-sieve/sieve-binary-dumper.c
@@ -135,9 +135,11 @@ bool sieve_binary_dumper_run
 
 	dumper->dumpenv.cdumper = sieve_code_dumper_create(&(dumper->dumpenv));
 
-	sieve_code_dumper_run(dumper->dumpenv.cdumper);
+	if ( dumper->dumpenv.cdumper != NULL ) {
+		sieve_code_dumper_run(dumper->dumpenv.cdumper);
 		
-	sieve_code_dumper_free(&dumper->dumpenv.cdumper);	
+		sieve_code_dumper_free(&dumper->dumpenv.cdumper);
+	}
 	
 	/* Finish with empty line */
 	sieve_binary_dumpf(denv, "\n");
diff --git a/src/lib-sieve/sieve-code-dumper.c b/src/lib-sieve/sieve-code-dumper.c
index b9ab277b0..4284437e3 100644
--- a/src/lib-sieve/sieve-code-dumper.c
+++ b/src/lib-sieve/sieve-code-dumper.c
@@ -165,10 +165,48 @@ static bool sieve_code_dumper_print_operation
 
 void sieve_code_dumper_run(struct sieve_code_dumper *dumper) 
 {
-	struct sieve_binary *sbin = dumper->dumpenv->sbin;
-	
+	const struct sieve_dumptime_env *denv = dumper->dumpenv;
+	struct sieve_binary *sbin = denv->sbin;
+	unsigned int ext_count;
+	bool success = TRUE;
+
 	dumper->pc = 0;
 	
+	/* Load and dump extensions listed in code */
+	sieve_code_mark(denv);
+	
+	if ( sieve_binary_read_integer(sbin, &dumper->pc, &ext_count) ) {
+		unsigned int i;
+		
+		sieve_code_dumpf(denv, "EXTENSIONS (%d):", ext_count);
+		sieve_code_descend(denv);
+		
+		for ( i = 0; i < ext_count; i++ ) {
+			unsigned int code = 0;
+			const struct sieve_extension *ext;
+			
+			sieve_code_mark(denv);
+			
+			if ( !sieve_binary_read_extension(sbin, &dumper->pc, &code, &ext) ) 
+			{
+        success = FALSE;
+        break;
+      }
+      	
+      sieve_code_dumpf(denv, "%s", ext->name);
+      
+			/* Load ? */ 
+		}
+		
+		sieve_code_ascend(denv);
+	}	else
+		success = FALSE;
+		
+	if ( !success ) {
+		sieve_code_dumpf(denv, "Binary code header is corrupt.");
+		return;
+	}
+	
 	while ( dumper->pc < 
 		sieve_binary_get_code_size(sbin) ) {
 		if ( !sieve_code_dumper_print_operation(dumper) ) {
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index 71443ade5..fb5cf2c93 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -374,14 +374,18 @@ bool sieve_generator_run
 		
 	gentr->genenv.sbin = *sbin;
 		
-	/* Load extensions linked to the AST */
+	/* Load extensions linked to the AST and emit a list in code */
 	extensions = sieve_ast_extensions_get(gentr->genenv.ast, &ext_count);
+	(void) sieve_binary_emit_integer(*sbin, ext_count);
 	for ( i = 0; i < ext_count; i++ ) {
 		const struct sieve_extension *ext = extensions[i];
 
 		/* Link to binary */
 		(void)sieve_binary_extension_link(*sbin, ext);
 	
+		/* Emit */
+		sieve_binary_emit_extension(*sbin, ext, 0);
+	
 		/* Load */
 		if ( ext->generator_load != NULL && !ext->generator_load(&gentr->genenv) )
 			return FALSE;
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index eb8e35073..21988f6ef 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -45,6 +45,8 @@ struct sieve_interpreter {
 
 	/* Runtime data for extensions */
 	ARRAY_DEFINE(extensions, struct sieve_interpreter_extension_reg); 
+	
+	sieve_size_t reset_vector;	
 		
 	/* Execution status */
 	
@@ -66,8 +68,8 @@ struct sieve_interpreter *sieve_interpreter_create
 (struct sieve_binary *sbin, struct sieve_error_handler *ehandler,
 	struct ostream *trace_stream) 
 {
-	unsigned int i;
-	int idx;
+	unsigned int i, ext_count;
+	bool success = TRUE;
 
 	pool_t pool;
 	struct sieve_interpreter *interp;
@@ -97,13 +99,29 @@ struct sieve_interpreter *sieve_interpreter_create
 			(void)ext->interpreter_load(interp);		
 	}
 
-	/* Load other extensions listed in the binary */
-	for ( idx = 0; idx < sieve_binary_extensions_count(sbin); idx++ ) {
-		const struct sieve_extension *ext = 
-			sieve_binary_extension_get_by_index(sbin, idx);
-		
-		if ( ext->interpreter_load != NULL )
-			ext->interpreter_load(interp);
+	/* Load other extensions listed in code */
+	if ( sieve_binary_read_integer(sbin, &interp->pc, &ext_count) ) {
+		for ( i = 0; i < ext_count; i++ ) {
+			unsigned int code = 0;
+			const struct sieve_extension *ext;
+			
+			if ( !sieve_binary_read_extension(sbin, &interp->pc, &code, &ext) ) {
+        success = FALSE;
+        break;
+      }
+ 
+			if ( ext->interpreter_load != NULL && !ext->interpreter_load(interp) ) {
+				success = FALSE;
+				break;
+			}
+		}
+	}	else
+		success = FALSE;
+	
+	if ( !success ) {
+		sieve_interpreter_free(&interp);
+	} else {
+		interp->reset_vector = interp->pc;
 	}
 	
 	return interp;
@@ -291,7 +309,7 @@ void *sieve_interpreter_extension_get_context
 
 void sieve_interpreter_reset(struct sieve_interpreter *interp) 
 {
-	interp->pc = 0;
+	interp->pc = interp->reset_vector;
 	interp->interrupted = FALSE;
 	interp->test_result = FALSE;
 	interp->runenv.msgdata = NULL;
@@ -460,8 +478,8 @@ int sieve_interpreter_start
 	const struct sieve_script_env *senv, struct sieve_message_context *msgctx, 
 	struct sieve_result *result, bool *interrupted) 
 {
-    const struct sieve_interpreter_extension_reg *extrs;
-    unsigned int ext_count, i;
+	const struct sieve_interpreter_extension_reg *extrs;
+	unsigned int ext_count, i;
 	
 	interp->runenv.msgdata = msgdata;
 	interp->runenv.result = result;		
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index 8b4628155..2657cb608 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -241,7 +241,10 @@ int sieve_test
 	struct sieve_interpreter *interp = 
 		sieve_interpreter_create(sbin, ehandler, trace_stream);			
 	int ret = 0;
-							
+		
+	if ( interp == NULL )
+		return SIEVE_EXEC_BIN_CORRUPT;
+					
 	ret = sieve_interpreter_run(interp, msgdata, senv, &sres);
 	
 	if ( ret > 0 ) 
@@ -265,6 +268,9 @@ int sieve_execute
 	struct sieve_interpreter *interp = 
 		sieve_interpreter_create(sbin, ehandler, trace_stream);			
 	int ret = 0;
+
+	if ( interp == NULL )
+		return SIEVE_EXEC_BIN_CORRUPT;
 							
 	ret = sieve_interpreter_run(interp, msgdata, senv, &sres);
 				
diff --git a/src/testsuite/testsuite-common.c b/src/testsuite/testsuite-common.c
index d0a3521e4..c0f563b70 100644
--- a/src/testsuite/testsuite-common.c
+++ b/src/testsuite/testsuite-common.c
@@ -445,6 +445,9 @@ bool testsuite_script_execute(const struct sieve_runtime_env *renv)
 	/* Execute the script */
 	interp=sieve_interpreter_create(_testsuite_compiled_script, test_script_ehandler, NULL);
 	
+	if ( interp == NULL )
+		return SIEVE_EXEC_BIN_CORRUPT;
+		
 	ret = sieve_interpreter_run(interp, renv->msgdata, &scriptenv, &result);
 
 	sieve_interpreter_free(&interp);
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index 16cca8dc7..9695895b5 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -159,18 +159,23 @@ static int testsuite_run
 		
 		interp=sieve_interpreter_create(sbin, ehandler, tstream);
 		
-	    ret = sieve_interpreter_run(interp, &testsuite_msgdata, scriptenv, &sres);
+		if ( interp != NULL ) 
+		    ret = sieve_interpreter_run(interp, &testsuite_msgdata, scriptenv, &sres);
 	
 		o_stream_destroy(&tstream);
 	} else {
 		interp=sieve_interpreter_create(sbin, ehandler, NULL);
 
-	    ret = sieve_interpreter_run(interp, &testsuite_msgdata, scriptenv, &sres);
+		if ( interp != NULL ) 
+		    ret = sieve_interpreter_run(interp, &testsuite_msgdata, scriptenv, &sres);
 	}
 
-	sieve_interpreter_free(&interp);
-	sieve_result_unref(&sres);
+	if ( interp != NULL )
+		sieve_interpreter_free(&interp);
+	else
+		ret = SIEVE_EXEC_BIN_CORRUPT;
 
+	sieve_result_unref(&sres);
 	sieve_error_handler_unref(&ehandler);
 
 	return ret;	
-- 
GitLab