Fix undefined behaviour around system_allocator, issue #133.

This commit is contained in:
Meredith L. Patterson 2015-08-02 21:32:47 +02:00
parent 0653a9e48a
commit 1ffd8d9276
12 changed files with 104 additions and 25 deletions

View file

@ -18,6 +18,7 @@ struct HCFStack_ {
HCFChoice *last_completed; // Last completed choice.
// XXX is last_completed still needed?
HCFChoice *prealloc; // If not NULL, will be used for the outermost choice.
char error;
};
#ifndef UNUSED
@ -33,6 +34,7 @@ static HCFStack* h_cfstack_new(HAllocator *mm__) {
stack->cap = 4;
stack->stack = h_new(HCFChoice*, stack->cap);
stack->prealloc = NULL;
stack->error = 0;
return stack;
}
@ -55,8 +57,12 @@ static inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFCh
for (int j = 0;; j++) {
if (cur_top->seq[i]->items[j] == NULL) {
cur_top->seq[i]->items = mm__->realloc(mm__, cur_top->seq[i]->items, sizeof(HCFChoice*) * (j+2));
if (!cur_top->seq[i]->items) {
stk__->error = 1;
}
cur_top->seq[i]->items[j] = item;
cur_top->seq[i]->items[j+1] = NULL;
assert(!stk__->error);
return;
}
}
@ -111,8 +117,11 @@ static inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) {
assert(stk__->cap > 0);
stk__->cap *= 2;
stk__->stack = mm__->realloc(mm__, stk__->stack, stk__->cap * sizeof(HCFChoice*));
if (!stk__->stack) {
stk__->error = 1;
}
}
assert(stk__->cap >= 1);
assert(stk__->cap >= 1 && !stk__->error);
stk__->stack[stk__->count++] = choice;
}
@ -121,6 +130,10 @@ static inline void h_cfstack_begin_seq(HAllocator *mm__, HCFStack *stk__) {
for (int i = 0;; i++) {
if (top->seq[i] == NULL) {
top->seq = mm__->realloc(mm__, top->seq, sizeof(HCFSequence*) * (i+2));
if (!top->seq) {
stk__->error = 1;
return;
}
HCFSequence *seq = top->seq[i] = h_new(HCFSequence, 1);
top->seq[i+1] = NULL;
seq->items = h_new(HCFChoice*, 1);

View file

@ -187,7 +187,9 @@ void* h_rvm_run__m(HAllocator *mm__, HRVMProg *prog, const uint8_t* input, size_
void svm_stack_ensure_cap(HAllocator *mm__, HSVMContext *ctx, size_t addl) {
if (ctx->stack_count + addl >= ctx->stack_capacity) {
ctx->stack = mm__->realloc(mm__, ctx->stack, sizeof(*ctx->stack) * (ctx->stack_capacity *= 2));
// TODO: check for realloc failure
if (!ctx->stack) {
ctx->error = 1;
}
}
}
@ -197,6 +199,7 @@ HParseResult *run_trace(HAllocator *mm__, HRVMProg *orig_prog, HRVMTrace *trace,
HArena *arena = h_new_arena(mm__, 0);
ctx.stack_count = 0;
ctx.stack_capacity = 16;
ctx.error = 0;
ctx.stack = h_new(HParsedToken*, ctx.stack_capacity);
HParsedToken *tmp_res;
@ -205,6 +208,9 @@ HParseResult *run_trace(HAllocator *mm__, HRVMProg *orig_prog, HRVMTrace *trace,
switch (cur->opcode) {
case SVM_PUSH:
svm_stack_ensure_cap(mm__, &ctx, 1);
if (ctx.error) {
goto fail;
}
tmp_res = a_new(HParsedToken, 1);
tmp_res->token_type = TT_MARK;
tmp_res->index = cur->input_pos;
@ -264,7 +270,9 @@ uint16_t h_rvm_create_action(HRVMProg *prog, HSVMActionFunc action_func, void* e
size_t array_size = (prog->action_count + 1) * 2; // action_count+1 is a
// power of two
prog->actions = prog->allocator->realloc(prog->allocator, prog->actions, array_size * sizeof(*prog->actions));
// TODO: Handle the allocation failed case nicely.
if (!prog->actions) {
longjmp(prog->except, 1);
}
}
HSVMAction *action = &prog->actions[prog->action_count];
@ -280,7 +288,9 @@ uint16_t h_rvm_insert_insn(HRVMProg *prog, HRVMOp op, uint16_t arg) {
size_t array_size = (prog->length + 1) * 2; // action_count+1 is a
// power of two
prog->insns = prog->allocator->realloc(prog->allocator, prog->insns, array_size * sizeof(*prog->insns));
// TODO: Handle the allocation failed case nicely.
if (!prog->insns) {
longjmp(prog->except, 1);
}
}
prog->insns[prog->length].op = op;
@ -338,7 +348,12 @@ bool h_svm_action_clear_to_mark(HArena *arena, HSVMContext *ctx, void* env) {
// Glue regex backend to rest of system
bool h_compile_regex(HRVMProg *prog, const HParser *parser) {
return parser->vtable->compile_to_rvm(prog, parser->env);
if (setjmp(prog->except)) {
return false;
}
bool ret = parser->vtable->compile_to_rvm(prog, parser->env);
memset(prog->except, 0, sizeof(prog->except));
return ret;
}
static void h_regex_free(HParser *parser) {

View file

@ -7,6 +7,8 @@
#ifndef HAMMER_BACKEND_REGEX__H
#define HAMMER_BACKEND_REGEX__H
#include <setjmp.h>
// each insn is an 8-bit opcode and a 16-bit parameter
// [a] are actions; they add an instruction to the stackvm that is being output.
// [m] are match ops; they can either succeed or fail, depending on the current character
@ -41,6 +43,7 @@ typedef struct HSVMContext_ {
HParsedToken **stack;
size_t stack_count; // number of items on the stack. Thus stack[stack_count] is the first unused item on the stack.
size_t stack_capacity;
char error;
} HSVMContext;
// These actions all assume that the items on the stack are not
@ -57,6 +60,7 @@ struct HRVMProg_ {
size_t action_count;
HRVMInsn *insns;
HSVMAction *actions;
jmp_buf except;
};
// Returns true IFF the provided parser could be compiled.

View file

@ -59,7 +59,7 @@ void dump_rvm_prog(HRVMProg *prog) {
symref = getsym(prog->actions[insn->arg].action);
// TODO: somehow format the argument to action
printf("%s\n", symref);
free(symref);
(&system_allocator)->free(&system_allocator, symref);
break;
case RVM_MATCH: {
uint8_t low, high;
@ -95,7 +95,7 @@ void dump_svm_prog(HRVMProg *prog, HRVMTrace *trace) {
symref = getsym(prog->actions[trace->arg].action);
// TODO: somehow format the argument to action
printf("%s\n", symref);
free(symref);
(&system_allocator)->free(&system_allocator, symref);
break;
default:
printf("\n");