diff --git a/CHANGELOG b/CHANGELOG index 8479ac89..3c5fef53 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,14 @@ HISTORY ++ New features: + 2007-05-18 Simon Goldschmidt + * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp + elements to overflow. This is achieved by adding some bytes before and after + each pool element (increasing their size, of course), filling them with a + prominent value and checking them on freeing the element. + Set it to 2 to also check every element in every pool each time memp_malloc() + or memp_free() is called (slower but more helpful). + 2007-05-10 Simon Goldschmidt * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce @@ -158,6 +166,10 @@ HISTORY ++ Bug fixes: + 2007-05-18 Simon Goldschmidt + * memp.c: addition to patch #5913: smaller pointer was returned but + memp_memory was the same size -> did not save memory. + 2007-05-16 Simon Goldschmidt * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns != ERR_OK. diff --git a/src/core/memp.c b/src/core/memp.c index 4bf88990..8fb39387 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -51,27 +51,58 @@ struct memp { struct memp *next; +#if MEMP_OVERFLOW_CHECK + const char *file; + int line; +#endif /* MEMP_OVERFLOW_CHECK */ }; -#define MEMP_SIZE MEM_ALIGN_SIZE(sizeof(struct memp)) - static struct memp *memp_tab[MEMP_MAX]; +#if MEMP_OVERFLOW_CHECK +/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning + * and at the end of each element, initialize them as 0xcd and check + * them later. */ +/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, + * every single element in each pool is checked! + * This is VERY SLOW but also very helpful. */ +#ifndef MEMP_SANITY_REGION_BEFORE +#define MEMP_SANITY_REGION_BEFORE MEM_ALIGN_SIZE(16) +#endif /* MEMP_SANITY_REGION_BEFORE*/ +#ifndef MEMP_SANITY_REGION_AFTER +#define MEMP_SANITY_REGION_AFTER MEM_ALIGN_SIZE(16) +#endif /* MEMP_SANITY_REGION_AFTER*/ + +/* MEMP_SIZE: save space for struct memp and for sanity check */ +#define MEMP_SIZE (MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE) +#define MEMP_ALIGN_SIZE(x) (MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER) + +#else /* MEMP_OVERFLOW_CHECK */ + +/* No sanity checks + * We don't need to preserve the struct memp while not allocated, so we + * can save a little space and set MEMP_SIZE to 0. + */ +#define MEMP_SIZE 0 +#define MEMP_ALIGN_SIZE(x) (MEM_ALIGN_SIZE(x)) + +#endif /* MEMP_OVERFLOW_CHECK */ + static const u16_t memp_sizes[MEMP_MAX] = { - MEM_ALIGN_SIZE(sizeof(struct pbuf)), - MEM_ALIGN_SIZE(sizeof(struct raw_pcb)), - MEM_ALIGN_SIZE(sizeof(struct udp_pcb)), - MEM_ALIGN_SIZE(sizeof(struct tcp_pcb)), - MEM_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)), - MEM_ALIGN_SIZE(sizeof(struct tcp_seg)), - MEM_ALIGN_SIZE(sizeof(struct netbuf)), - MEM_ALIGN_SIZE(sizeof(struct netconn)), - MEM_ALIGN_SIZE(sizeof(struct tcpip_msg)), + MEMP_ALIGN_SIZE(sizeof(struct pbuf)), + MEMP_ALIGN_SIZE(sizeof(struct raw_pcb)), + MEMP_ALIGN_SIZE(sizeof(struct udp_pcb)), + MEMP_ALIGN_SIZE(sizeof(struct tcp_pcb)), + MEMP_ALIGN_SIZE(sizeof(struct tcp_pcb_listen)), + MEMP_ALIGN_SIZE(sizeof(struct tcp_seg)), + MEMP_ALIGN_SIZE(sizeof(struct netbuf)), + MEMP_ALIGN_SIZE(sizeof(struct netconn)), + MEMP_ALIGN_SIZE(sizeof(struct tcpip_msg)), #if ARP_QUEUEING - MEM_ALIGN_SIZE(sizeof(struct etharp_q_entry)), + MEMP_ALIGN_SIZE(sizeof(struct etharp_q_entry)), #endif - MEM_ALIGN_SIZE(sizeof(struct pbuf)) + MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE), - MEM_ALIGN_SIZE(sizeof(struct sys_timeo)) + MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE), + MEMP_ALIGN_SIZE(sizeof(struct sys_timeo)) }; static const u16_t memp_num[MEMP_MAX] = { @@ -92,7 +123,7 @@ static const u16_t memp_num[MEMP_MAX] = { }; #define MEMP_TYPE_SIZE(qty, type) \ - ((qty) * (MEMP_SIZE + MEM_ALIGN_SIZE(sizeof(type)))) + ((qty) * (MEMP_SIZE + MEMP_ALIGN_SIZE(sizeof(type)))) static u8_t memp_memory[MEM_ALIGNMENT - 1 + MEMP_TYPE_SIZE(MEMP_NUM_PBUF, struct pbuf) + @@ -108,7 +139,7 @@ static u8_t memp_memory[MEM_ALIGNMENT - 1 + MEMP_TYPE_SIZE(MEMP_NUM_ARP_QUEUE, struct etharp_q_entry) + #endif MEMP_TYPE_SIZE(PBUF_POOL_SIZE, struct pbuf) + - PBUF_POOL_SIZE * MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + + PBUF_POOL_SIZE * MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)]; #if MEMP_SANITY_CHECK @@ -123,7 +154,7 @@ memp_sanity(void) c = 1; for (n = memp_tab[i]; n != NULL; n = n->next) { if (n == m && --c < 0) { - return 0; /* LW was: abort(); */ + return 0; } } } @@ -131,6 +162,68 @@ memp_sanity(void) return 1; } #endif /* MEMP_SANITY_CHECK*/ +#if MEMP_OVERFLOW_CHECK +static void +memp_overflow_check_single(struct memp *p, u16_t memp_size) +{ + u16_t k; + u8_t *m; +#if MEMP_SANITY_REGION_BEFORE > 0 + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE; + for (k = 0; k < MEMP_SANITY_REGION_BEFORE; k++) { + if (m[k] != 0xcd) { + LWIP_ASSERT("detected memp underflow!", 0); + } + } +#endif +#if MEMP_SANITY_REGION_AFTER > 0 + m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER; + for (k = 0; k < MEMP_SANITY_REGION_AFTER; k++) { + if (m[k] != 0xcd) { + LWIP_ASSERT("detected memp overflow!", 0); + } + } +#endif +} +static void +memp_overflow_check(void) +{ + u16_t i, j; + struct memp *p; + + p = MEM_ALIGN(memp_memory); + for (i = 0; i < MEMP_MAX; ++i) { + p = p; + for (j = 0; j < memp_num[i]; ++j) { + memp_overflow_check_single(p, memp_sizes[i]); + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]); + } + } +} +static void +memp_overflow_init(void) +{ + u16_t i, j; + struct memp *p; + u8_t *m; + + p = MEM_ALIGN(memp_memory); + for (i = 0; i < MEMP_MAX; ++i) { + p = p; + for (j = 0; j < memp_num[i]; ++j) { +#if MEMP_SANITY_REGION_BEFORE > 0 + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE; + memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE); +#endif +#if MEMP_SANITY_REGION_AFTER > 0 + m = (u8_t*)p + MEMP_SIZE + memp_sizes[i] - MEMP_SANITY_REGION_AFTER; + memset(m, 0xcd, MEMP_SANITY_REGION_AFTER); +#endif + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]); + } + } +} +#endif /* MEMP_OVERFLOW_CHECK */ void memp_init(void) @@ -155,10 +248,19 @@ memp_init(void) memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]); } } +#if MEMP_OVERFLOW_CHECK + memp_overflow_init(); + /* check everything a first time to see if it worked */ + memp_overflow_check(); +#endif /* MEMP_OVERFLOW_CHECK */ } void * +#if MEMP_OVERFLOW_CHECK +memp_malloc_fn(memp_t type, const char* file, const int line) +#else memp_malloc(memp_t type) +#endif { struct memp *memp; SYS_ARCH_DECL_PROTECT(old_level); @@ -166,12 +268,19 @@ memp_malloc(memp_t type) LWIP_ASSERT("memp_malloc: type < MEMP_MAX", type < MEMP_MAX); SYS_ARCH_PROTECT(old_level); +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check(); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ memp = memp_tab[type]; if (memp != NULL) { memp_tab[type] = memp->next; memp->next = NULL; +#if MEMP_OVERFLOW_CHECK + memp->file = file; + memp->line = line; +#endif /* MEMP_OVERFLOW_CHECK */ #if MEMP_STATS ++lwip_stats.memp[type].used; if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) { @@ -189,7 +298,7 @@ memp_malloc(memp_t type) SYS_ARCH_UNPROTECT(old_level); - return (void*)memp; + return (void*)((u8_t*)memp + MEMP_SIZE); } void @@ -204,9 +313,16 @@ memp_free(memp_t type, void *mem) LWIP_ASSERT("memp_free: mem properly aligned", ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); - memp = (struct memp *)mem; + memp = (struct memp *)((u8_t*)mem - MEMP_SIZE); SYS_ARCH_PROTECT(old_level); +#if MEMP_OVERFLOW_CHECK +#if MEMP_OVERFLOW_CHECK >= 2 + memp_overflow_check(); +#else + memp_overflow_check_single(memp, memp_sizes[type]); +#endif /* MEMP_OVERFLOW_CHECK >= 2 */ +#endif /* MEMP_OVERFLOW_CHECK */ #if MEMP_STATS lwip_stats.memp[type].used--; @@ -217,7 +333,7 @@ memp_free(memp_t type, void *mem) #if MEMP_SANITY_CHECK LWIP_ASSERT("memp sanity", memp_sanity()); -#endif +#endif /* MEMP_SANITY_CHECK */ SYS_ARCH_UNPROTECT(old_level); } diff --git a/src/include/lwip/memp.h b/src/include/lwip/memp.h index 6c47718c..64447c93 100644 --- a/src/include/lwip/memp.h +++ b/src/include/lwip/memp.h @@ -62,7 +62,12 @@ typedef enum { void memp_init(void); +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line); +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else void *memp_malloc(memp_t type); +#endif void memp_free(memp_t type, void *mem); #ifdef __cplusplus diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index f588856c..61b99488 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -84,8 +84,18 @@ a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 1600 #endif +/* MEMP_OVERFLOW_CHECK: memp overflow protection + * reserves a configurable amount of bytes before and after each memp + * element in every pool and fills it with a prominent default value. + * MEMP_OVERFLOW_CHECK = 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + #ifndef MEMP_SANITY_CHECK -#define MEMP_SANITY_CHECK 0 +#define MEMP_SANITY_CHECK 0 #endif /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application