summaryrefslogtreecommitdiff
path: root/src/modules/eina
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>2014-01-20 21:27:58 -0200
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>2014-01-20 21:44:42 -0200
commitdbc4669d6818d733d1d512f766ad8cf4c799dbba (patch)
tree4a74dba888ad04a3785b0ae0e9d28d108597ffa7 /src/modules/eina
parentedc548fac5497c1bd8d7c35c2942f6686baa64c4 (diff)
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).
Diffstat (limited to 'src/modules/eina')
-rw-r--r--src/modules/eina/mp/one_big/eina_one_big.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/src/modules/eina/mp/one_big/eina_one_big.c b/src/modules/eina/mp/one_big/eina_one_big.c
index 470a2ddf05..e384e52632 100644
--- a/src/modules/eina/mp/one_big/eina_one_big.c
+++ b/src/modules/eina/mp/one_big/eina_one_big.c
@@ -49,6 +49,12 @@
49#endif 49#endif
50#define WRN(...) EINA_LOG_DOM_WARN(_eina_one_big_mp_log_dom, __VA_ARGS__) 50#define WRN(...) EINA_LOG_DOM_WARN(_eina_one_big_mp_log_dom, __VA_ARGS__)
51 51
52#define OVER_MEM_TO_LIST(_pool, _over_mem) \
53 ((Eina_Inlist *)(((char *)_over_mem) + (_pool)->offset_to_item_inlist))
54
55#define OVER_MEM_FROM_LIST(_pool, _node) \
56 ((void *)(((char *)_node) - (_pool)->offset_to_item_inlist))
57
52static int _eina_one_big_mp_log_dom = -1; 58static int _eina_one_big_mp_log_dom = -1;
53 59
54typedef struct _One_Big One_Big; 60typedef struct _One_Big One_Big;
@@ -57,6 +63,7 @@ struct _One_Big
57 const char *name; 63 const char *name;
58 64
59 int item_size; 65 int item_size;
66 int offset_to_item_inlist;
60 67
61 int usage; 68 int usage;
62 int over; 69 int over;
@@ -114,15 +121,14 @@ eina_one_big_malloc(void *data, EINA_UNUSED unsigned int size)
114 } 121 }
115 122
116 retry_smaller: 123 retry_smaller:
117 mem = malloc(sizeof(Eina_Inlist) + pool->item_size); 124 mem = malloc(sizeof(Eina_Inlist) + pool->offset_to_item_inlist);
118 if (mem) 125 if (mem)
119 { 126 {
127 Eina_Inlist *node = OVER_MEM_TO_LIST(pool, mem);
120 pool->over++; 128 pool->over++;
121 /* Only need to zero list elements and not the payload here */ 129 /* Only need to zero list elements and not the payload here */
122 memset(mem, 0, sizeof(Eina_Inlist)); 130 memset(node, 0, sizeof(Eina_Inlist));
123 pool->over_list = eina_inlist_append(pool->over_list, 131 pool->over_list = eina_inlist_append(pool->over_list, node);
124 (Eina_Inlist *)mem);
125 mem = ((unsigned char *)mem) + sizeof(Eina_Inlist);
126 } 132 }
127#ifndef NVALGRIND 133#ifndef NVALGRIND
128 VALGRIND_MAKE_MEM_NOACCESS(mem, pool->item_size); 134 VALGRIND_MAKE_MEM_NOACCESS(mem, pool->item_size);
@@ -162,7 +168,7 @@ eina_one_big_free(void *data, void *ptr)
162#endif 168#endif
163 Eina_Inlist *il; 169 Eina_Inlist *il;
164 170
165 il = (Eina_Inlist *)(((unsigned char *)ptr) - sizeof(Eina_Inlist)); 171 il = OVER_MEM_TO_LIST(pool, ptr);
166 172
167#ifndef NDEBUG 173#ifndef NDEBUG
168 for (it = pool->over_list; it != NULL; it = it->next) 174 for (it = pool->over_list; it != NULL; it = it->next)
@@ -172,7 +178,7 @@ eina_one_big_free(void *data, void *ptr)
172#endif 178#endif
173 179
174 pool->over_list = eina_inlist_remove(pool->over_list, il); 180 pool->over_list = eina_inlist_remove(pool->over_list, il);
175 free(il); 181 free(ptr);
176 pool->over--; 182 pool->over--;
177 } 183 }
178 184
@@ -211,6 +217,14 @@ eina_one_big_init(const char *context,
211 pool->item_size = eina_mempool_alignof(item_size); 217 pool->item_size = eina_mempool_alignof(item_size);
212 pool->max = va_arg(args, int); 218 pool->max = va_arg(args, int);
213 219
220 pool->offset_to_item_inlist = pool->item_size;
221 if (pool->offset_to_item_inlist % (int)sizeof(void *) != 0)
222 {
223 pool->offset_to_item_inlist =
224 (((pool->offset_to_item_inlist / (int)sizeof(void *)) + 1) *
225 (int)sizeof(void *));
226 }
227
214 if (length) 228 if (length)
215 { 229 {
216 pool->name = (const char *)(pool + 1); 230 pool->name = (const char *)(pool + 1);
@@ -253,8 +267,9 @@ eina_one_big_shutdown(void *data)
253 while (pool->over_list) 267 while (pool->over_list)
254 { 268 {
255 Eina_Inlist *il = pool->over_list; 269 Eina_Inlist *il = pool->over_list;
270 void *ptr = OVER_MEM_FROM_LIST(pool, il);
256 pool->over_list = eina_inlist_remove(pool->over_list, il); 271 pool->over_list = eina_inlist_remove(pool->over_list, il);
257 free(il); 272 free(ptr);
258 pool->over--; 273 pool->over--;
259 } 274 }
260 } 275 }