aboutsummaryrefslogtreecommitdiff
path: root/tests/test_memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_memory.c')
-rw-r--r--tests/test_memory.c378
1 files changed, 378 insertions, 0 deletions
diff --git a/tests/test_memory.c b/tests/test_memory.c
new file mode 100644
index 0000000..04e9289
--- /dev/null
+++ b/tests/test_memory.c
@@ -0,0 +1,378 @@
+#ifndef FOR_TESTING
+#define FOR_TESTING
+#endif
+
+#include <stdlib.h>
+
+#include "arch.h"
+#include "test_harness.c"
+#include "kern/common.h"
+#include "kern/mem.h"
+
+struct TEST_STRUCT {
+ uint32_t array[3];
+};
+
+struct TEST_STRUCT2 {
+ uint32_t array[10];
+};
+
+/* Copy of the node structure. */
+typedef struct HALLOC_NODE {
+ union {
+ uint32_t header;
+ struct {
+ /* Is this memory block currently in use (hasn't been hfree'd) */
+ bool used:1;
+ /* Number of words allocated. Does not include the header. */
+ uint16_t size:12;
+ /* The location of the previous block (in WORDS from offest) */
+ uint16_t prev:12;
+ uint8_t canary:7;
+ } PACKED;
+ };
+
+ uint8_t mem[]; /* The memory to use. */
+} halloc_node_t;
+
+extern halloc_node_t* halloc_start;
+
+static void wipeout_halloc()
+{
+ memset(halloc_start, 0, 1024);
+ halloc_start = NULL;
+}
+
+
+static struct TEST_STRUCT* new_test_struct()
+{
+ struct TEST_STRUCT* ret = halloc(sizeof(struct TEST_STRUCT));
+
+ ret->array[0] = 1;
+ ret->array[1] = 2;
+ ret->array[2] = 3;
+
+ return ret;
+}
+
+static struct TEST_STRUCT2* new_test_struct2()
+{
+ struct TEST_STRUCT2* ret = halloc(sizeof(struct TEST_STRUCT2));
+
+ for (int i = 0; i < 10; ++ i) {
+ ret->array[i] = i;
+ }
+
+ return ret;
+}
+
+#define ASSERT_CHAIN(t1, t2) \
+ ASSERT_EQ(V(t1) + sizeof(*t1) + 4, V(t2))
+
+TEST(memory, halloc)
+{
+
+#define V(x) ((void*)(x))
+ struct TEST_STRUCT* test1 = new_test_struct();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+ struct TEST_STRUCT* test3 = new_test_struct();
+ struct TEST_STRUCT2* test4 = new_test_struct2();
+ struct TEST_STRUCT2* test5 = new_test_struct2();
+
+ ASSERT_TRUE(V(test1) != V(test2));
+ ASSERT_TRUE(V(test2) != V(test3));
+ ASSERT_TRUE(V(test3) != V(test1));
+ ASSERT_TRUE(V(test2) != V(test5));
+ ASSERT_TRUE(V(test4) != V(test5));
+
+ ASSERT_CHAIN(test1, test2);
+ ASSERT_CHAIN(test2, test3);
+ ASSERT_CHAIN(test3, test4);
+ ASSERT_CHAIN(test4, test5);
+
+
+ char buf[1024];
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (%s:%d)\n",
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ wipeout_halloc();
+
+ return 0;
+}
+
+struct UNEVEN_STRUCT {
+ uint8_t arr[5];
+};
+
+struct UNEVEN_STRUCT* new_uneven_struct()
+{
+ struct UNEVEN_STRUCT* ret = halloc(sizeof(struct UNEVEN_STRUCT));
+
+ ret->arr[0] = 1;
+ ret->arr[1] = 2;
+ ret->arr[2] = 3;
+ ret->arr[3] = 4;
+ ret->arr[4] = 5;
+
+ return ret;
+}
+
+#define size_for(n) \
+ (((n) / 4) + ((n) % 4 != 0))
+
+TEST(memory, uneven_halloc)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct UNEVEN_STRUCT* test1 = new_uneven_struct();
+ struct UNEVEN_STRUCT* test2 = new_uneven_struct();
+
+ ASSERT_EQ(V(test1) + 12, test2);
+
+ wipeout_halloc();
+
+ return 0;
+}
+
+TEST(memory, halloc_free)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct TEST_STRUCT* test1 = new_test_struct();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+ struct TEST_STRUCT* test3 = new_test_struct();
+ struct TEST_STRUCT2* test4 = new_test_struct2();
+ struct TEST_STRUCT2* test5 = new_test_struct2();
+
+ hfree(test2);
+ hfree(test4);
+ hfree(test3);
+ hfree(test1);
+ hfree(test5);
+
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ test1 = new_test_struct();
+ test2 = new_test_struct2();
+ test3 = new_test_struct();
+ test4 = new_test_struct2();
+ test5 = new_test_struct2();
+
+ hfree(test1);
+ hfree(test3);
+ hfree(test2);
+ hfree(test4);
+ hfree(test5);
+
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ test1 = new_test_struct();
+ test2 = new_test_struct2();
+ test3 = new_test_struct();
+ test4 = new_test_struct2();
+ test5 = new_test_struct2();
+
+ hfree(test4);
+ hfree(test3);
+ hfree(test1);
+ hfree(test2);
+ hfree(test5);
+
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ wipeout_halloc();
+
+ return 0;
+}
+
+TEST(memory, halloc_free_alloc2)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct TEST_STRUCT2* test1 = new_test_struct2();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+
+ hfree(test1);
+
+ struct TEST_STRUCT* test3 = new_test_struct();
+ struct TEST_STRUCT* test4 = new_test_struct();
+
+ ASSERT_EQ(debug_halloc_get_next_ptr(test3), V(test4));
+
+ ASSERT_EQ(
+ // There should be a free block after test4.
+ debug_halloc_get_next_ptr(debug_halloc_get_next_ptr(test4)),
+ V(test2));
+
+ ASSERT_EQ(
+ // There should be a free block after test4.
+ debug_halloc_get_prev_ptr(debug_halloc_get_prev_ptr(test2)),
+ V(test4));
+
+ char buf[1024];
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(stderr, "Consistency check failed.\n");
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ return 0;
+}
+
+TEST(memory, relink_backref_after_free)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ struct TEST_STRUCT* test2 = new_test_struct();
+ struct TEST_STRUCT* test3 = new_test_struct();
+
+ hfree(test2);
+ hfree(test3);
+
+ char buf[1024];
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(stderr, "Consistency check failed.\n");
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ return 0;
+}
+
+TEST(memory, consistency_stress)
+{
+#define NRUNS 500
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ int i;
+ void* allocd[NRUNS] = { 0 };
+ char buf[1024];
+
+ for (i = 0; i < NRUNS; ++ i) {
+ size_t nalloc = rand() % 20;
+ allocd[i] = halloc(nalloc);
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ ASSERT_TRUE(allocd[i]);
+
+ memset(allocd[i], 0xFF, nalloc);
+ size_t idx = rand() % NRUNS;
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ hfree(allocd[idx]);
+ allocd[idx] = NULL;
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+
+ idx = rand() % NRUNS;
+ hfree(allocd[idx]);
+ allocd[idx] = NULL;
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+ }
+
+ for(i = 0; i < NRUNS; ++ i) {
+ if (allocd[i]) {
+ hfree(allocd[i]);
+ }
+
+ if (debug_halloc_assert_consistency(buf, 1024)) {
+ fprintf(
+ stderr,
+ "Consistency check failed. (At index=%d, %s:%d)\n",
+ i,
+ __FILE__,
+ __LINE__);
+ fprintf(stderr, buf);
+ ASSERT_TRUE(false);
+ }
+ }
+ ASSERT_EQ((int) halloc_start->size * 4, MAX_HEAP_SIZE - 4);
+
+ return 0;
+}
+
+TEST(memory, halloc_free_alloc)
+{
+ if (halloc_start) {
+ wipeout_halloc();
+ }
+
+ new_test_struct();
+ struct TEST_STRUCT2* test2 = new_test_struct2();
+ new_test_struct();
+ struct TEST_STRUCT2* test4 = new_test_struct2();
+ new_test_struct2();
+
+ hfree(test4);
+
+ struct TEST_STRUCT2* test6 = new_test_struct2();
+
+ // test_6 should have been allocated in test_4's spot.
+ ASSERT_EQ(test6, test4);
+
+ hfree(test2);
+ struct TEST_STRUCT* test7 = new_test_struct();
+ struct TEST_STRUCT* test8 = new_test_struct();
+
+ // Test 2 was large enough to accomodate 3 smaller structs.
+ ASSERT_EQ(V(test7), V(test2));
+ ASSERT_EQ(V(test8), V(test2) + sizeof(*test7) + 4);
+
+ return 0;
+}