Fix memory leaks in compiler
diff --git a/src/lisp/Jmk2 b/src/lisp/Jmk2
index 5446f50..b9398ac 100644
--- a/src/lisp/Jmk2
+++ b/src/lisp/Jmk2
@@ -34,6 +34,11 @@
shell "LISP_LIBRARY_PATH=$::lisp_libpath ./lisp $::root/lib/lisp/repl/repl.lisp"
}
+rule valgrind [pwd]/lisp {
+ log VALGRIND "lisp test-gc.lisp"
+ shell "LISP_LIBRARY_PATH=$::lisp_libpath valgrind --track-origins=yes --leak-check=full ./lisp test-gc.lisp"
+}
+
srcs main.c lisp.c compiler.c lib/std.c plat/linux.c istream.c gc.c \
call_list.s error.c
diff --git a/src/lisp/compiler.dasc b/src/lisp/compiler.dasc
index a0b0236..122538c 100644
--- a/src/lisp/compiler.dasc
+++ b/src/lisp/compiler.dasc
@@ -105,6 +105,8 @@
{
next = f->prev;
// We're not gonna bother munmap()ing the function
+ if (f->args)
+ free(f->args);
free(f);
}
@@ -207,10 +209,15 @@
if (local_out)
*local_out = local;
+ else
+ del_local(&local);
if (args_out)
*args_out = ar;
+ if (!local_out && !args_out)
+ free(ar);
+
*state = d;
OKAY();
@@ -408,6 +415,8 @@
snprintf(full_path, 512, "%s/%s", dirname(relative_to), new_path);
+ free(relative_to);
+
if (load(env, full_path))
return t;
else
@@ -775,7 +784,7 @@
{
// Compile the function with this as the parent scope
struct local new_local;
- int nargs_out;
+ struct args *nargs_out;
dasm_State *d;
TRY(compile_function(
args, NS_ANONYMOUS, env, &new_local, local, &nargs_out,
@@ -1251,6 +1260,8 @@
add_variable(local, V_ARGUMENT, (char *)(name ^ SYMBOL_TAG),
args->num_required + args->num_optional - 1);
+
+ dasm_free(&d);
}
}
diff --git a/src/lisp/compiler.h b/src/lisp/compiler.h
index 340d955..62f1b69 100644
--- a/src/lisp/compiler.h
+++ b/src/lisp/compiler.h
@@ -152,8 +152,11 @@
void local_free(struct local *local, unsigned int slot);
/**
- * Deletes the memory allocated in `local`. Does not actually call `free()` on
- * `local` itself, but frees the variables and stack slots associated with it.
+ * Deletes the memory allocated in `local`. Does not actually call
+ * `free()` on `local` itself, but frees the variables and stack slots
+ * associated with it. Also does NOT free `local->args`. You must do
+ * that yourself if you want. This is because these arguments are
+ * often used in multiple places.
*/
void del_local(struct local *local);
diff --git a/src/lisp/gc.c b/src/lisp/gc.c
index 06d8a07..140bc3f 100644
--- a/src/lisp/gc.c
+++ b/src/lisp/gc.c
@@ -84,14 +84,23 @@
}
else
{
- fprintf(stderr, "[ GC ] freeing: ");
- printval(alloc_to_value(a), 1);
+ fprintf(stderr, "[ GC ] freeing: %p\n", a);
// Free and remove from allocation list
struct alloc *p = a->prev, *n = a->next;
- free_aligned(a);
+ del_alloc(a);
a = n;
+ if (a == first_a)
+ {
+ first_a = n;
+ }
+
+ if (a == last_a)
+ {
+ last_a = p;
+ }
+
if (p)
p->next = n;
@@ -152,7 +161,7 @@
for (struct alloc *a = first_a; a;)
{
struct alloc *next = a->next;
- free_aligned(a);
+ del_alloc(a);
a = next;
// fprintf(stderr, "a = %p\n", a);
}
diff --git a/src/lisp/lisp.c b/src/lisp/lisp.c
index ac6470d..6299e03 100644
--- a/src/lisp/lisp.c
+++ b/src/lisp/lisp.c
@@ -25,6 +25,7 @@
void add_this_alloc(struct alloc *a, int tag)
{
+ a->mark = -1;
a->type_tag = tag;
a->pool = current_pool;
@@ -600,6 +601,18 @@
a[-1].pool = current_pool;
}
+void del_alloc(struct alloc *alloc)
+{
+ if (alloc->type_tag == CLOSURE_TAG)
+ {
+ fprintf(stderr, "del_alloc closure\n");
+ struct closure_alloc *ca = alloc;
+ free(ca->closure.args);
+ }
+
+ free_aligned(alloc);
+}
+
int cons_line(value_t val)
{
if (!consp(val))
diff --git a/src/lisp/lisp.h b/src/lisp/lisp.h
index e41ebff..ad7314a 100644
--- a/src/lisp/lisp.h
+++ b/src/lisp/lisp.h
@@ -149,6 +149,8 @@
void add_to_pool(value_t form);
+void del_alloc(struct alloc *alloc);
+
/**
* @returns true if pool is still alive (in scope).
*/
diff --git a/src/lisp/main.c b/src/lisp/main.c
index f78b3b1..a9231b8 100644
--- a/src/lisp/main.c
+++ b/src/lisp/main.c
@@ -1,6 +1,6 @@
#include "compiler.h"
-#include "lisp.h"
#include "gc.h"
+#include "lisp.h"
#include "plat/plat.h"
int main(int argc, char **argv)
@@ -18,7 +18,7 @@
{
ereport(compile_error);
goto done;
- }
+ }
struct function *lisp_main_f = find_function(env, "main");