#include "test_mem.h" #include "lwip/mem.h" #include "lwip/stats.h" #if !LWIP_STATS || !MEM_STATS #error "This tests needs MEM-statistics enabled" #endif #if LWIP_DNS #error "This test needs DNS turned off (as it mallocs on init)" #endif /* Setups/teardown functions */ static void mem_setup(void) { lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT)); } static void mem_teardown(void) { lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT)); } /* Test functions */ /** Call mem_malloc, mem_free and mem_trim and check stats */ START_TEST(test_mem_one) { #define SIZE1 16 #define SIZE1_2 12 #define SIZE2 16 void *p1, *p2; mem_size_t s1, s2; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.mem.used == 0); p1 = mem_malloc(SIZE1); fail_unless(p1 != NULL); fail_unless(lwip_stats.mem.used >= SIZE1); s1 = lwip_stats.mem.used; p2 = mem_malloc(SIZE2); fail_unless(p2 != NULL); fail_unless(lwip_stats.mem.used >= SIZE2 + s1); s2 = lwip_stats.mem.used; mem_trim(p1, SIZE1_2); mem_free(p2); fail_unless(lwip_stats.mem.used <= s2 - SIZE2); mem_free(p1); fail_unless(lwip_stats.mem.used == 0); } END_TEST static void malloc_keep_x(int x, int num, int size, int freestep) { int i; void* p[16]; LWIP_ASSERT("invalid size", size >= 0 && size < (mem_size_t)-1); memset(p, 0, sizeof(p)); for(i = 0; i < num && i < 16; i++) { p[i] = mem_malloc((mem_size_t)size); fail_unless(p[i] != NULL); } for(i = 0; i < num && i < 16; i += freestep) { if (i == x) { continue; } mem_free(p[i]); p[i] = NULL; } for(i = 0; i < num && i < 16; i++) { if (i == x) { continue; } if (p[i] != NULL) { mem_free(p[i]); p[i] = NULL; } } fail_unless(p[x] != NULL); mem_free(p[x]); } START_TEST(test_mem_random) { const int num = 16; int x; int size; int freestep; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.mem.used == 0); for (x = 0; x < num; x++) { for (size = 1; size < 32; size++) { for (freestep = 1; freestep <= 3; freestep++) { fail_unless(lwip_stats.mem.used == 0); malloc_keep_x(x, num, size, freestep); fail_unless(lwip_stats.mem.used == 0); } } } } END_TEST START_TEST(test_mem_invalid_free) { u8_t *ptr, *ptr_low, *ptr_high; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.mem.used == 0); fail_unless(lwip_stats.mem.illegal == 0); ptr = (u8_t *)mem_malloc(1); fail_unless(ptr != NULL); fail_unless(lwip_stats.mem.used != 0); ptr_low = ptr - 0x10; mem_free(ptr_low); fail_unless(lwip_stats.mem.illegal == 1); lwip_stats.mem.illegal = 0; ptr_high = ptr + (MEM_SIZE * 2); mem_free(ptr_high); fail_unless(lwip_stats.mem.illegal == 1); lwip_stats.mem.illegal = 0; mem_free(ptr); fail_unless(lwip_stats.mem.illegal == 0); fail_unless(lwip_stats.mem.used == 0); } END_TEST START_TEST(test_mem_double_free) { u8_t *ptr1b, *ptr1, *ptr2, *ptr3; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.mem.used == 0); fail_unless(lwip_stats.mem.illegal == 0); ptr1 = (u8_t *)mem_malloc(1); fail_unless(ptr1 != NULL); fail_unless(lwip_stats.mem.used != 0); ptr2 = (u8_t *)mem_malloc(1); fail_unless(ptr2 != NULL); fail_unless(lwip_stats.mem.used != 0); ptr3 = (u8_t *)mem_malloc(1); fail_unless(ptr3 != NULL); fail_unless(lwip_stats.mem.used != 0); /* free the middle mem */ mem_free(ptr2); fail_unless(lwip_stats.mem.illegal == 0); /* double-free of middle mem: should fail */ mem_free(ptr2); fail_unless(lwip_stats.mem.illegal == 1); lwip_stats.mem.illegal = 0; /* free upper memory and try again */ mem_free(ptr3); fail_unless(lwip_stats.mem.illegal == 0); mem_free(ptr2); fail_unless(lwip_stats.mem.illegal == 1); lwip_stats.mem.illegal = 0; /* free lower memory and try again */ mem_free(ptr1); fail_unless(lwip_stats.mem.illegal == 0); fail_unless(lwip_stats.mem.used == 0); mem_free(ptr2); fail_unless(lwip_stats.mem.illegal == 1); fail_unless(lwip_stats.mem.used == 0); lwip_stats.mem.illegal = 0; /* reallocate lowest memory, now overlapping already freed ptr2 */ #ifndef MIN_SIZE #define MIN_SIZE 12 #endif ptr1b = (u8_t *)mem_malloc(MIN_SIZE * 2); fail_unless(ptr1b != NULL); fail_unless(lwip_stats.mem.used != 0); mem_free(ptr2); fail_unless(lwip_stats.mem.illegal == 1); lwip_stats.mem.illegal = 0; memset(ptr1b, 1, MIN_SIZE * 2); mem_free(ptr2); fail_unless(lwip_stats.mem.illegal == 1); lwip_stats.mem.illegal = 0; mem_free(ptr1b); fail_unless(lwip_stats.mem.illegal == 0); fail_unless(lwip_stats.mem.used == 0); } END_TEST /** Create the suite including all tests for this module */ Suite * mem_suite(void) { testfunc tests[] = { TESTFUNC(test_mem_one), TESTFUNC(test_mem_random), TESTFUNC(test_mem_invalid_free), TESTFUNC(test_mem_double_free) }; return create_suite("MEM", tests, sizeof(tests)/sizeof(testfunc), mem_setup, mem_teardown); }