diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2020-11-28 14:46:32 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2020-11-28 14:46:32 -0700 |
commit | 0ed233b879675929559fb413dd7e018d5aee26c3 (patch) | |
tree | 554f653ee0f29cec9774d704a8e39cd9beb9310e /tests/test_memory.c | |
parent | 4b8b2de19ed10c84d7a298c05907a1471bdf7077 (diff) | |
download | stm32l4-0ed233b879675929559fb413dd7e018d5aee26c3.tar.gz stm32l4-0ed233b879675929559fb413dd7e018d5aee26c3.tar.bz2 stm32l4-0ed233b879675929559fb413dd7e018d5aee26c3.zip |
Fix kalloc bug.
Bitfields are officially stupid. Bizzarre behavior was found in how the
bitfields integers were overflowing and causing other members to change
value, causing really screwy behavior. In addition, with the discovery
of 48k being available to the heap, a 12-bit value was no longer
sufficient to define the size.
I rewrote parts of the kalloc code to allow a generic size for the
kalloc header because now it'll require 2 words per block allocated,
and who knows what size the header will be on different platforms
with more memory.
Unfortunately, the second word of the header consists only of the "used"
bool. Because I wish to keep alignmennt with 32-bit words, 31 bits are
"wasted." However, these bits are used as a canary value to detect
heap corruption, so they're not completely wasted.
Also, testing was broken since adding the huge amount of platform
dependent code for doing system calls. These dependent parts were
put under a macro guard so they don't interfere with the x86 testing.
Diffstat (limited to 'tests/test_memory.c')
-rw-r--r-- | tests/test_memory.c | 98 |
1 files changed, 72 insertions, 26 deletions
diff --git a/tests/test_memory.c b/tests/test_memory.c index a977a70..c85e228 100644 --- a/tests/test_memory.c +++ b/tests/test_memory.c @@ -14,26 +14,25 @@ struct TEST_STRUCT { }; struct TEST_STRUCT2 { - uint32_t array[10]; + uint32_t array[16]; }; /* Copy of the node structure. */ +// The sizes will count the number of WORDS allocated. +// Since there's a max size of 16k, only 12 bits will be +// needed for this. typedef struct KALLOC_NODE { - union { - uint32_t header; - struct { - /* Is this memory block currently in use (hasn't been kfree'd) */ - bool used : 1; - /* Number of words allocated. Does not include the header. */ - uint16_t size : 12; - /* The location of the previous block (in WORDS from offest) */ - uint16_t prev : 12; - uint8_t canary : 7; - } PACKED; - }; + uint16_t size_words; + uint16_t prev; + /* + * LSB is whether this block is used. + * + * Rest of the bits must equal (0xdeadbeee >> 1) + */ + uint32_t used_and_canary; uint8_t mem[]; /* The memory to use. */ -} kalloc_node_t; +} PACKED kalloc_node_t; extern kalloc_node_t* kalloc_start; @@ -65,7 +64,8 @@ static struct TEST_STRUCT2* new_test_struct2() return ret; } -#define ASSERT_CHAIN(t1, t2) ASSERT_EQ(V(t1) + sizeof(*t1) + 4, V(t2)) +#define ASSERT_CHAIN(t1, t2) \ + ASSERT_EQ(V(t1) + sizeof(*t1) + sizeof(kalloc_node_t), V(t2)) TEST(memory, kalloc) { @@ -127,15 +127,17 @@ TEST(memory, uneven_kalloc) struct UNEVEN_STRUCT* test1 = new_uneven_struct(); struct UNEVEN_STRUCT* test2 = new_uneven_struct(); - ASSERT_EQ(V(test1) + 12, test2); + ASSERT_EQ(V(test1) + 8 + sizeof(kalloc_node_t), test2); wipeout_kalloc(); return 0; } -#define ASSERT_KALLOC_EMPTY() \ - ASSERT_EQ((void*)(kalloc_start + kalloc_start->size + 1), (void*)&HEAP_STOP) +#define ASSERT_KALLOC_EMPTY() \ + ASSERT_EQ( \ + (void*)((uint8_t*)kalloc_start + kalloc_start->size_words * sizeof(uint32_t) + sizeof(kalloc_node_t)), \ + (void*)&HEAP_STOP) TEST(memory, kalloc_free) { @@ -143,6 +145,10 @@ TEST(memory, kalloc_free) wipeout_kalloc(); } + kalloc_init(); + + ASSERT_KALLOC_EMPTY(); + struct TEST_STRUCT* test1 = new_test_struct(); struct TEST_STRUCT2* test2 = new_test_struct2(); struct TEST_STRUCT* test3 = new_test_struct(); @@ -248,6 +254,46 @@ TEST(memory, relink_backref_after_free) return 0; } +TEST(memory, alloc1) +{ + char buf[1024]; + + kalloc(5); + kalloc(1); + + if (debug_kalloc_assert_consistency(buf, 1024)) { + fprintf( + stderr, + "Consistency check failed. (%s:%d)\n", + __FILE__, + __LINE__); + fprintf(stderr, "%s", buf); + ASSERT_TRUE(false); + } + + return 0; +} + +TEST(memory, alloc0) +{ + char buf[1024]; + + kalloc(5); + kalloc(0); + + if (debug_kalloc_assert_consistency(buf, 1024)) { + fprintf( + stderr, + "Consistency check failed. (%s:%d)\n", + __FILE__, + __LINE__); + fprintf(stderr, "%s", buf); + ASSERT_TRUE(false); + } + + return 0; +} + TEST(memory, consistency_stress) { #define NRUNS 500 @@ -258,6 +304,7 @@ TEST(memory, consistency_stress) int i; void* allocd[NRUNS] = {0}; char buf[1024]; + void* tofree; for (i = 0; i < NRUNS; ++i) { size_t nalloc = rand() % 20; @@ -266,10 +313,11 @@ TEST(memory, consistency_stress) if (debug_kalloc_assert_consistency(buf, 1024)) { fprintf( stderr, - "Consistency check failed. (At index=%d, %s:%d)\n", + "Consistency check failed. (At index=%d, %s:%d, nalloc=%ld)\n", i, __FILE__, - __LINE__); + __LINE__, + nalloc); fprintf(stderr, "%s", buf); ASSERT_TRUE(false); } @@ -290,7 +338,8 @@ TEST(memory, consistency_stress) ASSERT_TRUE(false); } - kfree(allocd[idx]); + tofree = allocd[idx]; + kfree(tofree); allocd[idx] = NULL; if (debug_kalloc_assert_consistency(buf, 1024)) { @@ -305,7 +354,8 @@ TEST(memory, consistency_stress) } idx = rand() % NRUNS; - kfree(allocd[idx]); + tofree = allocd[idx]; + kfree(tofree); allocd[idx] = NULL; if (debug_kalloc_assert_consistency(buf, 1024)) { @@ -363,11 +413,7 @@ TEST(memory, kalloc_free_alloc) kfree(test2); struct TEST_STRUCT* test7 = new_test_struct(); - struct TEST_STRUCT* test8 = new_test_struct(); - // Test 2 was large enough to accomodate 3 smaller structs. ASSERT_EQ(V(test7), V(test2)); - ASSERT_EQ(V(test8), V(test2) + sizeof(*test7) + 4); - return 0; } |