Skip to content

Commit 4a97c2c

Browse files
authored
#119 return a status from buddy_safe_free (#120)
1 parent d2f6e82 commit 4a97c2c

File tree

2 files changed

+87
-48
lines changed

2 files changed

+87
-48
lines changed

buddy_alloc.h

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,16 @@ void *buddy_reallocarray(struct buddy *buddy, void *ptr,
114114
/* Use the specified buddy to free memory. See free. */
115115
void buddy_free(struct buddy *buddy, void *ptr);
116116

117+
enum buddy_safe_free_status {
118+
BUDDY_SAFE_FREE_SUCCESS,
119+
BUDDY_SAFE_FREE_BUDDY_IS_NULL,
120+
BUDDY_SAFE_FREE_INVALID_ADDRESS,
121+
BUDDY_SAFE_FREE_SIZE_MISMATCH,
122+
BUDDY_SAFE_FREE_ALREADY_FREE,
123+
};
124+
117125
/* A (safer) free with a size. Will not free unless the size fits the target span. */
118-
void buddy_safe_free(struct buddy *buddy, void *ptr, size_t requested_size);
126+
enum buddy_safe_free_status buddy_safe_free(struct buddy *buddy, void *ptr, size_t requested_size);
119127

120128
/*
121129
* Reservation functions
@@ -321,8 +329,13 @@ static size_t buddy_tree_status(struct buddy_tree *t, struct buddy_tree_pos pos)
321329
/* Marks the indicated position as allocated and propagates the change */
322330
static void buddy_tree_mark(struct buddy_tree *t, struct buddy_tree_pos pos);
323331

332+
enum buddy_tree_release_status {
333+
BUDDY_TREE_RELEASE_SUCCESS,
334+
BUDDY_TREE_RELEASE_FAIL_PARTIALLY_USED,
335+
};
336+
324337
/* Marks the indicated position as free and propagates the change */
325-
static void buddy_tree_release(struct buddy_tree *t, struct buddy_tree_pos pos);
338+
static enum buddy_tree_release_status buddy_tree_release(struct buddy_tree *t, struct buddy_tree_pos pos);
326339

327340
/* Returns a free position at the specified depth or an invalid position */
328341
static struct buddy_tree_pos buddy_tree_find_free(struct buddy_tree *t, uint8_t depth);
@@ -849,45 +862,55 @@ void buddy_free(struct buddy *buddy, void *ptr) {
849862
buddy_tree_release(tree, pos);
850863
}
851864

852-
void buddy_safe_free(struct buddy *buddy, void *ptr, size_t requested_size) {
853-
unsigned char *dst, *main;
854-
struct buddy_tree *tree;
865+
enum buddy_safe_free_status buddy_safe_free(struct buddy* buddy, void* ptr, size_t requested_size) {
866+
unsigned char* dst, * main;
867+
struct buddy_tree* tree;
855868
struct buddy_tree_pos pos;
856869
size_t allocated_size_for_depth;
870+
enum buddy_tree_release_status status;
857871

858872
if (buddy == NULL) {
859-
return;
873+
return BUDDY_SAFE_FREE_BUDDY_IS_NULL;
860874
}
861875
if (ptr == NULL) {
862-
return;
876+
return BUDDY_SAFE_FREE_INVALID_ADDRESS;
863877
}
864-
dst = (unsigned char *)ptr;
878+
dst = (unsigned char*)ptr;
865879
main = buddy_main(buddy);
866880
if ((dst < main) || (dst >= (main + buddy->memory_size))) {
867-
return;
881+
return BUDDY_SAFE_FREE_INVALID_ADDRESS;
868882
}
869883

870-
/* Find the position tracking this address */
884+
/* Find an allocated position tracking this address */
871885
tree = buddy_tree(buddy);
872886
pos = position_for_address(buddy, dst);
873887

874-
if (! buddy_tree_valid(tree, pos)) {
875-
return;
888+
if (!buddy_tree_valid(tree, pos)) {
889+
return BUDDY_SAFE_FREE_INVALID_ADDRESS;
876890
}
877891

878892
allocated_size_for_depth = size_for_depth(buddy, pos.depth);
879893
if (requested_size < buddy->alignment) {
880894
requested_size = buddy->alignment;
881895
}
882896
if (requested_size > allocated_size_for_depth) {
883-
return;
897+
return BUDDY_SAFE_FREE_SIZE_MISMATCH;
884898
}
885899
if (requested_size <= (allocated_size_for_depth / 2)) {
886-
return;
900+
return BUDDY_SAFE_FREE_SIZE_MISMATCH;
887901
}
888902

889903
/* Release the position */
890-
buddy_tree_release(tree, pos);
904+
status = buddy_tree_release(tree, pos);
905+
906+
switch (status) {
907+
case BUDDY_TREE_RELEASE_FAIL_PARTIALLY_USED:
908+
return BUDDY_SAFE_FREE_INVALID_ADDRESS;
909+
case BUDDY_TREE_RELEASE_SUCCESS:
910+
break;
911+
}
912+
913+
return BUDDY_SAFE_FREE_SUCCESS;
891914
}
892915

893916
void buddy_reserve_range(struct buddy *buddy, void *ptr, size_t requested_size) {
@@ -1062,7 +1085,6 @@ static unsigned int buddy_relative_mode(struct buddy *buddy) {
10621085

10631086
static void buddy_toggle_virtual_slots(struct buddy *buddy, unsigned int state) {
10641087
size_t delta, memory_size, effective_memory_size;
1065-
void (*toggle)(struct buddy_tree *, struct buddy_tree_pos);
10661088
struct buddy_tree *tree;
10671089
struct buddy_tree_pos pos;
10681090

@@ -1077,16 +1099,18 @@ static void buddy_toggle_virtual_slots(struct buddy *buddy, unsigned int state)
10771099
/* Node memory size is already aligned to buddy->alignment */
10781100
delta = effective_memory_size - memory_size;
10791101

1080-
/* Determine whether to mark or release */
1081-
toggle = state ? &buddy_tree_mark : &buddy_tree_release;
1082-
10831102
tree = buddy_tree(buddy);
10841103
pos = buddy_tree_right_child(buddy_tree_root());
10851104
while (delta) {
10861105
size_t current_pos_size = size_for_depth(buddy, buddy_tree_depth(pos));
10871106
if (delta == current_pos_size) {
10881107
/* toggle current pos */
1089-
(*toggle)(tree, pos);
1108+
if (state) {
1109+
buddy_tree_mark(tree, pos);
1110+
}
1111+
else {
1112+
buddy_tree_release(tree, pos);
1113+
}
10901114
break;
10911115
}
10921116
if (delta <= (current_pos_size / 2)) {
@@ -1095,7 +1119,12 @@ static void buddy_toggle_virtual_slots(struct buddy *buddy, unsigned int state)
10951119
continue;
10961120
} else {
10971121
/* toggle right child */
1098-
(*toggle)(tree, buddy_tree_right_child(pos));
1122+
if (state) {
1123+
buddy_tree_mark(tree, buddy_tree_right_child(pos));
1124+
}
1125+
else {
1126+
buddy_tree_release(tree, buddy_tree_right_child(pos));
1127+
}
10991128
/* reduce delta */
11001129
delta -= current_pos_size / 2;
11011130
/* re-run for left child */
@@ -1107,7 +1136,6 @@ static void buddy_toggle_virtual_slots(struct buddy *buddy, unsigned int state)
11071136

11081137
static void buddy_toggle_range_reservation(struct buddy *buddy, void *ptr, size_t requested_size, unsigned int state) {
11091138
unsigned char *dst, *main;
1110-
void (*toggle)(struct buddy_tree *, struct buddy_tree_pos);
11111139
struct buddy_tree *tree;
11121140
size_t offset;
11131141
struct buddy_tree_pos pos;
@@ -1127,17 +1155,19 @@ static void buddy_toggle_range_reservation(struct buddy *buddy, void *ptr, size_
11271155
return;
11281156
}
11291157

1130-
/* Determine whether to mark or release */
1131-
toggle = state ? &buddy_tree_mark : &buddy_tree_release;
1132-
11331158
/* Find the deepest position tracking this address */
11341159
tree = buddy_tree(buddy);
11351160
offset = (size_t) (dst - main);
11361161
pos = deepest_position_for_offset(buddy, offset);
11371162

11381163
/* Advance one position at a time and process */
11391164
while (requested_size) {
1140-
(*toggle)(tree, pos);
1165+
if (state) {
1166+
buddy_tree_mark(tree, pos);
1167+
}
1168+
else {
1169+
buddy_tree_release(tree, pos);
1170+
}
11411171
requested_size = (requested_size < buddy->alignment) ? 0 : (requested_size - buddy->alignment);
11421172
pos.index++;
11431173
}
@@ -1597,19 +1627,21 @@ static void buddy_tree_mark(struct buddy_tree *t, struct buddy_tree_pos pos) {
15971627
update_parent_chain(t, pos, internal, internal.local_offset);
15981628
}
15991629

1600-
static void buddy_tree_release(struct buddy_tree *t, struct buddy_tree_pos pos) {
1630+
static enum buddy_tree_release_status buddy_tree_release(struct buddy_tree *t, struct buddy_tree_pos pos) {
16011631
/* Calling release on an unused or a partially-used position a bug in caller */
16021632
struct internal_position internal = buddy_tree_internal_position_tree(t, pos);
16031633

16041634
if (read_from_internal_position(buddy_tree_bits(t), internal) != internal.local_offset) {
1605-
return;
1635+
return BUDDY_TREE_RELEASE_FAIL_PARTIALLY_USED;
16061636
}
16071637

16081638
/* Mark the node as unused */
16091639
write_to_internal_position(buddy_tree_bits(t), internal, 0);
16101640

16111641
/* Update the tree upwards */
16121642
update_parent_chain(t, pos, internal, 0);
1643+
1644+
return BUDDY_TREE_RELEASE_SUCCESS;
16131645
}
16141646

16151647
static void update_parent_chain(struct buddy_tree *t, struct buddy_tree_pos pos,

tests.c

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ void test_buddy_resize_up_within_reserved(void) {
345345
buddy = buddy_init(buddy_buf, data_buf, 768);
346346
assert(buddy != NULL);
347347
assert(buddy_resize(buddy, 896) == buddy);
348+
assert(buddy_resize(buddy, 768) == buddy);
348349
free(buddy_buf);
349350
}
350351

@@ -356,6 +357,7 @@ void test_buddy_resize_up_at_reserved(void) {
356357
buddy = buddy_init(buddy_buf, data_buf, 768);
357358
assert(buddy != NULL);
358359
assert(buddy_resize(buddy, 1024) == buddy);
360+
assert(buddy_resize(buddy, 768) == buddy);
359361
free(buddy_buf);
360362
}
361363

@@ -367,6 +369,7 @@ void test_buddy_resize_up_after_reserved(void) {
367369
buddy = buddy_init(buddy_buf, data_buf, 768);
368370
assert(buddy != NULL);
369371
assert(buddy_resize(buddy, 2048) == buddy);
372+
assert(buddy_resize(buddy, 768) == buddy);
370373
free(buddy_buf);
371374
}
372375

@@ -378,6 +381,7 @@ void test_buddy_resize_down_to_virtual(void) {
378381
buddy = buddy_init(buddy_buf, data_buf, 1024);
379382
assert(buddy != NULL);
380383
assert(buddy_resize(buddy, 832) == buddy);
384+
assert(buddy_resize(buddy, 1024) == buddy);
381385
free(buddy_buf);
382386
}
383387

@@ -389,6 +393,7 @@ void test_buddy_resize_down_to_virtual_partial(void) {
389393
buddy = buddy_init(buddy_buf, data_buf, 1024);
390394
assert(buddy != NULL);
391395
assert(buddy_resize(buddy, 832-1) == buddy);
396+
assert(buddy_resize(buddy, 1024) == buddy);
392397
free(buddy_buf);
393398
}
394399

@@ -400,6 +405,7 @@ void test_buddy_resize_down_within_reserved(void) {
400405
buddy = buddy_init(buddy_buf, data_buf, 768);
401406
assert(buddy != NULL);
402407
assert(buddy_resize(buddy, 640) == buddy);
408+
assert(buddy_resize(buddy, 768) == buddy);
403409
free(buddy_buf);
404410
}
405411

@@ -428,6 +434,7 @@ void test_buddy_resize_down_at_reserved(void) {
428434
buddy = buddy_init(buddy_buf, data_buf, 768);
429435
assert(buddy != NULL);
430436
assert(buddy_resize(buddy, 512) == buddy);
437+
assert(buddy_resize(buddy, 768) == buddy);
431438
free(buddy_buf);
432439
}
433440

@@ -439,6 +446,7 @@ void test_buddy_resize_down_before_reserved(void) {
439446
buddy = buddy_init(buddy_buf, data_buf, 768);
440447
assert(buddy != NULL);
441448
assert(buddy_resize(buddy, 448) == buddy);
449+
assert(buddy_resize(buddy, 768) == buddy);
442450
free(buddy_buf);
443451
}
444452

@@ -883,11 +891,11 @@ void test_buddy_safe_free_coverage(void) {
883891
start_test;
884892
buddy = buddy_init(buddy_buf, data_buf+1024, 1024);
885893
assert(buddy != NULL);
886-
buddy_safe_free(NULL, NULL, 0);
887-
buddy_safe_free(NULL, data_buf+1024, 0);
888-
buddy_safe_free(buddy, NULL, 0);
889-
buddy_safe_free(buddy, data_buf, 0);
890-
buddy_safe_free(buddy, data_buf+2048, 0);
894+
assert(buddy_safe_free(NULL, NULL, 0) == BUDDY_SAFE_FREE_BUDDY_IS_NULL);
895+
assert(buddy_safe_free(buddy, NULL, 0) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
896+
assert(buddy_safe_free(buddy, data_buf, 0) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
897+
assert(buddy_safe_free(buddy, data_buf+2048, 0) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
898+
assert(buddy_safe_free(buddy, data_buf+1024, 1024) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
891899
free(buddy_buf);
892900
}
893901

@@ -897,7 +905,7 @@ void test_buddy_safe_free_alignment(void) {
897905
struct buddy *buddy;
898906
start_test;
899907
buddy = buddy_init(buddy_buf, data_buf, 4096);
900-
buddy_safe_free(buddy, data_buf+1, 0);
908+
assert(buddy_safe_free(buddy, data_buf+1, 0) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
901909
free(buddy_buf);
902910
}
903911

@@ -915,11 +923,11 @@ void test_buddy_safe_free_invalid_free_01(void) {
915923
r = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN);
916924
assert(r != NULL);
917925
assert(l != r);
918-
buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN);
926+
assert(buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SUCCESS);
919927
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
920928
// double-free on a right node
921929
// that will propagate to a partially-allocated parent
922-
buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN);
930+
assert(buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
923931
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
924932
free(buddy_buf);
925933
free(buddy_buf_control);
@@ -939,12 +947,12 @@ void test_buddy_safe_free_invalid_free_02(void) {
939947
r = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN);
940948
assert(r != NULL);
941949
assert(l != r);
942-
buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN);
943-
buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN);
950+
assert(buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SUCCESS);
951+
assert(buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SUCCESS);
944952
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
945953
// double-free on a right node
946954
// that will propagate to a unallocated parent
947-
buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN);
955+
assert(buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
948956
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
949957
free(buddy_buf);
950958
free(buddy_buf_control);
@@ -964,14 +972,14 @@ void test_buddy_safe_free_invalid_free_03(void) {
964972
r = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN);
965973
assert(r != NULL);
966974
assert(l != r);
967-
buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN);
968-
buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN);
975+
assert(buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SUCCESS);
976+
assert(buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SUCCESS);
969977
m = buddy_malloc(buddy, size); // full allocation
970978
assert(m == l); // at the start of the arena
971979
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
972980
// double-free on a right node
973981
// that will propagate to a fully-allocated parent
974-
buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN);
982+
assert(buddy_safe_free(buddy, r, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
975983
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
976984
free(buddy_buf);
977985
free(buddy_buf_control);
@@ -991,12 +999,11 @@ void test_buddy_safe_free_invalid_free_04(void) {
991999
r = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN);
9921000
assert(r != NULL);
9931001
assert(l != r);
994-
buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN);
1002+
assert(buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SUCCESS);
9951003
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
9961004
// double-free on a left node
9971005
// that will propagate to a partially-allocated parent
998-
buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN);
999-
/* the use check in buddy_tree_release handles this case */
1006+
assert(buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN*2) == BUDDY_SAFE_FREE_INVALID_ADDRESS);
10001007
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
10011008
free(buddy_buf);
10021009
free(buddy_buf_control);
@@ -1014,7 +1021,7 @@ void test_buddy_safe_free_invalid_free_05(void) {
10141021
l = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN);
10151022
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
10161023
// safe free with double size
1017-
buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN * 2);
1024+
assert(buddy_safe_free(buddy, l, BUDDY_ALLOC_ALIGN * 2) == BUDDY_SAFE_FREE_SIZE_MISMATCH);
10181025
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
10191026
free(buddy_buf);
10201027
free(buddy_buf_control);
@@ -1032,7 +1039,7 @@ void test_buddy_safe_free_invalid_free_06(void) {
10321039
m = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN*2);
10331040
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
10341041
// safe free with half size
1035-
buddy_safe_free(buddy, m, BUDDY_ALLOC_ALIGN);
1042+
assert(buddy_safe_free(buddy, m, BUDDY_ALLOC_ALIGN) == BUDDY_SAFE_FREE_SIZE_MISMATCH);
10361043
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
10371044
free(buddy_buf);
10381045
free(buddy_buf_control);
@@ -1050,7 +1057,7 @@ void test_buddy_safe_free_invalid_free_07(void) {
10501057
m = buddy_malloc(buddy, BUDDY_ALLOC_ALIGN*2);
10511058
memcpy(buddy_buf_control, buddy_buf, buddy_sizeof(size));
10521059
// safe free with zero size
1053-
buddy_safe_free(buddy, m, 0);
1060+
assert(buddy_safe_free(buddy, m, 0) == BUDDY_SAFE_FREE_SIZE_MISMATCH);
10541061
assert(memcmp(buddy_buf_control, buddy_buf, buddy_sizeof(size)) == 0);
10551062
free(buddy_buf);
10561063
free(buddy_buf_control);

0 commit comments

Comments
 (0)