| #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); |
| } |