diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 43c93cc..b81841f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,16 +12,16 @@ jobs: - name: setup run: sudo apt-get update && sudo apt-get -y -qq install clang-tidy cppcheck cflow spell gcc-powerpc64-linux-gnu gcc-powerpc-linux-gnu gcc-aarch64-linux-gnu gcc-i686-linux-gnu qemu-user-binfmt - name: test-main - run: make LLVM_VERSION=14 + run: make LLVM_VERSION=14 CC=clang working-directory: . - name: bench-main - run: make LLVM_VERSION=14 bench + run: make LLVM_VERSION=14 CC=clang bench working-directory: . - name: test-multiplatform - run: make test-multiplatform + run: make test-multiplatform CC=clang working-directory: . - name: test-cpp-translation-unit - run: make LLVM_VERSION=14 test-cpp-translation-unit + run: make LLVM_VERSION=14 CC=clang CXX=clang++ test-cpp-translation-unit working-directory: . - uses: actions/upload-artifact@v3 if: failure() diff --git a/Makefile b/Makefile index 2de6ac2..983e013 100644 --- a/Makefile +++ b/Makefile @@ -7,12 +7,13 @@ MAKEFLAGS += --no-builtin-rules .SUFFIXES: LLVM_VERSION?=11 -CC=clang-$(LLVM_VERSION) -CXX=clang++-$(LLVM_VERSION) -CFLAGS=-std=c99 --coverage -pg -no-pie -fno-builtin -g -O0 -Og -fstrict-aliasing -fstack-protector-all -fsanitize=undefined -fsanitize=bounds -pedantic -Wall -Wextra -Werror -Wfatal-errors -Wformat=2 -Wformat-security -Wconversion -Wcast-qual -Wnull-dereference -Wstack-protector -Warray-bounds -Warray-bounds-pointer-arithmetic -Wassign-enum -Wbad-function-cast -Wconditional-uninitialized -Wfloat-equal -Wformat-type-confusion -Widiomatic-parentheses -Wimplicit-fallthrough -Wloop-analysis -Wpointer-arith -Wshift-sign-overflow -Wshorten-64-to-32 -Wswitch-enum -Wtautological-constant-in-range-compare -Wunreachable-code-aggressive -Wthread-safety -Wthread-safety-beta -Wcomma -Wdeclaration-after-statement -D_FORTIFY_SOURCE=3 -CXXFLAGS=-std=c++11 --coverage -pg -no-pie -fno-builtin -g -O0 -Og -fstrict-aliasing -fstack-protector-all -fsanitize=undefined -fsanitize=bounds -pedantic -Wall -Wextra -Wformat=2 -Wformat-security -Wconversion -Wcast-qual -Wnull-dereference -Wstack-protector -Warray-bounds -Warray-bounds-pointer-arithmetic -Wassign-enum -Wbad-function-cast -Wconditional-uninitialized -Wfloat-equal -Wformat-type-confusion -Widiomatic-parentheses -Wimplicit-fallthrough -Wloop-analysis -Wpointer-arith -Wshift-sign-overflow -Wshorten-64-to-32 -Wswitch-enum -Wtautological-constant-in-range-compare -Wunreachable-code-aggressive -Wthread-safety -Wthread-safety-beta -Wcomma -Wdeclaration-after-statement -D_FORTIFY_SOURCE=3 +CC?=clang-$(LLVM_VERSION) +CXX?=clang++-$(LLVM_VERSION) +CFLAGS?=-std=c99 --coverage -pg -no-pie -fno-builtin -g -O0 -Og -fstrict-aliasing -fstack-protector-all -fsanitize=undefined -fsanitize=bounds -pedantic -Wall -Wextra -Werror -Wfatal-errors -Wformat=2 -Wformat-security -Wconversion -Wcast-qual -Wnull-dereference -Wstack-protector -Warray-bounds -Warray-bounds-pointer-arithmetic -Wassign-enum -Wbad-function-cast -Wconditional-uninitialized -Wfloat-equal -Wformat-type-confusion -Widiomatic-parentheses -Wimplicit-fallthrough -Wloop-analysis -Wpointer-arith -Wshift-sign-overflow -Wshorten-64-to-32 -Wswitch-enum -Wtautological-constant-in-range-compare -Wunreachable-code-aggressive -Wthread-safety -Wthread-safety-beta -Wcomma -Wdeclaration-after-statement -D_FORTIFY_SOURCE=3 +CXXFLAGS?=-std=c++11 --coverage -pg -no-pie -fno-builtin -g -O0 -Og -fstrict-aliasing -fstack-protector-all -fsanitize=undefined -fsanitize=bounds -pedantic -Wall -Wextra -Wformat=2 -Wformat-security -Wconversion -Wcast-qual -Wnull-dereference -Wstack-protector -Warray-bounds -Warray-bounds-pointer-arithmetic -Wassign-enum -Wbad-function-cast -Wconditional-uninitialized -Wfloat-equal -Wformat-type-confusion -Widiomatic-parentheses -Wimplicit-fallthrough -Wloop-analysis -Wpointer-arith -Wshift-sign-overflow -Wshorten-64-to-32 -Wswitch-enum -Wtautological-constant-in-range-compare -Wunreachable-code-aggressive -Wthread-safety -Wthread-safety-beta -Wcomma -Wdeclaration-after-statement -D_FORTIFY_SOURCE=3 LLVM_COV?=llvm-cov-$(LLVM_VERSION) CPPCHECK?=cppcheck + TESTS_SRC=tests.c TESTCXX_SRC=testcxx.cpp LIB_SRC=buddy_alloc.h diff --git a/bench.c b/bench.c index 40c659c..2e33f43 100644 --- a/bench.c +++ b/bench.c @@ -14,27 +14,31 @@ #include "buddy_alloc.h" #undef BUDDY_ALLOC_IMPLEMENTATION -double test_malloc(size_t alloc_size); +double test_malloc(struct buddy *buddy, size_t alloc_size); double test_malloc_firstfit(size_t alloc_size); void *freeing_callback(void *ctx, void *addr, size_t slot_size, size_t allocated); int main() { setvbuf(stdout, NULL, _IONBF, 0); + size_t arena_size = 1 << 30; + unsigned char *buddy_buf = malloc(buddy_sizeof_alignment(arena_size, 64)); + unsigned char *data_buf = malloc(arena_size); + struct buddy *buddy = buddy_init_alignment(buddy_buf, data_buf, arena_size, 64); + double total = 0; for (size_t i = 0; i <= 6; i++) { - total += test_malloc(64 << i); + total += test_malloc(buddy, 64 << i); + total += test_malloc(buddy, 64 << i); + total += test_malloc(buddy, 64 << i); } printf("Total malloc runtime was %f seconds.\n\n", total); -} -double test_malloc(size_t alloc_size) { - - size_t arena_size = 1 << 30; - unsigned char *buddy_buf = malloc(buddy_sizeof(arena_size)); - unsigned char *data_buf = malloc(arena_size); - struct buddy *buddy = buddy_init(buddy_buf, data_buf, arena_size); + free(data_buf); + free(buddy_buf); +} +double test_malloc(struct buddy *buddy, size_t alloc_size) { printf("Starting test with alloc size [%zu].\n", alloc_size); time_t start_time = time(NULL); @@ -53,9 +57,6 @@ double test_malloc(size_t alloc_size) { printf("Test took %.f seconds in total. Allocation: %.f freeing: %.f\n", delta, difftime(alloc_time, start_time), difftime(end_time, alloc_time)); - free(data_buf); - free(buddy_buf); - return delta; } diff --git a/buddy_alloc.h b/buddy_alloc.h index b711c09..0df9dce 100644 --- a/buddy_alloc.h +++ b/buddy_alloc.h @@ -17,13 +17,14 @@ #ifndef BUDDY_HEADER #include +#include #include #include +#include +#include #ifndef BUDDY_PRINTF #include #endif -#include -#include #endif #ifdef __cplusplus @@ -92,11 +93,11 @@ void *buddy_malloc(struct buddy *buddy, size_t requested_size); void *buddy_calloc(struct buddy *buddy, size_t members_count, size_t member_size); /* Realloc semantics are a joke. See realloc. */ -void *buddy_realloc(struct buddy *buddy, void *ptr, size_t requested_size); +void *buddy_realloc(struct buddy *buddy, void *ptr, size_t requested_size, bool ignore_data); /* Realloc-like behavior that checks for overflow. See reallocarray*/ void *buddy_reallocarray(struct buddy *buddy, void *ptr, - size_t members_count, size_t member_size); + size_t members_count, size_t member_size, bool ignore_data); /* Use the specified buddy to free memory. See free. */ void buddy_free(struct buddy *buddy, void *ptr); @@ -338,7 +339,7 @@ static inline void bitset_set(unsigned char *bitset, size_t pos); static inline void bitset_clear(unsigned char *bitset, size_t pos); -static inline unsigned int bitset_test(const unsigned char *bitset, size_t pos); +static inline unsigned char bitset_test(const unsigned char *bitset, size_t pos); static void bitset_shift_left(unsigned char *bitset, size_t from_pos, size_t to_pos, size_t by); @@ -707,7 +708,7 @@ void *buddy_calloc(struct buddy *buddy, size_t members_count, size_t member_size return result; } -void *buddy_realloc(struct buddy *buddy, void *ptr, size_t requested_size) { +void *buddy_realloc(struct buddy *buddy, void *ptr, size_t requested_size, bool ignore_data) { struct buddy_tree *tree; struct buddy_tree_pos origin, new_pos; size_t current_depth, target_depth; @@ -758,26 +759,30 @@ void *buddy_realloc(struct buddy *buddy, void *ptr, size_t requested_size) { return ptr; } - /* Copy the content */ - source = address_for_position(buddy, origin); destination = address_for_position(buddy, new_pos); - memmove(destination, source, size_for_depth(buddy, - current_depth > target_depth ? current_depth : target_depth)); + + if (! ignore_data) { + /* Copy the content */ + source = address_for_position(buddy, origin); + memmove(destination, source, size_for_depth(buddy, + current_depth > target_depth ? current_depth : target_depth)); + } + /* Allocate and return */ buddy_tree_mark(tree, new_pos); return destination; } void *buddy_reallocarray(struct buddy *buddy, void *ptr, - size_t members_count, size_t member_size) { + size_t members_count, size_t member_size, bool ignore_data) { if (members_count == 0 || member_size == 0) { - return buddy_realloc(buddy, ptr, 0); + return buddy_realloc(buddy, ptr, 0, ignore_data); } /* Check for overflow */ if ((members_count * member_size)/members_count != member_size) { return NULL; } - return buddy_realloc(buddy, ptr, members_count * member_size); + return buddy_realloc(buddy, ptr, members_count * member_size, ignore_data); } void buddy_free(struct buddy *buddy, void *ptr) { @@ -1218,7 +1223,7 @@ static void buddy_tree_populate_size_for_order(struct buddy_tree *t); static inline size_t buddy_tree_size_for_order(struct buddy_tree *t, uint8_t to); static void write_to_internal_position(unsigned char *bitset, struct internal_position pos, size_t value); static size_t read_from_internal_position(unsigned char *bitset, struct internal_position pos); -static size_t compare_with_internal_position(unsigned char *bitset, struct internal_position pos, size_t value); +static inline unsigned char compare_with_internal_position(unsigned char *bitset, struct internal_position pos, size_t value); static inline size_t size_for_order(uint8_t order, uint8_t to) { size_t result = 0; @@ -1484,7 +1489,7 @@ static size_t read_from_internal_position(unsigned char *bitset, struct internal return bitset_count_range(bitset, pos.bitset_location, pos.bitset_location+pos.local_offset-1); } -static size_t compare_with_internal_position(unsigned char *bitset, struct internal_position pos, size_t value) { +static inline unsigned char compare_with_internal_position(unsigned char *bitset, struct internal_position pos, size_t value) { return bitset_test(bitset, pos.bitset_location+value-1); } @@ -1602,6 +1607,7 @@ static struct buddy_tree_pos buddy_tree_find_free(struct buddy_tree *t, uint8_t uint8_t target_status; size_t current_depth, right_status; struct internal_position left_internal, right_internal; + unsigned char *tree_bits; current_pos = buddy_tree_root(); target_status = target_depth - 1; @@ -1609,6 +1615,7 @@ static struct buddy_tree_pos buddy_tree_find_free(struct buddy_tree *t, uint8_t if (buddy_tree_status(t, current_pos) > target_status) { return INVALID_POS; /* No position available down the tree */ } + tree_bits = buddy_tree_bits(t); while (current_depth != target_depth) { /* Advance criteria */ target_status -= 1; @@ -1622,15 +1629,15 @@ static struct buddy_tree_pos buddy_tree_find_free(struct buddy_tree *t, uint8_t right_internal = left_internal; right_internal.bitset_location += right_internal.local_offset; /* advance to the right */ - if (compare_with_internal_position(buddy_tree_bits(t), left_internal, target_status+1)) { /* left branch is busy, pick right */ + if (compare_with_internal_position(tree_bits, left_internal, target_status+1)) { /* left branch is busy, pick right */ current_pos = right_pos; - } else if (compare_with_internal_position(buddy_tree_bits(t), right_internal, target_status+1)) { /* right branch is busy, pick left */ + } else if (compare_with_internal_position(tree_bits, right_internal, target_status+1)) { /* right branch is busy, pick left */ current_pos = left_pos; } else { /* One of the child nodes must be read in order to compare it to its sibling. */ - right_status = read_from_internal_position(buddy_tree_bits(t), right_internal); + right_status = read_from_internal_position(tree_bits, right_internal); if (right_status) { - if (compare_with_internal_position(buddy_tree_bits(t), left_internal, right_status)) { + if (compare_with_internal_position(tree_bits, left_internal, right_status)) { current_pos = left_pos; /* Left is equal or more busy than right, prefer left */ } else { current_pos = right_pos; @@ -1798,7 +1805,7 @@ static inline void bitset_clear(unsigned char *bitset, size_t pos) { bitset[bucket] &= ~bitset_index_mask[index]; } -static inline unsigned int bitset_test(const unsigned char *bitset, size_t pos) { +static inline unsigned char bitset_test(const unsigned char *bitset, size_t pos) { size_t bucket = pos / CHAR_BIT; size_t index = pos % CHAR_BIT; return bitset[bucket] & bitset_index_mask[index]; diff --git a/test-fuzz.c b/test-fuzz.c index cbc9863..ba7e1ca 100644 --- a/test-fuzz.c +++ b/test-fuzz.c @@ -25,7 +25,7 @@ int main(void) } else { size = size*2; } - buddy_realloc(b, allocs[slot], size); + buddy_realloc(b, allocs[slot], size, true); } assert(buddy_tree_check_invariant(tree, buddy_tree_root()) == 0); allocs[slot] = 0; @@ -39,4 +39,4 @@ int main(void) assert(buddy_tree_check_invariant(tree, buddy_tree_root()) == 0); } } -} \ No newline at end of file +} diff --git a/tests.c b/tests.c index f2d4ca9..6a405c1 100644 --- a/tests.c +++ b/tests.c @@ -1151,7 +1151,7 @@ void test_buddy_realloc_01(void) { buddy = buddy_init(buddy_buf, data_buf, 4096); assert(buddy != NULL); /* This is implementation-defined! */ - result = buddy_realloc(buddy, NULL, 0); + result = buddy_realloc(buddy, NULL, 0, false); assert(result != NULL); free(buddy_buf); } @@ -1164,7 +1164,7 @@ void test_buddy_realloc_02(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 4096); assert(buddy != NULL); - result = buddy_realloc(buddy, NULL, 128); + result = buddy_realloc(buddy, NULL, 128, false); assert(result == data_buf); free(buddy_buf); } @@ -1177,9 +1177,9 @@ void test_buddy_realloc_03(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 4096); assert(buddy != NULL); - result = buddy_realloc(buddy, NULL, 128); + result = buddy_realloc(buddy, NULL, 128, false); assert(result == data_buf); - result = buddy_realloc(buddy, result, 128); + result = buddy_realloc(buddy, result, 128, false); assert(result == data_buf); free(buddy_buf); } @@ -1192,9 +1192,9 @@ void test_buddy_realloc_04(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 4096); assert(buddy != NULL); - result = buddy_realloc(buddy, NULL, 128); + result = buddy_realloc(buddy, NULL, 128, false); assert(result == data_buf); - result = buddy_realloc(buddy, result, 64); + result = buddy_realloc(buddy, result, 64, false); assert(result == data_buf); free(buddy_buf); } @@ -1207,9 +1207,9 @@ void test_buddy_realloc_05(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 512); assert(buddy != NULL); - result = buddy_realloc(buddy, NULL, 128); + result = buddy_realloc(buddy, NULL, 128, false); assert(result == data_buf); - result = buddy_realloc(buddy, result, 256); + result = buddy_realloc(buddy, result, 256, false); assert(result == data_buf); free(buddy_buf); } @@ -1222,9 +1222,9 @@ void test_buddy_realloc_06(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 512); assert(buddy != NULL); - result = buddy_realloc(buddy, NULL, 128); + result = buddy_realloc(buddy, NULL, 128, false); assert(result == data_buf); - result = buddy_realloc(buddy, result, 0); + result = buddy_realloc(buddy, result, 0, false); assert(result == NULL); free(buddy_buf); } @@ -1237,9 +1237,9 @@ void test_buddy_realloc_07(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 512); assert(buddy != NULL); - result = buddy_realloc(buddy, NULL, 128); + result = buddy_realloc(buddy, NULL, 128, false); assert(result == data_buf); - result = buddy_realloc(buddy, result, 1024); + result = buddy_realloc(buddy, result, 1024, false); assert(result == NULL); free(buddy_buf); } @@ -1253,9 +1253,9 @@ void test_buddy_realloc_08(void) { buddy = buddy_init(buddy_buf, data_buf, 512); assert(buddy != NULL); assert(buddy_malloc(buddy, 256) == data_buf); - result = buddy_realloc(buddy, NULL, 256); + result = buddy_realloc(buddy, NULL, 256, false); assert(result == data_buf + 256); - result = buddy_realloc(buddy, result, 512); + result = buddy_realloc(buddy, result, 512, false); assert(result == NULL); free(buddy_buf); } @@ -1266,7 +1266,27 @@ void test_buddy_realloc_alignment(void) { struct buddy *buddy; start_test; buddy = buddy_init(buddy_buf, data_buf, 4096); - assert(buddy_realloc(buddy, data_buf+1, 2048) == NULL); + assert(buddy_realloc(buddy, data_buf+1, 2048, false) == NULL); + free(buddy_buf); +} + +void test_buddy_realloc_ignore_01(void) { + unsigned char *buddy_buf = malloc(buddy_sizeof(4096)); + unsigned char data_buf[4096]; + struct buddy *buddy; + void *result; + unsigned char *ba; + start_test; + memset(data_buf, 0, 4096); /* make sure the buffer is empty */ + buddy = buddy_init(buddy_buf, data_buf, 4096); + buddy_malloc(buddy, 64); /* allocate one slot */ + result = buddy_malloc(buddy, 64); /* allocate its sibling */ + memset(result, 255, 64); /* put some data in it */ + result = buddy_realloc(buddy, result, 128, true); /* get a new slot, ignore data */ + ba = (unsigned char *) result; + for (size_t i = 0; i < 64; i++) { + assert(ba[i] == 0); + } free(buddy_buf); } @@ -1277,7 +1297,7 @@ void test_buddy_reallocarray_01(void) { void *result; start_test; buddy = buddy_init(buddy_buf, data_buf, 512); - result = buddy_reallocarray(buddy, NULL, 0, 0); + result = buddy_reallocarray(buddy, NULL, 0, 0, false); /* This is implementation-defined! */ assert(result != NULL); free(buddy_buf); @@ -1290,7 +1310,7 @@ void test_buddy_reallocarray_02(void) { void *result; start_test; buddy = buddy_init(buddy_buf, data_buf, 512); - result = buddy_reallocarray(buddy, NULL, sizeof(short), SIZE_MAX); + result = buddy_reallocarray(buddy, NULL, sizeof(short), SIZE_MAX, false); assert(result == NULL); free(buddy_buf); } @@ -1302,7 +1322,7 @@ void test_buddy_reallocarray_03(void) { void *result; start_test; buddy = buddy_init(buddy_buf, data_buf, 512); - result = buddy_reallocarray(buddy, NULL, sizeof(char), 256); + result = buddy_reallocarray(buddy, NULL, sizeof(char), 256, false); assert(result == data_buf); free(buddy_buf); } @@ -1582,7 +1602,7 @@ void test_buddy_walk_05(void) { void *walker_06(void *ctx, void *addr, size_t size, size_t allocated) { struct buddy *buddy = (struct buddy *) ctx; assert(allocated); - buddy_realloc(buddy, addr, size); + buddy_realloc(buddy, addr, size, false); return NULL; } @@ -2392,6 +2412,8 @@ int main(void) { test_buddy_realloc_08(); test_buddy_realloc_alignment(); + test_buddy_realloc_ignore_01(); + test_buddy_reallocarray_01(); test_buddy_reallocarray_02(); test_buddy_reallocarray_03();