[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b

Török Edvin edwin at clamav.net
Sun Apr 4 00:58:23 UTC 2010


The following commit has been merged in the debian/unstable branch:
commit cfec3d90cec98697fb5a71346c15d09f79826b00
Author: Török Edvin <edwin at clamav.net>
Date:   Mon Jul 13 19:34:03 2009 +0300

    bytecode: fix handling of cast and icmp opcodes, improve stack handling.

diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c
index a97cf8c..70caf89 100644
--- a/libclamav/bytecode.c
+++ b/libclamav/bytecode.c
@@ -481,10 +481,12 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
 	    case OP_SEXT:
 	    case OP_TRUNC:
 		inst.u.cast.source = readOperand(bcfunc, buffer, &offset, len, &ok);
-		if (ok) {
-		    /* calculate mask */
-		    inst.u.cast.mask = (1<<bcfunc->allinsts[inst.u.cast.source].type)-1;
-		}
+		inst.u.cast.mask = bcfunc->types[inst.u.cast.source];
+		/* calculate mask */
+		if (inst.opcode != OP_SEXT)
+		    inst.u.cast.mask = inst.u.cast.mask != 64 ?
+			(1ull<<inst.u.cast.mask)-1 :
+			~0ull;
 		break;
 	    default:
 		numOp = operand_counts[inst.opcode];
@@ -528,7 +530,7 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
 	    case OP_ICMP_SGE:
 	    case OP_ICMP_SLE:
 	    case OP_ICMP_SLT:
-		inst.type = bcfunc->allinsts[inst.u.binop[0]].type;
+		inst.type = bcfunc->types[inst.u.binop[0]];
 		break;
 	}
 	BB->insts[BB->numInsts++] = inst;
@@ -540,7 +542,6 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
 	}
 	offset++;
     }
-    cli_dbgmsg("Parsed %d instructions\n", BB->numInsts);
     if (offset != len) {
 	cli_errmsg("Trailing garbage in basicblock: %d extra bytes\n",
 		   len-offset);
@@ -598,6 +599,8 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio)
 		    return rc;
 		}
 		if (bb >= bc->funcs[current_func].numBB) {
+		    cli_dbgmsg("Parsed %u BBs, %u instructions\n",
+			       bb, bc->funcs[current_func].numInsts);
 		    state = PARSE_FUNC_HEADER;
 		    current_func++;
 		}
diff --git a/libclamav/bytecode_vm.c b/libclamav/bytecode_vm.c
index 1c14ab3..65b0ea7 100644
--- a/libclamav/bytecode_vm.c
+++ b/libclamav/bytecode_vm.c
@@ -50,15 +50,6 @@ static int bcfail(const char *msg, long a, long b,
 #define CHECK_GT(a,b)
 #endif
 
-struct stack_entry {
-    const struct cli_bc_func *func;
-    struct cli_bc_value *ret;
-    struct cli_bc_value *values;
-    struct cli_bc_bb *bb;
-    unsigned bb_inst;
-};
-
-
 /* Get the operand of a binary operator, upper bits
  * (beyond the size of the operand) may have random values.
  * Use this when the active bits of the result of a binop are the same
@@ -70,17 +61,23 @@ struct stack_entry {
 #define UNOPNOMOD(i) (values[inst->u.binop[i]].v)
 
 /* get the operand of a binary operator, upper bits are cleared */
-#define BINOP(i) (BINOPNOMOD(i)&((1 << inst->type)-1))
-#define UNOP(x) (UNOPNOMOD(i)&((1 << inst->type)-1))
+#define type2mask(t) (inst->type == 64 ? ~0ull : (1ull << inst->type)-1)
+#define BINOP(i) (BINOPNOMOD(i)&type2mask(inst->type))
+#define UNOP(x) (UNOPNOMOD(i)&typemask(inst->type))
 
 /* get the operand as a signed value.
  * Warning: this assumes that result type is same as operand type.
  * This is usually true, except for icmp_* and select.
  * For icmp_* we fix it up in the loader. */
-#define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type))
-#define BINOPS(i) SIGNEXT(BINOPNOMOD(i))
+#define SIGNEXT(a, from) CLI_SRS(((int64_t)(a)) << (64-(from)), (64-(from)))
+#define BINOPS(i) SIGNEXT(BINOPNOMOD(i), inst->type)
+
+#define CASTOP (values[inst->u.cast.source].v& inst->u.cast.mask)
 
-static int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
+#undef always_inline
+#define always_inline
+
+static always_inline int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
 		unsigned *bb_inst)
 {
     CHECK_GT(func->numBB, bbid);
@@ -90,26 +87,164 @@ static int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb
     return 0;
 }
 
-static struct cli_bc_value *allocate_stack(const struct cli_bc_func *func)
+#define STACK_CHUNKSIZE 16384
+
+struct stack_chunk {
+    struct stack_chunk *prev;
+    unsigned used;
+    union {
+	void *align;
+	char data[STACK_CHUNKSIZE];
+    } u;
+};
+
+struct stack {
+    struct stack_chunk* chunk;
+    uint16_t last_size;
+};
+
+static always_inline void* cli_stack_alloc(struct stack *stack, unsigned bytes)
+{
+    struct stack_chunk *chunk = stack->chunk;
+    uint16_t last_size_off;
+
+    /* last_size is stored after data */
+    /* align bytes to pointer size */
+    bytes = (bytes + sizeof(uint16_t) + sizeof(void*)) & ~(sizeof(void*)-1);
+    last_size_off = bytes - 2;
+
+    if (chunk && (chunk->used + bytes <= STACK_CHUNKSIZE)) {
+	/* there is still room in this chunk */
+	void *ret;
+
+	*(uint16_t*)&chunk->u.data[chunk->used + last_size_off] = stack->last_size;
+	stack->last_size = bytes/sizeof(void*);
+
+	ret = chunk->u.data + chunk->used;
+	chunk->used += bytes;
+	return ret;
+    }
+
+    if(bytes >= STACK_CHUNKSIZE) {
+	cli_errmsg("cli_stack_alloc: Attempt to allocate more than STACK_CHUNKSIZE bytes!\n");
+	return NULL;
+    }
+    /* not enough room here, allocate new chunk */
+    chunk = cli_malloc(sizeof(*stack->chunk));
+    if (!chunk)
+	return NULL;
+
+    *(uint16_t*)&chunk->u.data[last_size_off] = stack->last_size;
+    stack->last_size = bytes/sizeof(void*);
+
+    chunk->used = bytes;
+    chunk->prev = stack->chunk;
+    stack->chunk = chunk;
+    return chunk->u.data;
+}
+
+static always_inline void cli_stack_free(struct stack *stack, void *data)
+{
+    uint16_t last_size;
+    struct stack_chunk *chunk = stack->chunk;
+    if (!chunk) {
+	cli_errmsg("cli_stack_free: stack empty!\n");
+	return;
+    }
+    if ((chunk->u.data + chunk->used) != ((char*)data + stack->last_size*sizeof(void*))) {
+	cli_errmsg("cli_stack_free: wrong free order: %p, expected %p\n",
+		   data, chunk->u.data + chunk->used - stack->last_size*sizeof(void*));
+	return;
+    }
+    last_size = *(uint16_t*)&chunk->u.data[chunk->used-2];
+    if (chunk->used < stack->last_size*sizeof(void*)) {
+	cli_errmsg("cli_stack_free: last_size is corrupt!\n");
+	return;
+    }
+    chunk->used -= stack->last_size*sizeof(void*);
+    stack->last_size = last_size;
+    if (!chunk->used) {
+	stack->chunk = chunk->prev;
+	free(chunk);
+    }
+}
+
+static void cli_stack_destroy(struct stack *stack)
+{
+    struct stack_chunk *chunk = stack->chunk;
+    while (chunk) {
+	stack->chunk = chunk->prev;
+	free(chunk);
+	chunk = stack->chunk;
+    }
+}
+
+struct stack_entry {
+    struct stack_entry *prev;
+    const struct cli_bc_func *func;
+    struct cli_bc_value *ret;
+    struct cli_bc_bb *bb;
+    unsigned bb_inst;
+    struct cli_bc_value *values;
+};
+
+static always_inline struct stack_entry *allocate_stack(struct stack *stack,
+							struct stack_entry *prev,
+							const struct cli_bc_func *func,
+							const struct cli_bc_func *func_old,
+							struct cli_bc_value *ret,
+							struct cli_bc_bb *bb,
+							unsigned bb_inst)
 {
     unsigned i;
-    struct cli_bc_value *values = cli_malloc((func->numValues+func->numConstants)*sizeof(*values));
-    if (!values)
+    struct cli_bc_value *values;
+    const unsigned numValues = func->numValues + func->numConstants;
+    struct stack_entry *entry = cli_stack_alloc(stack, sizeof(*entry) + sizeof(*values)*numValues);
+    if (!entry)
 	return NULL;
-    for (i=func->numValues;i<func->numValues+func->numConstants;i++)
-	values[i] = func->constants[i-func->numValues];
-    return values;
+    entry->prev = prev;
+    entry->func = func_old;
+    entry->ret = ret;
+    entry->bb = bb;
+    entry->bb_inst = bb_inst;
+    /* we allocated room for values right after stack_entry! */
+    entry->values = values = (struct cli_bc_value*)&entry[1];
+
+    memcpy(&values[func->numValues], func->constants,
+	   sizeof(*values)*func->numConstants);
+    return entry;
+}
+
+static always_inline struct stack_entry *pop_stack(struct stack *stack,
+						   struct stack_entry *stack_entry,
+						   const struct cli_bc_func **func,
+						   struct cli_bc_value **ret,
+						   struct cli_bc_bb **bb,
+						   unsigned *bb_inst)
+{
+    void *data;
+    *func = stack_entry->func;
+    *ret = stack_entry->ret;
+    *bb = stack_entry->bb;
+    *bb_inst = stack_entry->bb_inst;
+    data = stack_entry;
+    stack_entry = stack_entry->prev;
+    cli_stack_free(stack, data);
+    return stack_entry;
 }
 
 int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
 {
-    unsigned i, stack_depth=0, bb_inst=0, stop=0, stack_max_depth=0;
+    uint64_t tmp;
+    unsigned i, stack_depth=0, bb_inst=0, stop=0 ;
     struct cli_bc_func *func2;
-    struct stack_entry *stack = NULL;
+    struct stack stack;
+    struct stack_entry *stack_entry = NULL;
     struct cli_bc_bb *bb = NULL;
     struct cli_bc_value *values = ctx->values;
     struct cli_bc_value *value, *old_values;
 
+    memset(&stack, 0, sizeof(stack));
     do {
 	value = &values[inst->dest];
 	CHECK_GT(func->numValues+func->numConstants, value - values);
@@ -126,8 +261,10 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 	    case OP_UDIV:
 		{
 		    uint64_t d = BINOP(1);
-		    if (UNLIKELY(!d))
+		    if (UNLIKELY(!d)) {
+			cli_dbgmsg("bytecode attempted to execute udiv#0\n");
 			return CL_EBYTECODE;
+		    }
 		    value->v = BINOP(0) / d;
 		    break;
 		}
@@ -135,16 +272,20 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 		{
 		    int64_t a = BINOPS(0);
 		    int64_t b = BINOPS(1);
-		    if (UNLIKELY(b == 0 || (b == -1 && a == (-9223372036854775807LL-1LL))))
+		    if (UNLIKELY(b == 0 || (b == -1 && a == (-9223372036854775807LL-1LL)))) {
+			cli_dbgmsg("bytecode attempted to execute sdiv#0\n");
 			return CL_EBYTECODE;
+		    }
 		    value->v = a / b;
 		    break;
 		}
 	    case OP_UREM:
 		{
 		    uint64_t d = BINOP(1);
-		    if (UNLIKELY(!d))
+		    if (UNLIKELY(!d)) {
+			cli_dbgmsg("bytecode attempted to execute urem#0\n");
 			return CL_EBYTECODE;
+		    }
 		    value->v = BINOP(0) % d;
 		    break;
 		}
@@ -152,8 +293,10 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 		{
 		    int64_t a = BINOPS(0);
 		    int64_t b = BINOPS(1);
-		    if (UNLIKELY(b == 0 || (b == -1 && (a == -9223372036854775807LL-1LL))))
+		    if (UNLIKELY(b == 0 || (b == -1 && (a == -9223372036854775807LL-1LL)))) {
+			cli_dbgmsg("bytecode attempted to execute srem#0\n");
 			return CL_EBYTECODE;
+		    }
 		    value->v = a % b;
 		    break;
 		}
@@ -179,12 +322,13 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 		value->v = BINOPNOMOD(0) ^ BINOPNOMOD(1);
 		break;
 	    case OP_SEXT:
-		value->v = SIGNEXT(values[inst->u.cast.source].v);
+		/* mask is number of src bits here, not a mask! */
+		value->v = SIGNEXT(values[inst->u.cast.source].v, inst->u.cast.mask);
 		break;
 	    case OP_TRUNC:
 		/* fall-through */
 	    case OP_ZEXT:
-		value->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v;
+		value->v = CASTOP;
 		break;
 	    case OP_BRANCH:
 		stop = jump(func, (values[inst->u.branch.condition].v&1) ?
@@ -196,31 +340,13 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 		continue;
 	    case OP_RET:
 		CHECK_GT(stack_depth, 0);
-		stack_depth--;
-		value = stack[stack_depth].ret;
-		func = stack[stack_depth].func;
-		value->v = values[inst->u.unaryop].v;
-		old_values = values;
-		values = stack[stack_depth].values;
-		stack[stack_depth].values = old_values;
+		tmp = values[inst->u.unaryop].v;
+		stack_entry = pop_stack(&stack, stack_entry, &func, &value, &bb,
+					&bb_inst);
+		values = stack_entry ? stack_entry->values : ctx->values;
 		CHECK_GT(func->numValues+func->numConstants, value-values);
 		CHECK_GT(value-values, -1);
-		bb = stack[stack_depth].bb;
-		bb_inst = stack[stack_depth].bb_inst;
-		if ((stack_depth < stack_max_depth*3/4) || !stack_depth) {
-		    for (i=stack_depth;i<stack_max_depth;i++) {
-			free(stack[i].values);
-		    }
-		    if (!stack_depth) {
-			free(stack);
-			stack = 0;
-		    } else {
-			stack = cli_realloc2(stack, sizeof(*stack)*stack_depth);
-			if (!stack)
-			    return CL_EMEM;
-		    }
-		    stack_max_depth = stack_depth;
-		}
+		value->v = tmp;
 		if (!bb) {
 		    stop = CL_BREAK;
 		    continue;
@@ -266,29 +392,16 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 		func2 = &bc->funcs[inst->u.ops.funcid];
 		CHECK_EQ(func2->numArgs, inst->u.ops.numOps);
 		old_values = values;
-		if (stack_depth+1 > stack_max_depth) {
-		    stack = cli_realloc2(stack, sizeof(*stack)*(stack_depth+1));
-		    if (!stack)
-			return CL_EMEM;
-		    stack_max_depth = stack_depth+1;
-		    values = allocate_stack(func2);
-		    if (!values)
-			return CL_EMEM;
-		} else {
-		    values = stack[stack_depth].values;
-		}
-		stack[stack_depth].func = func;
-		stack[stack_depth].ret = value;
-		stack[stack_depth].bb = bb;
-		stack[stack_depth].bb_inst = bb_inst;
-		stack[stack_depth].values = old_values;
-		stack_depth++;
-//cli_dbgmsg("Executing %d\n", inst->u.ops.funcid);
+		stack_entry = allocate_stack(&stack, stack_entry, func2, func, value,
+					     bb, bb_inst);
+		values = stack_entry->values;
+//		cli_dbgmsg("Executing %d\n", inst->u.ops.funcid);
 		for (i=0;i<func2->numArgs;i++)
 		    values[i] = old_values[inst->u.ops.ops[i]];
 		func = func2;
 		CHECK_GT(func->numBB, 0);
 		stop = jump(func, 0, &bb, &inst, &bb_inst);
+		stack_depth++;
 		continue;
 	    case OP_COPY:
 		BINOPNOMOD(1) = BINOPNOMOD(0);
@@ -303,6 +416,6 @@ int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct
 	CHECK_GT(bb->numInsts, bb_inst);
     } while (stop == CL_SUCCESS);
 
-    free(stack);
+    cli_stack_destroy(&stack);
     return stop == CL_BREAK ? CL_SUCCESS : stop;
 }
diff --git a/libclamav/others.h b/libclamav/others.h
index 417043a..b5a140c 100644
--- a/libclamav/others.h
+++ b/libclamav/others.h
@@ -351,6 +351,12 @@ void cli_errmsg(const char *str, ...);
 #define UNLIKELY(cond) (cond)
 #endif
 
+#ifdef __GNUC__
+#define always_inline inline __attribute__((always_inline))
+#else
+#define always_inline inline
+#endif
+
 #define cli_dbgmsg (!UNLIKELY(cli_debug_flag)) ? (void)0 : cli_dbgmsg_internal
 
 #ifdef __GNUC__

-- 
Debian repository for ClamAV



More information about the Pkg-clamav-commits mailing list