diff --git a/src/backends/regex.c b/src/backends/regex.c index f7dd98add85844366cca53aa96be31c596b4221c..9646ddd59343cacbd1cc53645161c88d70c15f78 100644 --- a/src/backends/regex.c +++ b/src/backends/regex.c @@ -206,16 +206,43 @@ bool svm_stack_ensure_cap(HAllocator *mm__, HSVMContext *ctx, size_t addl) { return true; } +/* + * GCC produces the following diagnostic on this function: + * + * error: argument 'trace' might be clobbered by 'longjmp' or 'vfork' [-Werror=clobbered] + * + * However, this is spurious; what is happening is that the trace + * argument gets reused to store cur, and GCC doesn't know enough + * about setjmp to know that the second return only returns nonzero + * (and therefore the now-clobbered value of trace is invalid.) + * + * A side effect of disabling this warning is that we need to be + * careful about undefined behaviour involving automatic + * variables. Specifically, any automatic variable in this function + * whose value gets modified after setjmp has an undefined value after + * the second return; here, the only variables that could matter for + * are arena and ctx (because they're referenced in "goto fail"). + */ +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wclobbered" +#endif HParseResult *run_trace(HAllocator *mm__, HRVMProg *orig_prog, HRVMTrace *trace, const uint8_t *input, int len) { // orig_prog is only used for the action table - HSVMContext ctx; + HSVMContext *ctx = NULL; HArena *arena = h_new_arena(mm__, 0); - ctx.stack_count = 0; - ctx.stack_capacity = 16; - ctx.stack = h_new(HParsedToken*, ctx.stack_capacity); + if (arena == NULL) { + return NULL; + } + ctx = h_new(HSVMContext, 1); + if (!ctx) goto fail; + ctx->stack_count = 0; + ctx->stack_capacity = 16; + ctx->stack = h_new(HParsedToken*, ctx->stack_capacity); // out of memory handling - if(!arena || !ctx.stack) + if(!arena || !ctx->stack) goto fail; jmp_buf except; h_arena_set_except(arena, &except); @@ -227,20 +254,20 @@ HParseResult *run_trace(HAllocator *mm__, HRVMProg *orig_prog, HRVMTrace *trace, for (cur = trace; cur; cur = cur->next) { switch (cur->opcode) { case SVM_PUSH: - if (!svm_stack_ensure_cap(mm__, &ctx, 1)) { + if (!svm_stack_ensure_cap(mm__, ctx, 1)) { goto fail; } tmp_res = a_new(HParsedToken, 1); tmp_res->token_type = TT_MARK; tmp_res->index = cur->input_pos; tmp_res->bit_offset = 0; - ctx.stack[ctx.stack_count++] = tmp_res; + ctx->stack[ctx->stack_count++] = tmp_res; break; case SVM_NOP: break; case SVM_ACTION: // Action should modify stack appropriately - if (!orig_prog->actions[cur->arg].action(arena, &ctx, orig_prog->actions[cur->arg].env)) { + if (!orig_prog->actions[cur->arg].action(arena, ctx, orig_prog->actions[cur->arg].env)) { // action failed... abort somehow goto fail; @@ -249,9 +276,9 @@ HParseResult *run_trace(HAllocator *mm__, HRVMProg *orig_prog, HRVMTrace *trace, case SVM_CAPTURE: // Top of stack must be a mark // This replaces said mark in-place with a TT_BYTES. - assert(ctx.stack[ctx.stack_count-1]->token_type == TT_MARK); + assert(ctx->stack[ctx->stack_count-1]->token_type == TT_MARK); - tmp_res = ctx.stack[ctx.stack_count-1]; + tmp_res = ctx->stack[ctx->stack_count-1]; tmp_res->token_type = TT_BYTES; // TODO: Will need to copy if bit_offset is nonzero assert(tmp_res->bit_offset == 0); @@ -260,25 +287,33 @@ HParseResult *run_trace(HAllocator *mm__, HRVMProg *orig_prog, HRVMTrace *trace, tmp_res->bytes.len = cur->input_pos - tmp_res->index; break; case SVM_ACCEPT: - assert(ctx.stack_count <= 1); + assert(ctx->stack_count <= 1); HParseResult *res = a_new(HParseResult, 1); - if (ctx.stack_count == 1) { - res->ast = ctx.stack[0]; + if (ctx->stack_count == 1) { + res->ast = ctx->stack[0]; } else { res->ast = NULL; } res->bit_length = cur->input_pos * 8; res->arena = arena; h_arena_set_except(arena, NULL); - h_free(ctx.stack); + h_free(ctx->stack); + h_free(ctx); return res; } } fail: if (arena) h_delete_arena(arena); - if (ctx.stack) h_free(ctx.stack); + if (ctx) { + if (ctx->stack) h_free(ctx->stack); + h_free(ctx); + } return NULL; } +// Reenable -Wclobber +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif uint16_t h_rvm_create_action(HRVMProg *prog, HSVMActionFunc action_func, void* env) { for (uint16_t i = 0; i < prog->action_count; i++) {