]> granicus.if.org Git - jq/commitdiff
Fix refcount leak, fix #618
authorNicolas Williams <nico@cryptonector.com>
Sat, 29 Nov 2014 21:24:43 +0000 (15:24 -0600)
committerNicolas Williams <nico@cryptonector.com>
Sat, 29 Nov 2014 21:24:43 +0000 (15:24 -0600)
compile.c
execute.c
opcode_list.h

index a0046ca0959f097e65c01b93d545e8cab9740571..50a3d49ac4df8de30059eff7d2df6cb2f7d02d33 100644 (file)
--- 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
index 1b66770facbb5b0961264a183d9b52d1430e77f1..1cab3ba0f44b6b1be801ffdac1d9dde7234ca705 100644 (file)
--- 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;
index db9242f964a03a6de55d821d017bdb7fc4fde4fb..38e63856c0863c693b9e1928b7ba8e31c1436d87 100644 (file)
@@ -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)