forked from enlightenment/efl
eina/mp/one_big: fix alignment issues.
When over-allocating (past "pool->max" items) a memory slice will be allocated to the new item as a linked list using Eina_Inlist. The original code was placing the Eina_Inlist structure (3 pointers) at the beginning of the allocated memory. However the item must have proper alignment based on "pool->item_size", otherwise a structure may end with unaligned members. Take for example MIPS 32 bits, it uses 4 bytes pointers with 8 bytes double. A structure containing a double could have it unaligned as 12 % 8 = 4 (12 is the size of Eina_Inlist, that contains 3 pointers), and MIPS doesn't allow unaligned access. Albin Tonnerre (Lutin) spotted this in his Debian MIPS test machine, it was breaking at eet_data_get_double() that was storing an unaligned double. This was being called from within edje test suite. The current code will place the list node after the requested "pool->item_size", of course guaranteeing the pointer inside the node is aligned (otherwise a "char" or "short" would break its alignment).
This commit is contained in:
parent
edc548fac5
commit
dbc4669d68
|
@ -49,6 +49,12 @@
|
|||
#endif
|
||||
#define WRN(...) EINA_LOG_DOM_WARN(_eina_one_big_mp_log_dom, __VA_ARGS__)
|
||||
|
||||
#define OVER_MEM_TO_LIST(_pool, _over_mem) \
|
||||
((Eina_Inlist *)(((char *)_over_mem) + (_pool)->offset_to_item_inlist))
|
||||
|
||||
#define OVER_MEM_FROM_LIST(_pool, _node) \
|
||||
((void *)(((char *)_node) - (_pool)->offset_to_item_inlist))
|
||||
|
||||
static int _eina_one_big_mp_log_dom = -1;
|
||||
|
||||
typedef struct _One_Big One_Big;
|
||||
|
@ -57,6 +63,7 @@ struct _One_Big
|
|||
const char *name;
|
||||
|
||||
int item_size;
|
||||
int offset_to_item_inlist;
|
||||
|
||||
int usage;
|
||||
int over;
|
||||
|
@ -114,15 +121,14 @@ eina_one_big_malloc(void *data, EINA_UNUSED unsigned int size)
|
|||
}
|
||||
|
||||
retry_smaller:
|
||||
mem = malloc(sizeof(Eina_Inlist) + pool->item_size);
|
||||
mem = malloc(sizeof(Eina_Inlist) + pool->offset_to_item_inlist);
|
||||
if (mem)
|
||||
{
|
||||
Eina_Inlist *node = OVER_MEM_TO_LIST(pool, mem);
|
||||
pool->over++;
|
||||
/* Only need to zero list elements and not the payload here */
|
||||
memset(mem, 0, sizeof(Eina_Inlist));
|
||||
pool->over_list = eina_inlist_append(pool->over_list,
|
||||
(Eina_Inlist *)mem);
|
||||
mem = ((unsigned char *)mem) + sizeof(Eina_Inlist);
|
||||
memset(node, 0, sizeof(Eina_Inlist));
|
||||
pool->over_list = eina_inlist_append(pool->over_list, node);
|
||||
}
|
||||
#ifndef NVALGRIND
|
||||
VALGRIND_MAKE_MEM_NOACCESS(mem, pool->item_size);
|
||||
|
@ -162,7 +168,7 @@ eina_one_big_free(void *data, void *ptr)
|
|||
#endif
|
||||
Eina_Inlist *il;
|
||||
|
||||
il = (Eina_Inlist *)(((unsigned char *)ptr) - sizeof(Eina_Inlist));
|
||||
il = OVER_MEM_TO_LIST(pool, ptr);
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (it = pool->over_list; it != NULL; it = it->next)
|
||||
|
@ -172,7 +178,7 @@ eina_one_big_free(void *data, void *ptr)
|
|||
#endif
|
||||
|
||||
pool->over_list = eina_inlist_remove(pool->over_list, il);
|
||||
free(il);
|
||||
free(ptr);
|
||||
pool->over--;
|
||||
}
|
||||
|
||||
|
@ -211,6 +217,14 @@ eina_one_big_init(const char *context,
|
|||
pool->item_size = eina_mempool_alignof(item_size);
|
||||
pool->max = va_arg(args, int);
|
||||
|
||||
pool->offset_to_item_inlist = pool->item_size;
|
||||
if (pool->offset_to_item_inlist % (int)sizeof(void *) != 0)
|
||||
{
|
||||
pool->offset_to_item_inlist =
|
||||
(((pool->offset_to_item_inlist / (int)sizeof(void *)) + 1) *
|
||||
(int)sizeof(void *));
|
||||
}
|
||||
|
||||
if (length)
|
||||
{
|
||||
pool->name = (const char *)(pool + 1);
|
||||
|
@ -253,8 +267,9 @@ eina_one_big_shutdown(void *data)
|
|||
while (pool->over_list)
|
||||
{
|
||||
Eina_Inlist *il = pool->over_list;
|
||||
void *ptr = OVER_MEM_FROM_LIST(pool, il);
|
||||
pool->over_list = eina_inlist_remove(pool->over_list, il);
|
||||
free(il);
|
||||
free(ptr);
|
||||
pool->over--;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue