From: Nicolas Williams Date: Sat, 29 Nov 2014 21:24:43 +0000 (-0600) Subject: Fix refcount leak, fix #618 X-Git-Tag: jq-1.5rc1~53 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7243989c52cea7933ace6535eae914c19eb1210a;p=jq Fix refcount leak, fix #618 --- diff --git a/compile.c b/compile.c index a0046ca..50a3d49 100644 --- a/compile.c +++ b/compile.c @@ -643,14 +643,14 @@ block gen_collect(block expr) { return BLOCK(c, gen_op_target(FORK, tail), - expr, + expr, tail, gen_op_bound(LOADVN, array_var)); } block gen_reduce(const char* varname, block source, block init, block body) { block res_var = gen_op_var_fresh(STOREV, "reduce"); - block loop = BLOCK(gen_op_simple(DUP), + block loop = BLOCK(gen_op_simple(DUPN), source, block_bind(gen_op_unbound(STOREV, varname), BLOCK(gen_op_bound(LOADVN, res_var), @@ -669,7 +669,7 @@ block gen_reduce(const char* varname, block source, block init, block body) { block gen_foreach(const char* varname, block source, block init, block update, block extract) { block output = gen_op_targetlater(JUMP); block state_var = gen_op_var_fresh(STOREV, "foreach"); - block loop = BLOCK(gen_op_simple(DUP), + block loop = BLOCK(gen_op_simple(DUPN), // get a value from the source expression: source, // bind the $varname to that value for all the code in diff --git a/execute.c b/execute.c index 1b66770..1cab3ba 100644 --- a/execute.c +++ b/execute.c @@ -168,6 +168,19 @@ jv stack_pop(jq_state *jq) { return val; } +// Like stack_pop(), but assert !stack_pop_will_free() and replace with +// jv_null() on the stack. +jv stack_popn(jq_state *jq) { + jv* sval = stack_block(&jq->stk, jq->stk_top); + jv val = *sval; + if (!stack_pop_will_free(&jq->stk, jq->stk_top)) { + *sval = jv_null(); + } + jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv)); + assert(jv_is_valid(val)); + return val; +} + struct forkpoint { stack_ptr saved_data_stack; @@ -341,6 +354,13 @@ jv jq_next(jq_state *jq) { break; } + case DUPN: { + jv v = stack_popn(jq); + stack_push(jq, jv_copy(v)); + stack_push(jq, v); + break; + } + case DUP2: { jv keep = stack_pop(jq); jv v = stack_pop(jq); @@ -457,7 +477,7 @@ jv jq_next(jq_state *jq) { jv_dump(jv_copy(*var), 0); printf(" (%d)\n", jv_get_refcnt(*var)); } - jv_free(stack_pop(jq)); + jv_free(stack_popn(jq)); stack_push(jq, *var); *var = jv_null(); break; diff --git a/opcode_list.h b/opcode_list.h index db9242f..38e6385 100644 --- a/opcode_list.h +++ b/opcode_list.h @@ -1,5 +1,6 @@ OP(LOADK, CONSTANT, 1, 1) OP(DUP, NONE, 1, 2) +OP(DUPN, NONE, 1, 2) OP(DUP2, NONE, 2, 3) OP(POP, NONE, 1, 0) OP(LOADV, VARIABLE, 1, 1)