From ca1d8df06cdead8f9de1ba81d1de8cda363c16b4 Mon Sep 17 00:00:00 2001
From: "Sven M. Hallberg" <pesco@khjk.org>
Date: Mon, 30 Nov 2015 14:19:40 +0100
Subject: [PATCH] don't allocate a new arena in h_bind, use the existing one

Rationale: If memory allocation fails in the inner parse and we
longjump up the stack, the temporary arena will be missed and leak.

NB: This change means that any allocations done by the continuation
(in the form of new parsers, probably) will persist for the
lifetime of the parse result. Beware of wasting too much memory
this way! The bind continuation should generally keep dynamic
allocations to a minimum.
---
 src/parsers/bind.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/src/parsers/bind.c b/src/parsers/bind.c
index 7fa821dc..808df974 100644
--- a/src/parsers/bind.c
+++ b/src/parsers/bind.c
@@ -4,7 +4,6 @@ typedef struct {
     const HParser *p;
     HContinuation k;
     void *env;
-    HAllocator *mm__;
 } BindEnv;
 
 // an HAllocator backed by an HArena
@@ -39,20 +38,15 @@ static HParseResult *parse_bind(void *be_, HParseState *state) {
     if(!res)
         return NULL;
 
-    // create a temporary arena allocator for the continuation
-    HArena *arena = h_new_arena(be->mm__, 0);
-    ArenaAllocator aa = {{aa_alloc, aa_realloc, aa_free}, arena};
+    // create a wrapper arena allocator for the continuation
+    ArenaAllocator aa = {{aa_alloc, aa_realloc, aa_free}, state->arena};
 
     HParser *kx = be->k((HAllocator *)&aa, res->ast, be->env);
     if(!kx) {
-        h_delete_arena(arena);
         return NULL;
     }
 
-    res = h_do_parse(kx, state);
-
-    h_delete_arena(arena);
-    return res;
+    return h_do_parse(kx, state);
 }
 
 static const HParserVtable bind_vt = {
@@ -76,7 +70,6 @@ HParser *h_bind__m(HAllocator *mm__,
     be->p = p;
     be->k = k;
     be->env = env;
-    be->mm__ = mm__;
 
     return h_new_parser(mm__, &bind_vt, be);
 }
-- 
GitLab