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)