From 67155769103e2c50dde1a9ec18f4eb5a849fdca8 Mon Sep 17 00:00:00 2001
From: Caleb Sander <csander@caltech.edu>
Date: Tue, 26 Nov 2019 20:26:04 -0800
Subject: [PATCH] Improve tests

---
 Makefile                  |  4 ++--
 eval.c                    |  1 +
 eval_types.c              |  5 +++++
 refs.c                    |  4 ++++
 repl.c                    |  5 ++++-
 tests/dense_graph.py      |  2 +-
 tests/gc_ref_counts.py    |  2 +-
 tests/gc_tombstones.py    | 41 +++++++++++++++++++++++++++++++++++++++
 tests/linked_list.py      |  2 +-
 tests/long_loops.py       |  2 +-
 tests/simple_recursive.py |  2 +-
 11 files changed, 62 insertions(+), 8 deletions(-)
 create mode 100644 tests/gc_tombstones.py

diff --git a/Makefile b/Makefile
index 418c229..d8f08fa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 CC = clang-with-asan
-CFLAGS = -Wall -Wextra -Werror -MMD -fno-sanitize=integer
+CFLAGS = -Wall -Wextra -Werror -MMD
 
 ifdef NREADLINE
 	CFLAGS += -DNREADLINE
@@ -16,7 +16,7 @@ TESTS_1 = simple_math simple_print algo_fizzbuzz algo_csum algo_join \
 	long_chain transpose ordered_fractions # champernowne bouncy_numbers
 TESTS_2 = $(TESTS_1) dict_ops long_chain_dict tree dict_resize stress_struct
 TESTS_3 = $(TESTS_2) self_cycle simple_recursive simple_rep long_loops \
-	linked_list gc_ref_counts dense_graph compacting
+	linked_list gc_ref_counts dense_graph compacting gc_tombstones
 
 test: test3
 test1: $(TESTS_1:=-result)
diff --git a/eval.c b/eval.c
index 0f5b1ff..5cd8ee2 100644
--- a/eval.c
+++ b/eval.c
@@ -88,6 +88,7 @@ void eval_close() {
         free(global_vars[i].name);
     }
     free(global_vars);
+    global_vars = NULL;
 }
 
 /*!
diff --git a/eval_types.c b/eval_types.c
index 14036fd..a920d45 100644
--- a/eval_types.c
+++ b/eval_types.c
@@ -120,18 +120,23 @@ static bool integer_eq(value_t *l, value_t *r) {
     return integer_cmp(l, r) == 0;
 }
 
+__attribute__((no_sanitize("integer")))
 static reference_t integer_add(value_t *l, value_t *r) {
     return make_reference_int(integer_coerce(l) + integer_coerce(r));
 }
+__attribute__((no_sanitize("integer")))
 static reference_t integer_subtract(value_t *l, value_t *r) {
     return make_reference_int(integer_coerce(l) - integer_coerce(r));
 }
+__attribute__((no_sanitize("integer")))
 static reference_t integer_multiply(value_t *l, value_t *r) {
     return make_reference_int(integer_coerce(l) * integer_coerce(r));
 }
+__attribute__((no_sanitize("integer")))
 static reference_t integer_divide(value_t *l, value_t *r) {
     return make_reference_int(integer_coerce(l) / integer_coerce(r));
 }
+__attribute__((no_sanitize("integer")))
 static reference_t integer_modulo(value_t *l, value_t *r) {
     return make_reference_int(integer_coerce(l) % integer_coerce(r));
 }
diff --git a/refs.c b/refs.c
index 816b96f..d845db9 100644
--- a/refs.c
+++ b/refs.c
@@ -144,6 +144,8 @@ value_t *deref(reference_t ref) {
     /* Make sure the reference's value is within the pool!
      * Also ensure that the value is not NULL, indicating an unused reference. */
     assert(pool <= (uint8_t *) value && (uint8_t *) value < pool + pool_size);
+    /* The value should also be aligned to an 8-byte boundary. */
+    assert((size_t) value % ALIGNMENT == 0);
 
     return value;
 }
@@ -227,5 +229,7 @@ void collect_garbage() {
 void refs_close() {
     free(pool);
     free(ref_table);
+    pool = NULL;
+    ref_table = NULL;
 }
 
diff --git a/repl.c b/repl.c
index ede263c..0222acb 100644
--- a/repl.c
+++ b/repl.c
@@ -33,7 +33,10 @@ static bool debug = false;
  * completion.
  */
 bool eval(Node *node) {
-    assert(node != NULL);
+    if (node == NULL) {
+        /* Parsed a comment; nothing to do. */
+        return true;
+    }
 
     /* Perform the computation. */
     reference_t result = eval_root(node);
diff --git a/tests/dense_graph.py b/tests/dense_graph.py
index 8726b3c..ab40b4a 100644
--- a/tests/dense_graph.py
+++ b/tests/dense_graph.py
@@ -1,4 +1,4 @@
-# -m 10000
+# -m 10009
 
 node_one   = {"name": "a"}
 node_two   = {"name": "b"}
diff --git a/tests/gc_ref_counts.py b/tests/gc_ref_counts.py
index 0bafdd3..5c22e19 100644
--- a/tests/gc_ref_counts.py
+++ b/tests/gc_ref_counts.py
@@ -1,4 +1,4 @@
-# -m 10000
+# -m 10008
 
 # Simple test: one garbage value refers to non-garbage
 non_garbage = 123
diff --git a/tests/gc_tombstones.py b/tests/gc_tombstones.py
new file mode 100644
index 0000000..d4c19e5
--- /dev/null
+++ b/tests/gc_tombstones.py
@@ -0,0 +1,41 @@
+# -m 10015
+
+d = {0: 0, 1: 1}
+# output {0: 0, 1: 1}
+print(d)
+i = 2
+while i <= 40:
+    d[i] = d[i - 2] + d[i - 1]
+    del d[i - 2]
+    i = i + 1
+del i
+# output 824 bytes in use; 10 refs in use
+mem()
+# output {39: 63245986, 40: 102334155}
+print(d)
+gc()
+# output 824 bytes in use; 10 refs in use
+mem()
+del d
+# output 72 bytes in use; 3 refs in use
+mem()
+
+a = {}
+a[True] = a
+b = {1: a}
+del a
+# output {1: {True: {True: {...: ...}}}}
+print(b)
+# output 584 bytes in use; 10 refs in use
+mem()
+del b[1]
+# output {}
+print(b)
+# output 552 bytes in use; 9 refs in use
+mem()
+gc()
+# output 312 bytes in use; 6 refs in use
+mem()
+del b
+# output 72 bytes in use; 3 refs in use
+mem()
diff --git a/tests/linked_list.py b/tests/linked_list.py
index 87f4898..4bce090 100644
--- a/tests/linked_list.py
+++ b/tests/linked_list.py
@@ -1,4 +1,4 @@
-# -m 10000
+# -m 10004
 
 a = {"value": 1, "prev": None, "next": None}
 b = {"value": True, "prev": a, "next": None}
diff --git a/tests/long_loops.py b/tests/long_loops.py
index d34f7d2..ca7830e 100644
--- a/tests/long_loops.py
+++ b/tests/long_loops.py
@@ -1,4 +1,4 @@
-# -m 100000
+# -m 100003
 
 # Create three separate cycles
 z = {"next": "i am root"}
diff --git a/tests/simple_recursive.py b/tests/simple_recursive.py
index 86d89b9..ed77329 100644
--- a/tests/simple_recursive.py
+++ b/tests/simple_recursive.py
@@ -1,4 +1,4 @@
-# -m 10000
+# -m 10001
 
 a = [0]
 a[0] = a
-- 
GitLab