Symptom
The HTTP code-route handler in src/ext_http.c parses the route source per
request and never frees the resulting AST — so a long-running server leaks
one AST per request (worse: two, when http_route_authed is used, since the
auth source is parsed too). This is a per-request leak, not an error path —
it leaks on success.
Locations
In the route dispatch (around ext_http.c:972 and ext_http.c:990):
```
ASTNode *auth_ast = parse(&auth_tl);
... compile_ast(auth_ast, auth_env); vm_execute(...); chunk_free(...);
free_tokenlist(&auth_tl); // <- no free_ast(auth_ast)
ASTNode *ast = parse(&tl);
... compile_ast(ast, req_env); vm_execute(...); chunk_free(req_chunk);
free_tokenlist(&tl); // <- no free_ast(ast)
```
Both paths free_tokenlist + chunk_free but omit free_ast. (Same missing-
free_ast root cause as the parse-error leak fixed for main/import, but
here it leaks unconditionally, per request.)
Fix
Add free_ast(auth_ast) and free_ast(ast) after their compile_ast/use,
alongside the existing free_tokenlist. (compile_ast does not take ownership
of the AST — the other call sites free it after compiling.)
Verify
Not in the default ASan suite (it builds EXT_HTTP=0). Compile-check with
make http; verify under ASan by building the http variant and driving
tests/test_http_server.sh against a code/authed route, confirming the
per-request AST allocations no longer accumulate.
Acceptance
free_ast on both route-parse paths; make http compiles clean.
- A repeated-request loop against a code route is leak-stable under ASan.
Symptom
The HTTP
code-route handler insrc/ext_http.cparses the route source perrequest and never frees the resulting AST — so a long-running server leaks
one AST per request (worse: two, when
http_route_authedis used, since theauth source is parsed too). This is a per-request leak, not an error path —
it leaks on success.
Locations
In the route dispatch (around ext_http.c:972 and ext_http.c:990):
```
ASTNode *auth_ast = parse(&auth_tl);
... compile_ast(auth_ast, auth_env); vm_execute(...); chunk_free(...);
free_tokenlist(&auth_tl); // <- no free_ast(auth_ast)
ASTNode *ast = parse(&tl);
... compile_ast(ast, req_env); vm_execute(...); chunk_free(req_chunk);
free_tokenlist(&tl); // <- no free_ast(ast)
```
Both paths
free_tokenlist+chunk_freebut omitfree_ast. (Same missing-free_astroot cause as the parse-error leak fixed formain/import, buthere it leaks unconditionally, per request.)
Fix
Add
free_ast(auth_ast)andfree_ast(ast)after theircompile_ast/use,alongside the existing
free_tokenlist. (compile_ast does not take ownershipof the AST — the other call sites free it after compiling.)
Verify
Not in the default ASan suite (it builds
EXT_HTTP=0). Compile-check withmake http; verify under ASan by building the http variant and drivingtests/test_http_server.shagainst acode/authed route, confirming theper-request AST allocations no longer accumulate.
Acceptance
free_aston both route-parse paths;make httpcompiles clean.