Fix memory leaks, aligned allocators
diff --git a/src/lisp/Jmk b/src/lisp/Jmk
index 394e077..7c1fe8e 100644
--- a/src/lisp/Jmk
+++ b/src/lisp/Jmk
@@ -43,6 +43,10 @@
status_log(LISP, $(F))
@./lisp $(F)
+leak-check: lisp
+ status_log(VALGRIND, lisp $(F))
+ @valgrind --leak-check=full ./lisp $(F)
+
format:
status_log(FORMAT, *)
@clang-format -i *.c *.h *.dasc plat/* lib/*
diff --git a/src/lisp/compiler.dasc b/src/lisp/compiler.dasc
index 9a64801..c2c0639 100644
--- a/src/lisp/compiler.dasc
+++ b/src/lisp/compiler.dasc
@@ -87,6 +87,27 @@
local->stack_slots[slot] = false;
}
+void del_local(struct local *local)
+{
+ free(local->stack_slots);
+
+ for (struct variable *next, *f = local->first; f; f = next)
+ {
+ next = f->prev;
+ free(f);
+ }
+}
+
+void del_env(struct environment *env)
+{
+ for (struct function *next, *f = env->first; f; f = next)
+ {
+ next = f->prev;
+ // We're not gonna bother munmap()ing the function
+ free(f);
+ }
+}
+
struct dasm_State *compile_function(value_t args, enum namespace namespace,
struct environment *env, struct local *local_out,
struct local *local_parent, int *nargs, char *name)
@@ -160,9 +181,6 @@
*nargs = length(arglist);
return d;
-
- // TODO: local leaks memory! free variables too, not just stack slots (in
- // two places). Add a free_local() function that does this.
}
void compile_tl(value_t val, struct environment *env)
@@ -189,7 +207,7 @@
nargs, namespace);
dasm_free(&d);
- free(local.stack_slots);
+ del_local(&local);
}
}
@@ -481,7 +499,7 @@
// Closure is still in eax
dasm_free(&d);
- free(new_local.stack_slots);
+ del_local(&new_local);
}
else
{
diff --git a/src/lisp/compiler.h b/src/lisp/compiler.h
index 16cc35e..d70cac6 100644
--- a/src/lisp/compiler.h
+++ b/src/lisp/compiler.h
@@ -119,6 +119,18 @@
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.
+ */
+void del_local(struct local *local);
+
+/**
+ * Deletes the memory allocated in `env`. Does not actually call `free()` on
+ * `env` itself.
+ */
+void del_env(struct environment *env);
+
+/**
* Walk `body` and reserve space in `local` for any variable declarations.
*/
void walk_and_alloc(struct local *local, value_t body);
diff --git a/src/lisp/main.c b/src/lisp/main.c
index 95eb196..94bdeaf 100644
--- a/src/lisp/main.c
+++ b/src/lisp/main.c
@@ -25,4 +25,6 @@
lisp_main();
free_all();
+ del_env(&env);
+ del_fistream(is);
}
diff --git a/src/lisp/plat/linux.c b/src/lisp/plat/linux.c
index 2777950..4a223a6 100644
--- a/src/lisp/plat/linux.c
+++ b/src/lisp/plat/linux.c
@@ -5,28 +5,19 @@
void *malloc_aligned(size_t size)
{
- void *mem = malloc(size + 8 + sizeof(void *) * 2);
- void **aligned_ptr = (void **)((uintptr_t)(mem + 8 + sizeof(void *)) & ~7);
- aligned_ptr[-1] = mem;
- aligned_ptr[-2] = (void *)size;
- return aligned_ptr;
+ // https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
+ // On glibc malloc() and realloc() return 8-byte aligned addresses.
+ return malloc(size);
}
void *realloc_aligned(void *addr, size_t size)
{
- void *mem = malloc(size + 8 + sizeof(void *) * 2);
- void **aligned_ptr = (void **)((uintptr_t)(mem + 8 + sizeof(void *)) & ~7);
- aligned_ptr[-1] = mem;
-
- memcpy(aligned_ptr, addr, ((uintptr_t *)addr)[-2]);
-
- return aligned_ptr;
+ return realloc(addr, size);
}
void free_aligned(void *addr)
{
- void **ptr = (void **)addr;
- free(ptr[-1]);
+ free(addr);
}
void *link(dasm_State **Dst)