[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