mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-25 03:29:58 -07:00
Merge branch 'dev' into zlo/tlsf-and-a-temple-of-memcorrupt
This commit is contained in:
296
applications/debug/unit_tests/tests/furi/furi_memmgr_test.c
Normal file
296
applications/debug/unit_tests/tests/furi/furi_memmgr_test.c
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "../test.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void test_furi_memmgr(void) {
|
||||
void* ptr;
|
||||
|
||||
// allocate memory case
|
||||
ptr = malloc(100);
|
||||
mu_check(ptr != NULL);
|
||||
// test that memory is zero-initialized after allocation
|
||||
for(int i = 0; i < 100; i++) {
|
||||
mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
|
||||
}
|
||||
free(ptr);
|
||||
|
||||
// reallocate memory case
|
||||
ptr = malloc(100);
|
||||
memset(ptr, 66, 100);
|
||||
ptr = realloc(ptr, 200);
|
||||
mu_check(ptr != NULL);
|
||||
|
||||
// test that memory is really reallocated
|
||||
for(int i = 0; i < 100; i++) {
|
||||
mu_assert_int_eq(66, ((uint8_t*)ptr)[i]);
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
|
||||
// allocate and zero-initialize array (calloc)
|
||||
ptr = calloc(100, 2);
|
||||
mu_check(ptr != NULL);
|
||||
for(int i = 0; i < 100 * 2; i++) {
|
||||
mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void test_memmgr_malloc(const size_t allocation_size) {
|
||||
uint8_t* ptr = NULL;
|
||||
const char* error_message = NULL;
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
ptr = malloc(allocation_size);
|
||||
|
||||
// test that we can allocate memory
|
||||
if(ptr == NULL) {
|
||||
error_message = "malloc failed";
|
||||
}
|
||||
|
||||
// test that memory is zero-initialized after allocation
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] != 0) {
|
||||
error_message = "memory is not zero-initialized after malloc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
memset(ptr, 0x55, allocation_size);
|
||||
free(ptr);
|
||||
|
||||
// test that memory is zero-initialized after free
|
||||
// we know that allocator can use this memory for inner purposes
|
||||
// so we check that memory at least partially zero-initialized
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wuse-after-free"
|
||||
|
||||
size_t zero_count = 0;
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] == 0) {
|
||||
zero_count++;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// check that at least 75% of memory is zero-initialized
|
||||
if(zero_count < (allocation_size * 0.75)) {
|
||||
error_message = "seems that memory is not zero-initialized after free (malloc)";
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
if(error_message != NULL) {
|
||||
mu_fail(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_memmgr_realloc(const size_t allocation_size) {
|
||||
uint8_t* ptr = NULL;
|
||||
const char* error_message = NULL;
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
ptr = realloc(ptr, allocation_size);
|
||||
|
||||
// test that we can allocate memory
|
||||
if(ptr == NULL) {
|
||||
error_message = "realloc(NULL) failed";
|
||||
}
|
||||
|
||||
// test that memory is zero-initialized after allocation
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] != 0) {
|
||||
error_message = "memory is not zero-initialized after realloc(NULL)";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memset(ptr, 0x55, allocation_size);
|
||||
|
||||
ptr = realloc(ptr, allocation_size * 2);
|
||||
|
||||
// test that we can reallocate memory
|
||||
if(ptr == NULL) {
|
||||
error_message = "realloc failed";
|
||||
}
|
||||
|
||||
// test that memory content is preserved
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] != 0x55) {
|
||||
error_message = "memory is not reallocated after realloc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// test that remaining memory is zero-initialized
|
||||
size_t non_zero_count = 0;
|
||||
for(size_t i = allocation_size; i < allocation_size * 2; i++) {
|
||||
if(ptr[i] != 0) {
|
||||
non_zero_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// check that at most of memory is zero-initialized
|
||||
// we know that allocator not always can restore content size from a pointer
|
||||
// so we check against small threshold
|
||||
if(non_zero_count > 4) {
|
||||
error_message = "seems that memory is not zero-initialized after realloc";
|
||||
}
|
||||
|
||||
uint8_t* null_ptr = realloc(ptr, 0);
|
||||
|
||||
// test that we can free memory
|
||||
if(null_ptr != NULL) {
|
||||
error_message = "realloc(0) failed";
|
||||
}
|
||||
|
||||
// test that memory is zero-initialized after realloc(0)
|
||||
// we know that allocator can use this memory for inner purposes
|
||||
// so we check that memory at least partially zero-initialized
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wuse-after-free"
|
||||
|
||||
size_t zero_count = 0;
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] == 0) {
|
||||
zero_count++;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// check that at least 75% of memory is zero-initialized
|
||||
if(zero_count < (allocation_size * 0.75)) {
|
||||
error_message = "seems that memory is not zero-initialized after realloc(0)";
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
if(error_message != NULL) {
|
||||
mu_fail(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_memmgr_alloc_aligned(const size_t allocation_size, const size_t alignment) {
|
||||
uint8_t* ptr = NULL;
|
||||
const char* error_message = NULL;
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
ptr = aligned_alloc(alignment, allocation_size);
|
||||
|
||||
// test that we can allocate memory
|
||||
if(ptr == NULL) {
|
||||
error_message = "aligned_alloc failed";
|
||||
}
|
||||
|
||||
// test that memory is aligned
|
||||
if(((uintptr_t)ptr % alignment) != 0) {
|
||||
error_message = "memory is not aligned after aligned_alloc";
|
||||
}
|
||||
|
||||
// test that memory is zero-initialized after allocation
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] != 0) {
|
||||
error_message = "memory is not zero-initialized after aligned_alloc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
memset(ptr, 0x55, allocation_size);
|
||||
free(ptr);
|
||||
|
||||
// test that memory is zero-initialized after free
|
||||
// we know that allocator can use this memory for inner purposes
|
||||
// so we check that memory at least partially zero-initialized
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wuse-after-free"
|
||||
|
||||
size_t zero_count = 0;
|
||||
for(size_t i = 0; i < allocation_size; i++) {
|
||||
if(ptr[i] == 0) {
|
||||
zero_count++;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// check that at least 75% of memory is zero-initialized
|
||||
if(zero_count < (allocation_size * 0.75)) {
|
||||
error_message = "seems that memory is not zero-initialized after free (aligned_alloc)";
|
||||
}
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
|
||||
if(error_message != NULL) {
|
||||
mu_fail(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
void test_furi_memmgr_advanced(void) {
|
||||
const size_t sizes[] = {50, 100, 500, 1000, 5000, 10000};
|
||||
const size_t sizes_count = sizeof(sizes) / sizeof(sizes[0]);
|
||||
const size_t alignments[] = {4, 8, 16, 32, 64, 128, 256, 512, 1024};
|
||||
const size_t alignments_count = sizeof(alignments) / sizeof(alignments[0]);
|
||||
|
||||
// do test without memory fragmentation
|
||||
{
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
test_memmgr_malloc(sizes[i]);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
test_memmgr_realloc(sizes[i]);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
for(size_t j = 0; j < alignments_count; j++) {
|
||||
test_memmgr_alloc_aligned(sizes[i], alignments[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do test with memory fragmentation
|
||||
{
|
||||
void* blocks[sizes_count];
|
||||
void* guards[sizes_count - 1];
|
||||
|
||||
// setup guards
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
blocks[i] = malloc(sizes[i]);
|
||||
if(i < sizes_count - 1) {
|
||||
guards[i] = malloc(sizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
free(blocks[i]);
|
||||
}
|
||||
|
||||
// do test
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
test_memmgr_malloc(sizes[i]);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
test_memmgr_realloc(sizes[i]);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < sizes_count; i++) {
|
||||
for(size_t j = 0; j < alignments_count; j++) {
|
||||
test_memmgr_alloc_aligned(sizes[i], alignments[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup guards
|
||||
for(size_t i = 0; i < sizes_count - 1; i++) {
|
||||
free(guards[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
applications/debug/unit_tests/tests/furi/furi_pubsub_test.c
Normal file
45
applications/debug/unit_tests/tests/furi/furi_pubsub_test.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <furi.h>
|
||||
#include "../test.h"
|
||||
|
||||
const uint32_t context_value = 0xdeadbeef;
|
||||
const uint32_t notify_value_0 = 0x12345678;
|
||||
const uint32_t notify_value_1 = 0x11223344;
|
||||
|
||||
uint32_t pubsub_value = 0;
|
||||
uint32_t pubsub_context_value = 0;
|
||||
|
||||
void test_pubsub_handler(const void* arg, void* ctx) {
|
||||
pubsub_value = *(uint32_t*)arg;
|
||||
pubsub_context_value = *(uint32_t*)ctx;
|
||||
}
|
||||
|
||||
void test_furi_pubsub(void) {
|
||||
FuriPubSub* test_pubsub = NULL;
|
||||
FuriPubSubSubscription* test_pubsub_subscription = NULL;
|
||||
|
||||
// init pubsub case
|
||||
test_pubsub = furi_pubsub_alloc();
|
||||
mu_assert_pointers_not_eq(test_pubsub, NULL);
|
||||
|
||||
// subscribe pubsub case
|
||||
test_pubsub_subscription =
|
||||
furi_pubsub_subscribe(test_pubsub, test_pubsub_handler, (void*)&context_value);
|
||||
mu_assert_pointers_not_eq(test_pubsub_subscription, NULL);
|
||||
|
||||
/// notify pubsub case
|
||||
furi_pubsub_publish(test_pubsub, (void*)¬ify_value_0);
|
||||
mu_assert_int_eq(pubsub_value, notify_value_0);
|
||||
mu_assert_int_eq(pubsub_context_value, context_value);
|
||||
|
||||
// unsubscribe pubsub case
|
||||
furi_pubsub_unsubscribe(test_pubsub, test_pubsub_subscription);
|
||||
|
||||
/// notify unsubscribed pubsub case
|
||||
furi_pubsub_publish(test_pubsub, (void*)¬ify_value_1);
|
||||
mu_assert_int_not_eq(pubsub_value, notify_value_1);
|
||||
|
||||
// delete pubsub case
|
||||
furi_pubsub_free(test_pubsub);
|
||||
}
|
||||
31
applications/debug/unit_tests/tests/furi/furi_record_test.c
Normal file
31
applications/debug/unit_tests/tests/furi/furi_record_test.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <furi.h>
|
||||
#include "../test.h"
|
||||
|
||||
#define TEST_RECORD_NAME "test/holding"
|
||||
|
||||
void test_furi_create_open(void) {
|
||||
// Test that record does not exist
|
||||
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
|
||||
|
||||
// Create record
|
||||
uint8_t test_data = 0;
|
||||
furi_record_create(TEST_RECORD_NAME, (void*)&test_data);
|
||||
|
||||
// Test that record exists
|
||||
mu_check(furi_record_exists(TEST_RECORD_NAME) == true);
|
||||
|
||||
// Open it
|
||||
void* record = furi_record_open(TEST_RECORD_NAME);
|
||||
mu_assert_pointers_eq(record, &test_data);
|
||||
|
||||
// Close it
|
||||
furi_record_close(TEST_RECORD_NAME);
|
||||
|
||||
// Clean up
|
||||
furi_record_destroy(TEST_RECORD_NAME);
|
||||
|
||||
// Test that record does not exist
|
||||
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
|
||||
}
|
||||
61
applications/debug/unit_tests/tests/furi/furi_test.c
Normal file
61
applications/debug/unit_tests/tests/furi/furi_test.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "../test.h"
|
||||
|
||||
// v2 tests
|
||||
void test_furi_create_open(void);
|
||||
void test_furi_concurrent_access(void);
|
||||
void test_furi_pubsub(void);
|
||||
|
||||
void test_furi_memmgr(void);
|
||||
void test_furi_memmgr_advanced(void);
|
||||
|
||||
static int foo = 0;
|
||||
|
||||
void test_setup(void) {
|
||||
foo = 7;
|
||||
}
|
||||
|
||||
void test_teardown(void) {
|
||||
/* Nothing */
|
||||
}
|
||||
|
||||
MU_TEST(test_check) {
|
||||
mu_check(foo != 6);
|
||||
}
|
||||
|
||||
// v2 tests
|
||||
MU_TEST(mu_test_furi_create_open) {
|
||||
test_furi_create_open();
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_pubsub) {
|
||||
test_furi_pubsub();
|
||||
}
|
||||
|
||||
MU_TEST(mu_test_furi_memmgr) {
|
||||
// this test is not accurate, but gives a basic understanding
|
||||
// that memory management is working fine
|
||||
test_furi_memmgr();
|
||||
test_furi_memmgr_advanced();
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_suite) {
|
||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||
|
||||
MU_RUN_TEST(test_check);
|
||||
|
||||
// v2 tests
|
||||
MU_RUN_TEST(mu_test_furi_create_open);
|
||||
MU_RUN_TEST(mu_test_furi_pubsub);
|
||||
MU_RUN_TEST(mu_test_furi_memmgr);
|
||||
}
|
||||
|
||||
int run_minunit_test_furi(void) {
|
||||
MU_RUN_SUITE(test_suite);
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_furi)
|
||||
Reference in New Issue
Block a user