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.
This commit is contained in:
parent
e26a8ff572
commit
ca1d8df06c
1 changed files with 3 additions and 10 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue