Browse Source

Implement allocation checking in the unit tests

master
Riyyi 5 days ago
parent
commit
ba0d496a3c
  1. 1
      CMakeLists.txt
  2. 9
      README.org
  3. 18
      src/10-4-decrement-and-free/main.c
  4. 17
      src/10-4-decrement-and-free/snekobject.c
  5. 34
      src/10-5-vectors/main.c
  6. 15
      src/10-5-vectors/snekobject.c
  7. 38
      src/10-6-arrays/main.c
  8. 17
      src/10-6-arrays/snekobject.c
  9. 3
      src/10-7-refcounting-review/main.c
  10. 6
      src/7-6-generic-swap/exercise.c
  11. 6
      src/7-6-generic-swap/main.c
  12. 14
      src/8-1-low-level-stack/main.c
  13. 7
      src/8-1-low-level-stack/snekstack.c
  14. 22
      src/8-2-stack-push/main.c
  15. 13
      src/8-2-stack-push/snekstack.c
  16. 26
      src/8-3-stack-pop/main.c
  17. 9
      src/8-3-stack-pop/snekstack.c
  18. 8
      src/8-4-stack-free/main.c
  19. 13
      src/8-4-stack-free/snekstack.c
  20. 13
      src/9-3-float/main.c
  21. 5
      src/9-3-float/snekobject.c
  22. 12
      src/9-4-string/main.c
  23. 11
      src/9-4-string/snekobject.c
  24. 19
      src/9-5-vector3/main.c
  25. 24
      src/9-5-vector3/snekobject.c
  26. 13
      src/9-6-arrays/main.c
  27. 19
      src/9-6-arrays/snekobject.c
  28. 33
      src/9-7-get-and-set/main.c
  29. 19
      src/9-7-get-and-set/snekobject.c
  30. 33
      src/9-8-length/main.c
  31. 19
      src/9-8-length/snekobject.c
  32. 127
      src/bootlib.c
  33. 16
      src/bootlib.h
  34. 5
      src/munit.h

1
CMakeLists.txt

@ -33,6 +33,7 @@ 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)

9
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~

18
src/10-4-decrement-and-free/main.c

@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
// #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() {

17
src/10-4-decrement-and-free/snekobject.c

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#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;
}

34
src/10-5-vectors/main.c

@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
// #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() {

15
src/10-5-vectors/snekobject.c

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#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;
}

38
src/10-6-arrays/main.c

@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
// #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() {

17
src/10-6-arrays/snekobject.c

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#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;
}

3
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

6
src/7-6-generic-swap/exercise.c

@ -1,13 +1,15 @@
#include <stdlib.h>
#include <string.h>
#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);
}

6
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, {

14
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() {

7
src/8-1-low-level-stack/snekstack.c

@ -1,16 +1,17 @@
#include <stdlib.h>
#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;
}

22
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());
});

13
src/8-2-stack-push/snekstack.c

@ -3,12 +3,13 @@
#include <stdlib.h>
#include <string.h>
#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;
}

26
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());
});

9
src/8-3-stack-pop/snekstack.c

@ -2,6 +2,7 @@
#include <stddef.h>
#include <stdlib.h>
#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;
}

8
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() {

13
src/8-4-stack-free/snekstack.c

@ -2,17 +2,18 @@
#include <stddef.h>
#include <stdlib.h>
#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;
}

13
src/9-3-float/main.c

@ -1,5 +1,6 @@
#include <stdlib.h>
#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() {

5
src/9-3-float/snekobject.c

@ -1,9 +1,10 @@
#include <stdlib.h>
#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;
}

12
src/9-4-string/main.c

@ -1,5 +1,7 @@
#include <stdbool.h>
#include <stdlib.h>
#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() {

11
src/9-4-string/snekobject.c

@ -2,16 +2,17 @@
#include <stdlib.h>
#include <string.h>
#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;
}

19
src/9-5-vector3/main.c

@ -1,5 +1,6 @@
#include <stdlib.h>
#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() {

24
src/9-5-vector3/snekobject.c

@ -1,33 +1,25 @@
#include <stdlib.h>
#include <string.h>
#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;
}

13
src/9-6-arrays/main.c

@ -1,5 +1,6 @@
#include <stdlib.h>
#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() {

19
src/9-6-arrays/snekobject.c

@ -1,15 +1,16 @@
#include <stdlib.h>
#include <string.h>
#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;
}

33
src/9-7-get-and-set/main.c

@ -1,5 +1,6 @@
#include <stdlib.h>
#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() {

19
src/9-7-get-and-set/snekobject.c

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#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;
}

33
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() {

19
src/9-8-length/snekobject.c

@ -1,3 +1,4 @@
#include "bootlib.h"
#include <stdlib.h>
#include <string.h>
@ -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;
}

127
src/bootlib.c

@ -0,0 +1,127 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#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;
}

16
src/bootlib.h

@ -0,0 +1,16 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
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();

5
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);

Loading…
Cancel
Save