From ba0d496a3c3fabc003952aa134e3e2c382e0d932 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sat, 6 Sep 2025 12:50:43 +0200 Subject: [PATCH] Implement allocation checking in the unit tests --- CMakeLists.txt | 3 +- README.org | 9 +- src/10-4-decrement-and-free/main.c | 18 ++-- src/10-4-decrement-and-free/snekobject.c | 17 +-- src/10-5-vectors/main.c | 34 +++--- src/10-5-vectors/snekobject.c | 15 +-- src/10-6-arrays/main.c | 38 +++---- src/10-6-arrays/snekobject.c | 17 +-- src/10-7-refcounting-review/main.c | 3 +- src/7-6-generic-swap/exercise.c | 6 +- src/7-6-generic-swap/main.c | 6 +- src/8-1-low-level-stack/main.c | 14 +-- src/8-1-low-level-stack/snekstack.c | 7 +- src/8-2-stack-push/main.c | 22 ++-- src/8-2-stack-push/snekstack.c | 13 +-- src/8-3-stack-pop/main.c | 26 ++--- src/8-3-stack-pop/snekstack.c | 9 +- src/8-4-stack-free/main.c | 8 +- src/8-4-stack-free/snekstack.c | 13 +-- src/9-3-float/main.c | 13 +-- src/9-3-float/snekobject.c | 5 +- src/9-4-string/main.c | 12 ++- src/9-4-string/snekobject.c | 11 +- src/9-5-vector3/main.c | 19 ++-- src/9-5-vector3/snekobject.c | 24 ++--- src/9-6-arrays/main.c | 13 +-- src/9-6-arrays/snekobject.c | 19 ++-- src/9-7-get-and-set/main.c | 33 +++--- src/9-7-get-and-set/snekobject.c | 19 ++-- src/9-8-length/main.c | 33 +++--- src/9-8-length/snekobject.c | 19 ++-- src/bootlib.c | 127 +++++++++++++++++++++++ src/bootlib.h | 16 +++ src/munit.h | 5 + 34 files changed, 407 insertions(+), 239 deletions(-) create mode 100644 src/bootlib.c create mode 100644 src/bootlib.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3893920..eaff23f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,13 +33,14 @@ foreach(LESSON ${LESSONS}) if(NOT LESSON_SOURCES) continue() endif() + list(APPEND LESSON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/bootlib.c) # Get last directory name of the path to use as exe get_filename_component(EXE_NAME ${LESSON} NAME) add_executable(${EXE_NAME} ${LESSON_SOURCES}) target_include_directories(${EXE_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/${LESSON}) target_link_libraries(${EXE_NAME} munit) diff --git a/README.org b/README.org index 81903fb..dd333a1 100644 --- a/README.org +++ b/README.org @@ -13,11 +13,14 @@ The first the 3 chapters of the course can be done interactively on the website. [[./bootdev-c.png]] If you're reading this with the intention of completing the exercises yourself, -just remove the directories from the =src= directory and recreate the directory -with the files from the exercise. Alternatively, just remove the file the -exercise is asking you to modify as you go. +you can find each exercise is in its own directory inside of the =src= directory. +Remove all the files that are not called =main.c= and recreate them from the +exercises on the boot.dev website as you go through them, so you won't get spoiled. Note: +- In order to verify allocations in the unit tests, please use the wrapper + functions =boot_malloc=, =boot_calloc=, =boot_realloc= and =boot_free= from + =boot_lib.h= instead of the =stdlib.h= allocation functions - In chapter 6 exercise 6, macOS malloc will almost never return a NULL pointer due to virtual memory overcommit, so you should check for ~size == 1024 * 1024 * 100)~ instead of ~array == NULL~ diff --git a/src/10-4-decrement-and-free/main.c b/src/10-4-decrement-and-free/main.c index a70f91f..44a5f8f 100644 --- a/src/10-4-decrement-and-free/main.c +++ b/src/10-4-decrement-and-free/main.c @@ -1,7 +1,7 @@ #include #include -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -9,7 +9,7 @@ munit_case(RUN, test_int_has_refcount, { snek_object_t *obj = new_snek_integer(10); assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); - free(obj); + boot_free(obj); }); munit_case(RUN, test_inc_refcount, { @@ -19,7 +19,7 @@ munit_case(RUN, test_inc_refcount, { refcount_inc(obj); assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); - free(obj); + boot_free(obj); }); munit_case(RUN, test_dec_refcount, { @@ -31,10 +31,10 @@ munit_case(RUN, test_dec_refcount, { refcount_dec(obj); assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); - // assert(!boot_is_freed(obj)); + assert(!boot_is_freed(obj)); // Object is still alive, so we will free manually. - free(obj); + boot_free(obj); }); munit_case(SUBMIT, test_refcount_free_is_called, { @@ -47,8 +47,8 @@ munit_case(SUBMIT, test_refcount_free_is_called, { assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); refcount_dec(obj); - // assert(boot_is_freed(obj)); - // assert(boot_all_freed()); + assert(boot_is_freed(obj)); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_allocated_string_is_freed, { @@ -62,8 +62,8 @@ munit_case(SUBMIT, test_allocated_string_is_freed, { assert_string_equal(obj->data.v_string, "Hello @wagslane!", "references str"); refcount_dec(obj); - // assert(boot_is_freed(obj)); - // assert(boot_all_freed()); + assert(boot_is_freed(obj)); + assert(boot_all_freed()); }); int main() { diff --git a/src/10-4-decrement-and-free/snekobject.c b/src/10-4-decrement-and-free/snekobject.c index 8258606..9b836e6 100644 --- a/src/10-4-decrement-and-free/snekobject.c +++ b/src/10-4-decrement-and-free/snekobject.c @@ -3,6 +3,7 @@ #include #include +#include "bootlib.h" #include "snekobject.h" void refcount_dec(snek_object_t *obj) { @@ -14,11 +15,11 @@ void refcount_dec(snek_object_t *obj) { void refcount_free(snek_object_t *obj) { if (obj == NULL) return; if (obj->kind == INTEGER || obj->kind == FLOAT) { - free(obj); + boot_free(obj); } if (obj->kind == STRING) { - free(obj->data.v_string); - free(obj); + boot_free(obj->data.v_string); + boot_free(obj); } } @@ -34,7 +35,7 @@ void refcount_inc(snek_object_t *obj) { } snek_object_t *_new_snek_object() { - snek_object_t *obj = calloc(1, sizeof(snek_object_t)); + snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -50,9 +51,9 @@ snek_object_t *new_snek_array(size_t size) { return NULL; } - snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); + snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); if (elements == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -109,9 +110,9 @@ snek_object_t *new_snek_string(char *value) { } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/10-5-vectors/main.c b/src/10-5-vectors/main.c index bd48034..fb9f840 100644 --- a/src/10-5-vectors/main.c +++ b/src/10-5-vectors/main.c @@ -1,7 +1,7 @@ #include #include -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -17,20 +17,20 @@ munit_case(RUN, test_vector3_refcounting, { // `foo` is stil referenced in the `vec`, so it should not be freed. refcount_dec(foo); - // assert(!boot_is_freed(foo)); + assert(!boot_is_freed(foo)); refcount_dec(vec); - // assert(boot_is_freed(foo)); + assert(boot_is_freed(foo)); // These are still alive, they have the original reference still. - // assert(!boot_is_freed(bar)); - // assert(!boot_is_freed(baz)); + assert(!boot_is_freed(bar)); + assert(!boot_is_freed(baz)); // Decrement the last reference to the objects, so they will be freed. refcount_dec(bar); refcount_dec(baz); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_vector3_refcounting_same, { @@ -41,19 +41,19 @@ munit_case(SUBMIT, test_vector3_refcounting_same, { // `foo` is stil referenced in the `vec`, so it should not be freed. refcount_dec(foo); - // assert(!boot_is_freed(foo)); + assert(!boot_is_freed(foo)); refcount_dec(vec); - // assert(boot_is_freed(foo)); - // assert(boot_is_freed(vec)); - // assert(boot_all_freed()); + assert(boot_is_freed(foo)); + assert(boot_is_freed(vec)); + assert(boot_all_freed()); }); munit_case(RUN, test_int_has_refcount, { snek_object_t *obj = new_snek_integer(10); assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); - free(obj); + boot_free(obj); }); munit_case(RUN, test_inc_refcount, { @@ -63,7 +63,7 @@ munit_case(RUN, test_inc_refcount, { refcount_inc(obj); assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); - free(obj); + boot_free(obj); }); munit_case(RUN, test_dec_refcount, { @@ -78,7 +78,7 @@ munit_case(RUN, test_dec_refcount, { // assert(!boot_is_freed(obj)); // Object is still alive, so we will free manually. - free(obj); + boot_free(obj); }); munit_case(RUN, test_refcount_free_is_called, { @@ -91,8 +91,8 @@ munit_case(RUN, test_refcount_free_is_called, { assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); refcount_dec(obj); - // assert(boot_is_freed(obj)); - // assert(boot_all_freed()); + assert(boot_is_freed(obj)); + assert(boot_all_freed()); }); munit_case(RUN, test_allocated_string_is_freed, { @@ -106,8 +106,8 @@ munit_case(RUN, test_allocated_string_is_freed, { assert_string_equal(obj->data.v_string, "Hello @wagslane!", "references str"); refcount_dec(obj); - // assert(boot_is_freed(obj)); - // assert(boot_all_freed()); + assert(boot_is_freed(obj)); + assert(boot_all_freed()); }); int main() { diff --git a/src/10-5-vectors/snekobject.c b/src/10-5-vectors/snekobject.c index eb73b56..7f852db 100644 --- a/src/10-5-vectors/snekobject.c +++ b/src/10-5-vectors/snekobject.c @@ -3,6 +3,7 @@ #include #include +#include "bootlib.h" #include "snekobject.h" snek_object_t *_new_snek_object(); @@ -31,7 +32,7 @@ void refcount_free(snek_object_t *obj) case FLOAT: break; case STRING: - free(obj->data.v_string); + boot_free(obj->data.v_string); break; case VECTOR3: { refcount_dec(obj->data.v_vector3.x); @@ -43,7 +44,7 @@ void refcount_free(snek_object_t *obj) assert(false); } - free(obj); + boot_free(obj); } // don't touch below this line @@ -69,7 +70,7 @@ void refcount_dec(snek_object_t *obj) { } snek_object_t *_new_snek_object() { - snek_object_t *obj = calloc(1, sizeof(snek_object_t)); + snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -85,9 +86,9 @@ snek_object_t *new_snek_array(size_t size) { return NULL; } - snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); + snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); if (elements == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -126,9 +127,9 @@ snek_object_t *new_snek_string(char *value) { } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/10-6-arrays/main.c b/src/10-6-arrays/main.c index b460b39..0fded63 100644 --- a/src/10-6-arrays/main.c +++ b/src/10-6-arrays/main.c @@ -1,7 +1,7 @@ #include #include -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -12,11 +12,11 @@ munit_case(RUN, test_array_set, { snek_array_set(array, 0, foo); assert_int(foo->refcount, ==, 2, "foo is now referenced by array"); - // assert(!boot_is_freed(foo)); + assert(!boot_is_freed(foo)); refcount_dec(foo); refcount_dec(array); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_array_free, { @@ -33,17 +33,17 @@ munit_case(SUBMIT, test_array_free, { // `foo` is stil referenced in the `array`, so it should not be freed. refcount_dec(foo); - // assert(!boot_is_freed(foo)); + assert(!boot_is_freed(foo)); // Overwrite index 0, which is `foo`, with `baz`. // Now `foo` is not referenced by `array`, so it should be freed. snek_array_set(array, 0, baz); - // assert(boot_is_freed(foo)); + assert(boot_is_freed(foo)); refcount_dec(bar); refcount_dec(baz); refcount_dec(array); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, test_vector3_refcounting, { @@ -58,27 +58,27 @@ munit_case(RUN, test_vector3_refcounting, { // `foo` is stil referenced in the `vec`, so it should not be freed. refcount_dec(foo); - // assert(!boot_is_freed(foo)); + assert(!boot_is_freed(foo)); refcount_dec(vec); - // assert(boot_is_freed(foo)); + assert(boot_is_freed(foo)); // These are still alive, they have the original reference still. - // assert(!boot_is_freed(bar)); - // assert(!boot_is_freed(baz)); + assert(!boot_is_freed(bar)); + assert(!boot_is_freed(baz)); // Decrement the last reference to the objects, so they will be freed. refcount_dec(bar); refcount_dec(baz); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, test_int_has_refcount, { snek_object_t *obj = new_snek_integer(10); assert_int(obj->refcount, ==, 1, "Refcount should be 1 on creation"); - free(obj); + boot_free(obj); }); munit_case(RUN, test_inc_refcount, { @@ -88,7 +88,7 @@ munit_case(RUN, test_inc_refcount, { refcount_inc(obj); assert_int(obj->refcount, ==, 2, "Refcount should be incremented"); - free(obj); + boot_free(obj); }); munit_case(RUN, test_dec_refcount, { @@ -100,10 +100,10 @@ munit_case(RUN, test_dec_refcount, { refcount_dec(obj); assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); - // assert(!boot_is_freed(obj)); + assert(!boot_is_freed(obj)); // Object is still alive, so we will free manually. - free(obj); + boot_free(obj); }); munit_case(RUN, test_refcount_free_is_called, { @@ -116,8 +116,8 @@ munit_case(RUN, test_refcount_free_is_called, { assert_int(obj->refcount, ==, 1, "Refcount should be decremented"); refcount_dec(obj); - // assert(boot_is_freed(obj)); - // assert(boot_all_freed()); + assert(boot_is_freed(obj)); + assert(boot_all_freed()); }); munit_case(RUN, test_allocated_string_is_freed, { @@ -131,8 +131,8 @@ munit_case(RUN, test_allocated_string_is_freed, { assert_string_equal(obj->data.v_string, "Hello @wagslane!", "references str"); refcount_dec(obj); - // assert(boot_is_freed(obj)); - // assert(boot_all_freed()); + assert(boot_is_freed(obj)); + assert(boot_all_freed()); }); int main() { diff --git a/src/10-6-arrays/snekobject.c b/src/10-6-arrays/snekobject.c index c2871a5..0e31997 100644 --- a/src/10-6-arrays/snekobject.c +++ b/src/10-6-arrays/snekobject.c @@ -3,6 +3,7 @@ #include #include +#include "bootlib.h" #include "snekobject.h" bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value) @@ -31,7 +32,7 @@ void refcount_free(snek_object_t *obj) case FLOAT: break; case STRING: - free(obj->data.v_string); + boot_free(obj->data.v_string); break; case VECTOR3: { snek_vector_t vec = obj->data.v_vector3; @@ -44,13 +45,13 @@ void refcount_free(snek_object_t *obj) for (int i = 0; i < obj->data.v_array.size; i++) { refcount_dec(obj->data.v_array.elements[i]); } - free(obj->data.v_array.elements); + boot_free(obj->data.v_array.elements); break; } default: assert(false); } - free(obj); + boot_free(obj); } // don't touch below this line @@ -92,7 +93,7 @@ void refcount_dec(snek_object_t *obj) { } snek_object_t *_new_snek_object() { - snek_object_t *obj = calloc(1, sizeof(snek_object_t)); + snek_object_t *obj = boot_calloc(1, sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -108,9 +109,9 @@ snek_object_t *new_snek_array(size_t size) { return NULL; } - snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); + snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); if (elements == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -149,9 +150,9 @@ snek_object_t *new_snek_string(char *value) { } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/10-7-refcounting-review/main.c b/src/10-7-refcounting-review/main.c index c753e7c..c0cfa9f 100644 --- a/src/10-7-refcounting-review/main.c +++ b/src/10-7-refcounting-review/main.c @@ -2,4 +2,5 @@ // Q: Why doesn't the snek_add function need to take care of // garbage collecting the resulting object? -// A: +// A: Because we've coded the GC logic to happen automatically whenever a +// reference count hits 0 diff --git a/src/7-6-generic-swap/exercise.c b/src/7-6-generic-swap/exercise.c index a56b671..0450bd0 100644 --- a/src/7-6-generic-swap/exercise.c +++ b/src/7-6-generic-swap/exercise.c @@ -1,13 +1,15 @@ #include #include +#include "bootlib.h" + void swap(void *vp1, void *vp2, size_t size) { if (vp1 == vp2) return; - void *tmp = malloc(size); + void *tmp = boot_malloc(size); if (tmp == NULL) return; memcpy(tmp, vp1, size); memcpy(vp1, vp2, size); memcpy(vp2, tmp, size); - free(tmp); + boot_free(tmp); } diff --git a/src/7-6-generic-swap/main.c b/src/7-6-generic-swap/main.c index 0fcce2e..3c9635e 100644 --- a/src/7-6-generic-swap/main.c +++ b/src/7-6-generic-swap/main.c @@ -1,4 +1,4 @@ -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "exercise.h" @@ -18,7 +18,7 @@ munit_case(RUN, test_generic_ints, { assert_int(i1, ==, 5678, "i1 should be i2's original value"); assert_int(i2, ==, 1234, "i2 should be i1's original value"); - // assert_true(boot_all_freed()); + assert_true(boot_all_freed()); }); munit_case(RUN, test_generic_strings, { @@ -28,7 +28,7 @@ munit_case(RUN, test_generic_strings, { swap(&s1, &s2, sizeof(char *)); assert_string_equal(s1, "adam", "s1 should be s2's original value"); assert_string_equal(s2, "dax", "s2 should be s1's original value"); - // assert_true(boot_all_freed()); + assert_true(boot_all_freed()); }); munit_case(SUBMIT, test_generic_structs, { diff --git a/src/8-1-low-level-stack/main.c b/src/8-1-low-level-stack/main.c index 39bff9f..b04dd7d 100644 --- a/src/8-1-low-level-stack/main.c +++ b/src/8-1-low-level-stack/main.c @@ -1,4 +1,4 @@ -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekstack.h" @@ -8,10 +8,10 @@ munit_case(RUN, create_stack_small, { assert_int(s->count, ==, 0, "No elements in the stack yet"); assert_ptr_not_null(s->data, "Allocates the stack data"); - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(SUBMIT, create_stack_large, { @@ -20,10 +20,10 @@ munit_case(SUBMIT, create_stack_large, { assert_int(s->count, ==, 0, "No elements in the stack yet"); assert_ptr_not_null(s->data, "Allocates the stack data"); - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); int main() { diff --git a/src/8-1-low-level-stack/snekstack.c b/src/8-1-low-level-stack/snekstack.c index d9f3e17..37c4899 100644 --- a/src/8-1-low-level-stack/snekstack.c +++ b/src/8-1-low-level-stack/snekstack.c @@ -1,16 +1,17 @@ #include +#include "bootlib.h" #include "snekstack.h" my_stack_t *stack_new(size_t capacity) { - my_stack_t *stack = (my_stack_t *)malloc(sizeof(my_stack_t)); + my_stack_t *stack = (my_stack_t *)boot_malloc(sizeof(my_stack_t)); if (stack == NULL) return NULL; stack->count = 0; stack->capacity = capacity; - stack->data = malloc(sizeof(void*) * capacity); + stack->data = boot_malloc(sizeof(void*) * capacity); if (stack->data == NULL) { - free(stack); + boot_free(stack); return NULL; } diff --git a/src/8-2-stack-push/main.c b/src/8-2-stack-push/main.c index e9a3673..d74440f 100644 --- a/src/8-2-stack-push/main.c +++ b/src/8-2-stack-push/main.c @@ -1,4 +1,4 @@ -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekstack.h" @@ -9,11 +9,11 @@ munit_case(RUN, create_stack, { assert_ptr_not_null(s->data, "Allocates the stack data"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, push_stack, { @@ -34,11 +34,11 @@ munit_case(RUN, push_stack, { assert_ptr_equal(s->data[0], &a, "element inserted into stack"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(SUBMIT, push_double_capacity, { @@ -62,14 +62,14 @@ munit_case(SUBMIT, push_double_capacity, { assert_int(s->count, ==, 3, "3 elements in the stack"); // Should reallocate memory. - // assert_int_equal(boot_realloc_count(), 1, "Must reallocate memory for stack"); + assert_int_equal(boot_realloc_count(), 1, "Must reallocate memory for stack"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); diff --git a/src/8-2-stack-push/snekstack.c b/src/8-2-stack-push/snekstack.c index 89d5618..e1460af 100644 --- a/src/8-2-stack-push/snekstack.c +++ b/src/8-2-stack-push/snekstack.c @@ -3,12 +3,13 @@ #include #include +#include "bootlib.h" #include "snekstack.h" -void stack_push(my_stack_t *stack, void *obj) { - +void stack_push(my_stack_t *stack, void *obj) +{ if (stack->count >= stack->capacity) { - void **data = realloc(stack->data, sizeof(void *) * stack->capacity * 2); + void **data = boot_realloc(stack->data, sizeof(void *) * stack->capacity * 2); if (data == NULL) return; stack->data = data; stack->capacity *= 2; @@ -21,16 +22,16 @@ void stack_push(my_stack_t *stack, void *obj) { // don't touch below this line my_stack_t *stack_new(size_t capacity) { - my_stack_t *stack = malloc(sizeof(my_stack_t)); + my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); if (stack == NULL) { return NULL; } stack->count = 0; stack->capacity = capacity; - stack->data = malloc(stack->capacity * sizeof(void *)); + stack->data = boot_malloc(stack->capacity * sizeof(void *)); if (stack->data == NULL) { - free(stack); + boot_free(stack); return NULL; } diff --git a/src/8-3-stack-pop/main.c b/src/8-3-stack-pop/main.c index 80e24c1..f15c7f0 100644 --- a/src/8-3-stack-pop/main.c +++ b/src/8-3-stack-pop/main.c @@ -1,4 +1,4 @@ -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekstack.h" @@ -37,11 +37,11 @@ munit_case(RUN, pop_stack, { assert_null(popped, "No remaining elements"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(SUBMIT, pop_stack_empty, { @@ -56,11 +56,11 @@ munit_case(SUBMIT, pop_stack_empty, { assert_null(popped, "Should return null when popping an empty stack"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, push_stack, { @@ -84,11 +84,11 @@ munit_case(RUN, push_stack, { assert_int(s->count, ==, 3, "3 elements in the stack"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, create_stack, { @@ -98,11 +98,11 @@ munit_case(RUN, create_stack, { assert_ptr_not_null(s->data, "Allocates the stack data"); // Clean up our allocated data. - free(s->data); - free(s); + boot_free(s->data); + boot_free(s); // Should be nothing left that is allocated. - // assert(boot_all_freed()); + assert(boot_all_freed()); }); diff --git a/src/8-3-stack-pop/snekstack.c b/src/8-3-stack-pop/snekstack.c index 5180f43..070b4ed 100644 --- a/src/8-3-stack-pop/snekstack.c +++ b/src/8-3-stack-pop/snekstack.c @@ -2,6 +2,7 @@ #include #include +#include "bootlib.h" #include "snekstack.h" void *stack_pop(my_stack_t *stack) { @@ -15,7 +16,7 @@ void *stack_pop(my_stack_t *stack) { void stack_push(my_stack_t *stack, void *obj) { if (stack->count == stack->capacity) { stack->capacity *= 2; - void **temp = realloc(stack->data, stack->capacity * sizeof(void *)); + void **temp = boot_realloc(stack->data, stack->capacity * sizeof(void *)); if (temp == NULL) { stack->capacity /= 2; @@ -29,16 +30,16 @@ void stack_push(my_stack_t *stack, void *obj) { } my_stack_t *stack_new(size_t capacity) { - my_stack_t *stack = malloc(sizeof(my_stack_t)); + my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); if (stack == NULL) { return NULL; } stack->count = 0; stack->capacity = capacity; - stack->data = malloc(stack->capacity * sizeof(void *)); + stack->data = boot_malloc(stack->capacity * sizeof(void *)); if (stack->data == NULL) { - free(stack); + boot_free(stack); return NULL; } diff --git a/src/8-4-stack-free/main.c b/src/8-4-stack-free/main.c index 5c076f7..7c7a182 100644 --- a/src/8-4-stack-free/main.c +++ b/src/8-4-stack-free/main.c @@ -1,4 +1,4 @@ -// #include "bootlib.h" +#include "bootlib.h" #include "munit.h" #include "snekstack.h" @@ -37,7 +37,7 @@ munit_case(RUN, pop_stack, { assert_null(popped, "No remaining elements"); stack_free(s); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, push_stack, { @@ -61,7 +61,7 @@ munit_case(RUN, push_stack, { assert_int(s->count, ==, 3, "3 elements in the stack"); stack_free(s); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); munit_case(RUN, create_stack, { @@ -71,7 +71,7 @@ munit_case(RUN, create_stack, { assert_ptr_not_null(s->data, "Allocates the stack data"); stack_free(s); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); int main() { diff --git a/src/8-4-stack-free/snekstack.c b/src/8-4-stack-free/snekstack.c index 310cebf..c427bf1 100644 --- a/src/8-4-stack-free/snekstack.c +++ b/src/8-4-stack-free/snekstack.c @@ -2,17 +2,18 @@ #include #include +#include "bootlib.h" #include "snekstack.h" void stack_free(my_stack_t *stack) { if (stack == NULL) return; if (stack->data != NULL) { - free(stack->data); + boot_free(stack->data); stack->data = NULL; } - free(stack); + boot_free(stack); } // don't touch below this line @@ -29,7 +30,7 @@ void *stack_pop(my_stack_t *stack) { void stack_push(my_stack_t *stack, void *obj) { if (stack->count == stack->capacity) { stack->capacity *= 2; - void **temp = realloc(stack->data, stack->capacity * sizeof(void *)); + void **temp = boot_realloc(stack->data, stack->capacity * sizeof(void *)); if (temp == NULL) { stack->capacity /= 2; exit(1); @@ -42,16 +43,16 @@ void stack_push(my_stack_t *stack, void *obj) { } my_stack_t *stack_new(size_t capacity) { - my_stack_t *stack = malloc(sizeof(my_stack_t)); + my_stack_t *stack = boot_malloc(sizeof(my_stack_t)); if (stack == NULL) { return NULL; } stack->count = 0; stack->capacity = capacity; - stack->data = malloc(stack->capacity * sizeof(void *)); + stack->data = boot_malloc(stack->capacity * sizeof(void *)); if (stack->data == NULL) { - free(stack); + boot_free(stack); return NULL; } diff --git a/src/9-3-float/main.c b/src/9-3-float/main.c index bda0e4d..83de8ee 100644 --- a/src/9-3-float/main.c +++ b/src/9-3-float/main.c @@ -1,5 +1,6 @@ #include +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -7,8 +8,8 @@ munit_case(RUN, test_positive, { snek_object_t *obj = new_snek_float(42); assert_float(obj->data.v_float, ==, 42, "Must accept positive values"); - free(obj); - // assert(boot_all_freed()); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_zero, { @@ -17,8 +18,8 @@ munit_case(SUBMIT, test_zero, { assert_float(obj->kind, ==, FLOAT, "Must set type to FLOAT"); assert_float(obj->data.v_float, ==, 0.0, "Must accept 0.0"); - free(obj); - // assert(boot_all_freed()); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_negative, { @@ -27,8 +28,8 @@ munit_case(SUBMIT, test_negative, { assert_float(obj->kind, ==, FLOAT, "Must set type to FLOAT"); assert_float(obj->data.v_float, ==, -5.0, "Must accept negative numbers"); - free(obj); - // assert(boot_all_freed()); + boot_free(obj); + assert(boot_all_freed()); }); int main() { diff --git a/src/9-3-float/snekobject.c b/src/9-3-float/snekobject.c index cc6ad48..ec2697c 100644 --- a/src/9-3-float/snekobject.c +++ b/src/9-3-float/snekobject.c @@ -1,9 +1,10 @@ #include +#include "bootlib.h" #include "snekobject.h" snek_object_t *new_snek_float(float value) { - snek_object_t *obj = (snek_object_t *)malloc(sizeof(snek_object_t)); + snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); if (obj == NULL) return NULL; obj->kind = FLOAT; obj->data.v_float = value; @@ -13,7 +14,7 @@ snek_object_t *new_snek_float(float value) { // don't touch below this line snek_object_t *new_snek_integer(int value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } diff --git a/src/9-4-string/main.c b/src/9-4-string/main.c index e0f8269..cd974f9 100644 --- a/src/9-4-string/main.c +++ b/src/9-4-string/main.c @@ -1,5 +1,7 @@ +#include #include +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -21,12 +23,14 @@ munit_case(RUN, test_str_copied, { ); // Should allocate memory for the string with null terminator. - // assert_int_equal(boot_alloc_size(), 22, "Must allocate memory for string"); + bool is_32_bit = sizeof(void *) == 4; + int allocated = 14 + (is_32_bit ? 8 : 16); // pointers are larger on x64 + assert_int_equal(boot_alloc_size(), allocated, "Must allocate memory for string"); // Free the string, and then free the object. - free(obj->data.v_string); - free(obj); - // assert(boot_all_freed()); + boot_free(obj->data.v_string); + boot_free(obj); + assert(boot_all_freed()); }); int main() { diff --git a/src/9-4-string/snekobject.c b/src/9-4-string/snekobject.c index 97404ad..94be740 100644 --- a/src/9-4-string/snekobject.c +++ b/src/9-4-string/snekobject.c @@ -2,16 +2,17 @@ #include #include +#include "bootlib.h" #include "snekobject.h" snek_object_t *new_snek_string(char *value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); if (obj == NULL) return NULL; size_t size = strlen(value); - char *str = (char *)malloc(sizeof(char) * size + 1); + char *str = (char *)boot_malloc(sizeof(char) * size + 1); if (str == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -24,7 +25,7 @@ snek_object_t *new_snek_string(char *value) { // don't touch below this line snek_object_t *new_snek_integer(int value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -35,7 +36,7 @@ snek_object_t *new_snek_integer(int value) { } snek_object_t *new_snek_float(float value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } diff --git a/src/9-5-vector3/main.c b/src/9-5-vector3/main.c index b2958c5..59bea0e 100644 --- a/src/9-5-vector3/main.c +++ b/src/9-5-vector3/main.c @@ -1,5 +1,6 @@ #include +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -8,7 +9,7 @@ munit_case(RUN, test_returns_null, { assert_null(vec, "Should return null when input is null"); - // assert(boot_all_freed()); + assert(boot_all_freed()); }); @@ -31,11 +32,11 @@ munit_case(RUN, test_vec_multiple_objects, { assert_int(vec->data.v_vector3.z->data.v_int, ==, 3, "should have correct z"); // Free all of our objects. - free(x); - free(y); - free(z); - free(vec); - // assert(boot_all_freed()); + boot_free(x); + boot_free(y); + boot_free(z); + boot_free(vec); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_vec_same_object, { @@ -62,9 +63,9 @@ munit_case(SUBMIT, test_vec_same_object, { assert_int(vec->data.v_vector3.z->data.v_int, ==, 2, "should have correct z"); // Free all of our objects. - free(i); - free(vec); - // assert(boot_all_freed()); + boot_free(i); + boot_free(vec); + assert(boot_all_freed()); }); int main() { diff --git a/src/9-5-vector3/snekobject.c b/src/9-5-vector3/snekobject.c index 3f9db3c..f67d2a7 100644 --- a/src/9-5-vector3/snekobject.c +++ b/src/9-5-vector3/snekobject.c @@ -1,33 +1,25 @@ #include #include +#include "bootlib.h" #include "snekobject.h" snek_object_t *new_snek_vector3(snek_object_t *x, snek_object_t *y, snek_object_t *z) { if (x == NULL || y == NULL || z == NULL) return NULL; - snek_object_t *obj = (snek_object_t *)malloc(sizeof(snek_object_t)); + snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); if (obj == NULL) return NULL; - snek_vector_t *vec = (snek_vector_t *)malloc(sizeof(snek_vector_t)); - if (vec == NULL) { - free(obj); - return NULL; - } - - vec->x = x; - vec->y = y; - vec->z = z; obj->kind = VECTOR3; - obj->data.v_vector3 = *vec; + obj->data.v_vector3 = (snek_vector_t){ .x = x, .y = y, .z = z }; return obj; } // don't touch below this line snek_object_t *new_snek_integer(int value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -38,7 +30,7 @@ snek_object_t *new_snek_integer(int value) { } snek_object_t *new_snek_float(float value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -49,15 +41,15 @@ snek_object_t *new_snek_float(float value) { } snek_object_t *new_snek_string(char *value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/9-6-arrays/main.c b/src/9-6-arrays/main.c index 2a00bc8..f523f4f 100644 --- a/src/9-6-arrays/main.c +++ b/src/9-6-arrays/main.c @@ -1,5 +1,6 @@ #include +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -9,9 +10,9 @@ munit_case(RUN, test_create_empty_array, { assert_int(obj->kind, ==, ARRAY, "Must set type to ARRAY"); assert_int(obj->data.v_array.size, ==, 2, "Must set size to 2"); - free(obj->data.v_array.elements); - free(obj); - // assert(boot_all_freed()); + boot_free(obj->data.v_array.elements); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_used_calloc, { @@ -20,9 +21,9 @@ munit_case(SUBMIT, test_used_calloc, { assert_ptr_null(obj->data.v_array.elements[0], "Should use calloc"); assert_ptr_null(obj->data.v_array.elements[1], "Should use calloc"); - free(obj->data.v_array.elements); - free(obj); - // assert(boot_all_freed()); + boot_free(obj->data.v_array.elements); + boot_free(obj); + assert(boot_all_freed()); }); int main() { diff --git a/src/9-6-arrays/snekobject.c b/src/9-6-arrays/snekobject.c index 2252514..2f82bc5 100644 --- a/src/9-6-arrays/snekobject.c +++ b/src/9-6-arrays/snekobject.c @@ -1,15 +1,16 @@ #include #include +#include "bootlib.h" #include "snekobject.h" snek_object_t *new_snek_array(size_t size) { - snek_object_t *obj = (snek_object_t *)malloc(sizeof(snek_object_t)); + snek_object_t *obj = (snek_object_t *)boot_malloc(sizeof(snek_object_t)); if (obj == NULL) return NULL; - snek_object_t **arr = (snek_object_t **)calloc(size, sizeof(snek_object_t *)); + snek_object_t **arr = (snek_object_t **)boot_calloc(size, sizeof(snek_object_t *)); if (arr == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -27,7 +28,7 @@ snek_object_t *new_snek_vector3( return NULL; } - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -39,7 +40,7 @@ snek_object_t *new_snek_vector3( } snek_object_t *new_snek_integer(int value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -50,7 +51,7 @@ snek_object_t *new_snek_integer(int value) { } snek_object_t *new_snek_float(float value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -61,15 +62,15 @@ snek_object_t *new_snek_float(float value) { } snek_object_t *new_snek_string(char *value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/9-7-get-and-set/main.c b/src/9-7-get-and-set/main.c index 3d4a9cc..6efdb0f 100644 --- a/src/9-7-get-and-set/main.c +++ b/src/9-7-get-and-set/main.c @@ -1,5 +1,6 @@ #include +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -25,12 +26,12 @@ munit_case(RUN, test_array, { assert_int(retrieved_second->kind, ==, INTEGER, "Should be a integer"); assert_ptr(second, ==, retrieved_second, "Should be the same object"); - free(first->data.v_string); - free(first); - free(second); - free(obj->data.v_array.elements); - free(obj); - // assert(boot_all_freed()); + boot_free(first->data.v_string); + boot_free(first); + boot_free(second); + boot_free(obj->data.v_array.elements); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(RUN, test_set_outside_bounds, { @@ -46,11 +47,11 @@ munit_case(RUN, test_set_outside_bounds, { assert_false(snek_array_set(obj, 100, outside)); // Free memory - free(outside->data.v_string); - free(outside); - free(obj->data.v_array.elements); - free(obj); - // assert(boot_all_freed()); + boot_free(outside->data.v_string); + boot_free(outside); + boot_free(obj->data.v_array.elements); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_get_outside_bounds, { @@ -62,11 +63,11 @@ munit_case(SUBMIT, test_get_outside_bounds, { // Outside of bound assert_null(snek_array_get(obj, 1), "Should not access outside the array"); - free(first->data.v_string); - free(first); - free(obj->data.v_array.elements); - free(obj); - // assert(boot_all_freed()); + boot_free(first->data.v_string); + boot_free(first); + boot_free(obj->data.v_array.elements); + boot_free(obj); + assert(boot_all_freed()); }); int main() { diff --git a/src/9-7-get-and-set/snekobject.c b/src/9-7-get-and-set/snekobject.c index 3463e2d..5dcee5a 100644 --- a/src/9-7-get-and-set/snekobject.c +++ b/src/9-7-get-and-set/snekobject.c @@ -2,6 +2,7 @@ #include #include +#include "bootlib.h" #include "snekobject.h" bool snek_array_set(snek_object_t *snek_obj, size_t index, snek_object_t *value) { @@ -24,14 +25,14 @@ snek_object_t *snek_array_get(snek_object_t *snek_obj, size_t index) { // don't touch below this line snek_object_t *new_snek_array(size_t size) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } - snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); + snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); if (elements == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -47,7 +48,7 @@ snek_object_t *new_snek_vector3( return NULL; } - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -59,7 +60,7 @@ snek_object_t *new_snek_vector3( } snek_object_t *new_snek_integer(int value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -70,7 +71,7 @@ snek_object_t *new_snek_integer(int value) { } snek_object_t *new_snek_float(float value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -81,15 +82,15 @@ snek_object_t *new_snek_float(float value) { } snek_object_t *new_snek_string(char *value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/9-8-length/main.c b/src/9-8-length/main.c index 9518a1d..10ffc55 100644 --- a/src/9-8-length/main.c +++ b/src/9-8-length/main.c @@ -1,3 +1,4 @@ +#include "bootlib.h" #include "munit.h" #include "snekobject.h" @@ -5,16 +6,16 @@ munit_case(RUN, test_integer, { snek_object_t *obj = new_snek_integer(42); assert_int(snek_length(obj), ==, 1, "Integers are length 1"); - free(obj); - // assert(boot_all_freed()); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(RUN, test_float, { snek_object_t *obj = new_snek_float(3.14); assert_int(snek_length(obj), ==, 1, "Floats are length 1"); - free(obj); - // assert(boot_all_freed()); + boot_free(obj); + assert(boot_all_freed()); }); munit_case(RUN, test_string, { @@ -26,11 +27,11 @@ munit_case(RUN, test_string, { snek_length(longer), ==, strlen("hello, world"), "Should use strlen" ); - free(shorter->data.v_string); - free(shorter); - free(longer->data.v_string); - free(longer); - // assert(boot_all_freed()); + boot_free(shorter->data.v_string); + boot_free(shorter); + boot_free(longer->data.v_string); + boot_free(longer); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_vector3, { @@ -38,9 +39,9 @@ munit_case(SUBMIT, test_vector3, { snek_object_t *vec = new_snek_vector3(i, i, i); assert_int(snek_length(vec), ==, 3, "Vec3 always has length 3"); - free(i); - free(vec); - // assert(boot_all_freed()); + boot_free(i); + boot_free(vec); + assert(boot_all_freed()); }); munit_case(SUBMIT, test_array, { @@ -52,10 +53,10 @@ munit_case(SUBMIT, test_array, { assert_int(snek_length(arr), ==, 4, "Length of array should be its size"); - free(i); - free(arr->data.v_array.elements); - free(arr); - // assert(boot_all_freed()); + boot_free(i); + boot_free(arr->data.v_array.elements); + boot_free(arr); + assert(boot_all_freed()); }); int main() { diff --git a/src/9-8-length/snekobject.c b/src/9-8-length/snekobject.c index 48f4e6a..0e84c82 100644 --- a/src/9-8-length/snekobject.c +++ b/src/9-8-length/snekobject.c @@ -1,3 +1,4 @@ +#include "bootlib.h" #include #include @@ -15,14 +16,14 @@ int snek_length(snek_object_t *obj) { // don't touch below this line snek_object_t *new_snek_array(size_t size) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } - snek_object_t **elements = calloc(size, sizeof(snek_object_t *)); + snek_object_t **elements = boot_calloc(size, sizeof(snek_object_t *)); if (elements == NULL) { - free(obj); + boot_free(obj); return NULL; } @@ -73,7 +74,7 @@ snek_object_t *new_snek_vector3( return NULL; } - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -85,7 +86,7 @@ snek_object_t *new_snek_vector3( } snek_object_t *new_snek_integer(int value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -96,7 +97,7 @@ snek_object_t *new_snek_integer(int value) { } snek_object_t *new_snek_float(float value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } @@ -107,15 +108,15 @@ snek_object_t *new_snek_float(float value) { } snek_object_t *new_snek_string(char *value) { - snek_object_t *obj = malloc(sizeof(snek_object_t)); + snek_object_t *obj = boot_malloc(sizeof(snek_object_t)); if (obj == NULL) { return NULL; } int len = strlen(value); - char *dst = malloc(len + 1); + char *dst = boot_malloc(len + 1); if (dst == NULL) { - free(obj); + boot_free(obj); return NULL; } diff --git a/src/bootlib.c b/src/bootlib.c new file mode 100644 index 0000000..1249fa2 --- /dev/null +++ b/src/bootlib.c @@ -0,0 +1,127 @@ +#include +#include +#include + +#include "bootlib.h" + +typedef struct Allocation { + void* ptr; + size_t size; + bool freed; + struct Allocation *next; +} Allocation; + +static Allocation *allocations = NULL; // backwards linked list +static int allocated_count = 0; +static int reallocated_count = 0; +static int total_size = 0; + +void *create_allocation(void *allocated, size_t size); +Allocation *find_allocation(void *ptr); + +void *boot_malloc(size_t size) +{ + void *allocated = malloc(size); + if (allocated == NULL) return NULL; + + return create_allocation(allocated, size); +} + +void *boot_calloc (size_t num, size_t size) +{ + void *allocated = calloc(num, size); + if (allocated == NULL) return NULL; + + return create_allocation(allocated, num * size); +} + +void *boot_realloc(void* ptr, size_t size) +{ + if (ptr == NULL) return NULL; + + void *allocated = realloc(ptr, size); + if (allocated == NULL) return NULL; + + reallocated_count++; + + Allocation *allocation = find_allocation(ptr); + if (allocated == ptr) { // realloc resized the existing ptr's memory block + allocation->size = size; + total_size += size - allocation->size; + return allocated; + } + allocation->freed = true; + allocated_count--; + total_size -= allocation->size; + + return create_allocation(allocated, size); +} + +void boot_free (void *ptr) +{ + if (ptr == NULL) return; + + free(ptr); + + Allocation *allocation = find_allocation(ptr); + allocation->freed = true; + allocated_count--; + total_size -= allocation->size; +} + +// ----------------------------------------- + +bool boot_all_freed() +{ + return allocated_count == 0; +} + +bool boot_is_freed(void *ptr) +{ + return find_allocation(ptr)->freed; +} + +int boot_realloc_count() +{ + return reallocated_count; +} + +int boot_alloc_size() +{ + return total_size; +} + +// ----------------------------------------- + +void *create_allocation(void *allocated, size_t size) +{ + if (allocated == NULL) return NULL; + + total_size += size; + + Allocation *allocation = (Allocation *)malloc(sizeof(Allocation)); + if (allocation == NULL) return NULL; + allocation->ptr = allocated; + allocation->size = size; + allocation->freed = false; + allocation->next = allocations; + allocations = allocation; + + allocated_count++; + + return allocated; +} + +Allocation *find_allocation(void *ptr) +{ + if (allocations == NULL) return NULL; + + Allocation *current = allocations; + while (true) { + if (current == NULL) return NULL; + if (current->ptr == ptr) return current; + current = current->next; + } + + return NULL; +} diff --git a/src/bootlib.h b/src/bootlib.h new file mode 100644 index 0000000..09f5399 --- /dev/null +++ b/src/bootlib.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +void *boot_malloc(size_t size); +void *boot_calloc (size_t num, size_t size); +void *boot_realloc(void* ptr, size_t size); +void boot_free (void *ptr); + +// ----------------------------------------- + +bool boot_all_freed(); +bool boot_is_freed(void *ptr); +int boot_realloc_count(); +int boot_alloc_size(); diff --git a/src/munit.h b/src/munit.h index f9c94f0..312d2c6 100644 --- a/src/munit.h +++ b/src/munit.h @@ -1,3 +1,5 @@ +#pragma once + #define MUNIT_ENABLE_ASSERT_ALIASES #include "../vendor/munit/munit.h" @@ -40,6 +42,9 @@ #define assert_int(A, OP, B, MSG) \ munit_assert_int(A, OP, B, MSG); +#define assert_int_equal(A, B, MSG) \ + munit_assert_int(A, ==, B, MSG); + #undef assert_uint #define assert_uint(A, OP, B, MSG) \ munit_assert_uint(A, OP, B);