From ec5cccc7ef98d9abcabec53fc3be30c5eaeeacf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B6r=C3=B6k=20Edvin?= Date: Thu, 9 Jul 2009 23:05:08 +0300 Subject: [PATCH] bytecode: allocate proper stack for functions. --- clambc/bcrun.c | 2 +- libclamav/bytecode.c | 33 ++++++------------- libclamav/bytecode_priv.h | 5 +-- libclamav/bytecode_vm.c | 68 +++++++++++++++++++++++++-------------- 4 files changed, 56 insertions(+), 52 deletions(-) diff --git a/clambc/bcrun.c b/clambc/bcrun.c index db7201cd1..e472f7013 100644 --- a/clambc/bcrun.c +++ b/clambc/bcrun.c @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) uint64_t v; printf("Bytecode run finished\n"); v = cli_bytecode_context_getresult_int(ctx); - printf("Bytecode returned: %llx\n", (long long)v); + printf("Bytecode returned: 0x%llx\n", (long long)v); } cli_bytecode_context_destroy(ctx); cli_bytecode_destroy(bc); diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c index 05ea51d68..ec5d5b00c 100644 --- a/libclamav/bytecode.c +++ b/libclamav/bytecode.c @@ -167,25 +167,23 @@ static inline operand_t readOperand(struct cli_bc_func *func, unsigned char *p, unsigned *off, unsigned len, char *ok) { uint64_t v; - unsigned numValues = func->numArgs + func->numInsts + func->numConstants; if ((p[*off]&0xf0) == 0x40 || p[*off] == 0x50) { p[*off] |= 0x20; /* TODO: unique constants */ - func->values = cli_realloc2(func->values, (numValues+1)*sizeof(*func->values)); - if (!func->values) { + func->constants = cli_realloc2(func->constants, (func->numConstants+1)*sizeof(*func->constants)); + if (!func->constants) { *ok = 0; return MAX_OP; } - func->numConstants++; - func->values[numValues].v = readNumber(p, off, len, ok); - func->values[numValues].ref = CONSTANT_OP; - return numValues; + func->constants[func->numConstants].v = readNumber(p, off, len, ok); + func->constants[func->numConstants].ref = CONSTANT_OP; + return func->numValues + func->numConstants++; } v = readNumber(p, off, len, ok); if (!*ok) return MAX_OP; - if (v >= numValues) { - cli_errmsg("Operand index exceeds bounds: %u >= %u!\n", (unsigned)v, (unsigned)numValues); + if (v >= func->numValues) { + cli_errmsg("Operand index exceeds bounds: %u >= %u!\n", (unsigned)v, (unsigned)func->numValues); *ok = 0; return MAX_OP; } @@ -380,6 +378,7 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *bu cli_errmsg("Invalid instructions count\n"); return CL_EMALFDB; } + func->numValues = func->numArgs + func->numLocals; func->insn_idx = 0; func->numConstants=0; func->allinsts = cli_calloc(func->numInsts, sizeof(*func->allinsts)); @@ -387,19 +386,6 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *bu cli_errmsg("Out of memory allocating instructions\n"); return CL_EMEM; } - func->values = cli_calloc(func->numInsts+func->numArgs, sizeof(*func->values)); - if (!func->values) { - cli_errmsg("Out of memory allocating values\n"); - return CL_EMEM; - } - for (i=0;inumArgs;i++) { - func->values[i].v = 0xdeadbeef; - func->values[i].ref = ARG_OP; - } - for(;inumInsts+func->numArgs;i++) { - func->values[i].v = 0xdeadbeef; - func->values[i].ref = i-func->numArgs; - } func->numBB = readNumber(buffer, &offset, len, &ok); if (!ok) { cli_errmsg("Invalid basic block count\n"); @@ -643,8 +629,8 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx) } } memset(&func, 0, sizeof(func)); - func.values = ctx->values; func.numInsts = 1; + func.numValues = 1; inst.opcode = OP_CALL_DIRECT; inst.dest = func.numArgs; @@ -680,7 +666,6 @@ void cli_bytecode_destroy(struct cli_bc *bc) } free(f->BB); free(f->allinsts); - free(f->values); } free(bc->funcs); } diff --git a/libclamav/bytecode_priv.h b/libclamav/bytecode_priv.h index 479739b48..b8c5d5c2f 100644 --- a/libclamav/bytecode_priv.h +++ b/libclamav/bytecode_priv.h @@ -74,13 +74,14 @@ struct cli_bc_func { uint8_t numArgs; uint16_t numLocals; uint32_t numInsts; + uint32_t numValues;//without constants uint32_t numConstants; uint16_t numBB; uint16_t *types; uint32_t insn_idx; struct cli_bc_bb *BB; struct cli_bc_inst *allinsts; - struct cli_bc_value *values; + struct cli_bc_value *constants; }; struct cli_bc_ctx { @@ -93,5 +94,5 @@ struct cli_bc_ctx { unsigned numParams; }; -int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst); +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); #endif diff --git a/libclamav/bytecode_vm.c b/libclamav/bytecode_vm.c index 214c34567..688a5a803 100644 --- a/libclamav/bytecode_vm.c +++ b/libclamav/bytecode_vm.c @@ -32,18 +32,18 @@ /* These checks will also be done by the bytecode verifier, but for * debugging purposes we have explicit checks, these should never fail! */ #ifdef CL_DEBUG -static int bcfail(const char *msg, unsigned a, unsigned b, +static int bcfail(const char *msg, long a, long b, const char *file, unsigned line) { - cli_errmsg("bytecode: check failed %s (%u and %u) at %s:%u\n", msg, a, b, file, line); + cli_errmsg("bytecode: check failed %s (%lx and %lx) at %s:%u\n", msg, a, b, file, line); return CL_EARG; } #define CHECK_FUNCID(funcid) do { if (funcid >= bc->num_func) return \ bcfail("funcid out of bounds!",funcid, bc->num_func,__FILE__,__LINE__); } while(0) -#define CHECK_EQ(a, b) do { if (a != b) return \ - bcfail("Values "#a" and "#b" don't match!",a,b,__FILE__,__LINE__); } while(0) -#define CHECK_GT(a, b) do {if (a <= b) return \ - bcfail("Condition failed "#a" > "#b,a,b, __FILE__, __LINE__); } while(0) +#define CHECK_EQ(a, b) do { if ((a) != (b)) return \ + bcfail("Values "#a" and "#b" don't match!",(a),(b),__FILE__,__LINE__); } while(0) +#define CHECK_GT(a, b) do {if ((a) <= (b)) return \ + bcfail("Condition failed "#a" > "#b,(a),(b), __FILE__, __LINE__); } while(0) #else #define CHECK_FUNCID(x) #define CHECK_EQ(a,b) @@ -51,8 +51,9 @@ static int bcfail(const char *msg, unsigned a, unsigned b, #endif struct stack_entry { - struct cli_bc_func *func; + const struct cli_bc_func *func; struct cli_bc_value *ret; + struct cli_bc_value *values; struct cli_bc_bb *bb; unsigned bb_inst; }; @@ -79,28 +80,39 @@ struct stack_entry { #define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type)) #define BINOPS(i) SIGNEXT(BINOPNOMOD(i)) -static void jump(struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, struct cli_bc_inst **inst, - struct cli_bc_value **value, unsigned *bb_inst) +static 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); *bb = &func->BB[bbid]; *inst = (*bb)->insts; - *value = &func->values[*inst - func->allinsts]; *bb_inst = 0; + return 0; } -int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst) +static struct cli_bc_value *allocate_stack(const struct cli_bc_func *func) +{ + unsigned i; + struct cli_bc_value *values = cli_calloc(func->numValues+func->numConstants, sizeof(*values)); + if (!values) + return NULL; + for (i=func->numValues;inumValues+func->numConstants;i++) + values[i] = func->constants[i-func->numValues]; + return values; +} + +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; struct cli_bc_func *func2; struct stack_entry *stack = NULL; struct cli_bc_bb *bb = NULL; - struct cli_bc_value *values = func->values; - struct cli_bc_value *value; + struct cli_bc_value *values = ctx->values; + struct cli_bc_value *value, *old_values; do { value = &values[inst->dest]; - CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value); + CHECK_GT(func->numValues+func->numConstants, value - values); switch (inst->opcode) { case OP_ADD: value->v = BINOPNOMOD(0) + BINOPNOMOD(1); @@ -175,22 +187,23 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func value->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v; break; case OP_BRANCH: - jump(func, (values[inst->u.branch.condition].v&1) ? - inst->u.branch.br_true : inst->u.branch.br_false, - &bb, &inst, &value, &bb_inst); + stop = jump(func, (values[inst->u.branch.condition].v&1) ? + inst->u.branch.br_true : inst->u.branch.br_false, + &bb, &inst, &bb_inst); continue; case OP_JMP: - jump(func, inst->u.jump, &bb, &inst, &value, &bb_inst); + stop = jump(func, inst->u.jump, &bb, &inst, &bb_inst); continue; case OP_RET: CHECK_GT(stack_depth, 0); stack_depth--; value = stack[stack_depth].ret; func = stack[stack_depth].func; - CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value); - CHECK_GT(value, &func->values[-1]); value->v = values[inst->u.unaryop].v; - values = func->values; + free(values); + values = stack[stack_depth].values; + CHECK_GT(func->numValues+func->numConstants, value-values); + CHECK_GT(value-values, -1); if (!stack[stack_depth].bb) { stop = CL_BREAK; bb_inst--; @@ -238,8 +251,6 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func CHECK_FUNCID(inst->u.ops.funcid); func2 = &bc->funcs[inst->u.ops.funcid]; CHECK_EQ(func2->numArgs, inst->u.ops.numOps); - for (i=0;inumArgs;i++) - func2->values[i] = func->values[inst->u.ops.ops[i]]; stack = cli_realloc2(stack, sizeof(*stack)*(stack_depth+1)); if (!stack) return CL_EMEM; @@ -247,12 +258,18 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func stack[stack_depth].ret = value; stack[stack_depth].bb = bb; stack[stack_depth].bb_inst = bb_inst; + stack[stack_depth].values = values; stack_depth++; cli_dbgmsg("Executing %d\n", inst->u.ops.funcid); + old_values = values; + values = allocate_stack(func2); + if (!values) + return CL_EMEM; + for (i=0;inumArgs;i++) + values[i] = old_values[inst->u.ops.ops[i]]; func = func2; - values = func->values; CHECK_GT(func->numBB, 0); - jump(func, 0, &bb, &inst, &value, &bb_inst); + stop = jump(func, 0, &bb, &inst, &bb_inst); continue; case OP_COPY: BINOPNOMOD(1) = BINOPNOMOD(0); @@ -260,6 +277,7 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func default: cli_errmsg("Opcode %u is not implemented yet!\n", inst->opcode); stop = CL_EARG; + break; } bb_inst++; inst++;